@occluze/tether 0.6.7 → 0.7.0
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/README.md +11 -11
- package/dist/esm/astro.js +2 -2
- package/dist/esm/chunks/account-UIPWJQ3Y.js +1 -0
- package/dist/esm/chunks/account-pages-6ROA6Y4V.js +1 -0
- package/dist/esm/chunks/analytics-2V632IRV.js +1 -0
- package/dist/esm/chunks/chunk-4GCXM764.js +1 -0
- package/dist/esm/chunks/chunk-56FCLJJD.js +1 -0
- package/dist/esm/chunks/chunk-5Z5O3767.js +1 -0
- package/dist/esm/chunks/chunk-6OZJCAGZ.js +1 -0
- package/dist/esm/chunks/chunk-A5SYCVQM.js +1 -0
- package/dist/esm/chunks/chunk-BA4LQJJQ.js +1 -0
- package/dist/esm/chunks/chunk-BFTZR4OB.js +4 -0
- package/dist/esm/chunks/chunk-C5JYQCWH.js +1 -0
- package/dist/esm/chunks/chunk-E5YO6274.js +1 -0
- package/dist/esm/chunks/chunk-MPDWM2NN.js +1 -0
- package/dist/esm/chunks/chunk-T44MUL4Y.js +1 -0
- package/dist/esm/chunks/chunk-YLUULATY.js +1 -0
- package/dist/esm/chunks/diagnose-3FEKRIEK.js +14 -0
- package/dist/esm/chunks/extras-6POFBNOP.js +1 -0
- package/dist/esm/chunks/markets-ui-FD6NI2OG.js +1 -0
- package/dist/esm/chunks/search-UJ73YBQ5.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/server.js +2 -1
- package/dist/presets/barba.esm.js +55 -39
- package/dist/tether.account-pages.js +781 -495
- package/dist/tether.account-pages.min.js +1 -1
- package/dist/tether.account.js +462 -381
- package/dist/tether.account.min.js +1 -1
- package/dist/tether.analytics.js +299 -194
- package/dist/tether.analytics.min.js +1 -1
- package/dist/tether.diagnose.js +354 -262
- package/dist/tether.diagnose.min.js +2 -2
- package/dist/tether.extras.js +82 -45
- package/dist/tether.extras.min.js +1 -1
- package/dist/tether.js +3653 -2116
- package/dist/tether.markets.js +238 -150
- package/dist/tether.markets.min.js +1 -1
- package/dist/tether.min.js +3 -3
- package/dist/tether.min.js.map +4 -4
- package/dist/tether.search.js +207 -136
- package/dist/tether.search.min.js +1 -1
- package/dist/types/server/src/shared/account-orders.d.ts +44 -0
- package/dist/types/server/src/shared/account-routes.d.ts +153 -0
- package/dist/types/server/src/shared/api-versions.d.ts +13 -0
- package/dist/types/server/src/shared/error-message.d.ts +2 -0
- package/dist/types/server/src/shared/json.d.ts +25 -0
- package/dist/types/server/src/shared/market-codes.d.ts +16 -0
- package/dist/types/src/account/addresses-view.d.ts +5 -0
- package/dist/types/src/account/answers.d.ts +40 -0
- package/dist/types/src/account/markup.d.ts +19 -0
- package/dist/types/src/account/operations.d.ts +41 -0
- package/dist/types/src/account/order-lines.d.ts +13 -0
- package/dist/types/src/account/order-list.d.ts +12 -0
- package/dist/types/src/account/order-page.d.ts +6 -0
- package/dist/types/src/account/page-answers.d.ts +182 -0
- package/dist/types/src/account/page-events.d.ts +2 -0
- package/dist/types/src/account/server-client.d.ts +60 -0
- package/dist/types/src/account/subscriptions-view.d.ts +2 -0
- package/dist/types/src/account-api.d.ts +18 -0
- package/dist/types/src/account-marks.d.ts +15 -0
- package/dist/types/src/account-pages.d.ts +8 -0
- package/dist/types/src/account.d.ts +64 -0
- package/dist/types/src/amounts.d.ts +12 -0
- package/dist/types/src/analytics-shopify.d.ts +41 -0
- package/dist/types/src/analytics.d.ts +2 -0
- package/dist/types/src/api-version.d.ts +28 -0
- package/dist/types/src/astro.d.ts +42 -0
- package/dist/types/src/cart/cart-shape.d.ts +43 -0
- package/dist/types/src/cart/checkout.d.ts +16 -0
- package/dist/types/src/cart/drawer.d.ts +18 -0
- package/dist/types/src/cart/mutations.d.ts +79 -0
- package/dist/types/src/cart/render.d.ts +17 -0
- package/dist/types/src/cart/store.d.ts +182 -0
- package/dist/types/src/cart.d.ts +106 -0
- package/dist/types/src/client.d.ts +100 -0
- package/dist/types/src/collection.d.ts +25 -0
- package/dist/types/src/config-sections.d.ts +40 -0
- package/dist/types/src/config.d.ts +185 -0
- package/dist/types/src/controls/cart-controls.d.ts +2 -0
- package/dist/types/src/controls/discount.d.ts +2 -0
- package/dist/types/src/controls/extras.d.ts +5 -0
- package/dist/types/src/controls/navigation.d.ts +12 -0
- package/dist/types/src/diagnose-markup.d.ts +19 -0
- package/dist/types/src/diagnose.d.ts +60 -0
- package/dist/types/src/dom.d.ts +75 -0
- package/dist/types/src/extras.d.ts +21 -0
- package/dist/types/src/fragments.d.ts +158 -0
- package/dist/types/src/globals.d.ts +15 -0
- package/dist/types/src/images.d.ts +20 -0
- package/dist/types/src/index.d.ts +167 -0
- package/dist/types/src/initial.d.ts +56 -0
- package/dist/types/src/lazy.d.ts +28 -0
- package/dist/types/src/loader.d.ts +84 -0
- package/dist/types/src/market-codes.d.ts +6 -0
- package/dist/types/src/markets-ui.d.ts +32 -0
- package/dist/types/src/markets.d.ts +72 -0
- package/dist/types/src/markup.d.ts +131 -0
- package/dist/types/src/mounting.d.ts +46 -0
- package/dist/types/src/page-market.d.ts +27 -0
- package/dist/types/src/presets/barba.d.ts +56 -0
- package/dist/types/src/product-events.d.ts +2 -0
- package/dist/types/src/product-render.d.ts +17 -0
- package/dist/types/src/product-shape.d.ts +88 -0
- package/dist/types/src/product-state.d.ts +110 -0
- package/dist/types/src/product.d.ts +66 -0
- package/dist/types/src/repeaters.d.ts +16 -0
- package/dist/types/src/search.d.ts +33 -0
- package/dist/types/src/selling-plans.d.ts +64 -0
- package/dist/types/src/server.d.ts +88 -0
- package/dist/types/src/shopify-values.d.ts +46 -0
- package/dist/types/src/status.d.ts +33 -0
- package/dist/types/src/storage.d.ts +12 -0
- package/dist/types/src/store-html.d.ts +39 -0
- package/dist/types/src/storefront/catalog.d.ts +38 -0
- package/dist/types/src/storefront/json-ld.d.ts +20 -0
- package/dist/types/src/variant-render.d.ts +14 -0
- package/package.json +42 -22
- package/src/account/addresses-view.ts +58 -0
- package/src/account/answers.ts +79 -0
- package/src/account/markup.ts +36 -0
- package/src/account/operations.ts +145 -0
- package/src/account/order-lines.ts +75 -0
- package/src/account/order-list.ts +107 -0
- package/src/account/order-page.ts +137 -0
- package/src/account/page-answers.ts +317 -0
- package/src/account/page-events.ts +253 -0
- package/src/account/server-client.ts +183 -0
- package/src/account/subscriptions-view.ts +115 -0
- package/src/account-api.ts +98 -0
- package/src/account-marks.ts +35 -0
- package/src/account-pages.ts +81 -0
- package/src/account.ts +284 -0
- package/src/amounts.ts +64 -0
- package/src/analytics-shopify.ts +246 -0
- package/src/analytics.ts +315 -0
- package/src/api-version.ts +79 -0
- package/src/astro.ts +272 -0
- package/src/cart/cart-shape.ts +25 -0
- package/src/cart/checkout.ts +101 -0
- package/src/cart/drawer.ts +125 -0
- package/src/cart/mutations.ts +237 -0
- package/src/cart/render.ts +266 -0
- package/src/cart/store.ts +279 -0
- package/src/cart.ts +345 -0
- package/src/client.ts +391 -0
- package/src/collection.ts +175 -0
- package/src/config-sections.ts +284 -0
- package/src/config.ts +480 -0
- package/src/controls/cart-controls.ts +123 -0
- package/src/controls/discount.ts +75 -0
- package/src/controls/extras.ts +54 -0
- package/src/controls/navigation.ts +77 -0
- package/src/diagnose-markup.ts +298 -0
- package/src/diagnose.ts +294 -0
- package/src/dom.ts +268 -0
- package/src/extras.ts +136 -0
- package/src/fragments.ts +261 -0
- package/src/globals.d.ts +15 -0
- package/src/images.ts +91 -0
- package/src/index.ts +415 -0
- package/src/initial.ts +101 -0
- package/src/lazy-iife.ts +197 -0
- package/src/lazy.ts +42 -0
- package/src/loader.ts +363 -0
- package/src/market-codes.ts +6 -0
- package/src/markets-ui.ts +227 -0
- package/src/markets.ts +246 -0
- package/src/markup.ts +127 -0
- package/src/mounting.ts +264 -0
- package/src/page-market.ts +110 -0
- package/src/part-integrity.ts +7 -0
- package/src/parts/account-pages.ts +7 -0
- package/src/parts/account.ts +7 -0
- package/src/parts/analytics.ts +7 -0
- package/src/parts/diagnose.ts +7 -0
- package/src/parts/extras.ts +7 -0
- package/src/parts/markets.ts +7 -0
- package/src/parts/search.ts +7 -0
- package/src/presets/barba.ts +194 -0
- package/src/product-events.ts +115 -0
- package/src/product-render.ts +218 -0
- package/src/product-shape.ts +49 -0
- package/src/product-state.ts +318 -0
- package/src/product.ts +308 -0
- package/src/repeaters.ts +161 -0
- package/src/search.ts +305 -0
- package/src/selling-plans.ts +145 -0
- package/src/server.ts +211 -0
- package/src/shopify-values.ts +91 -0
- package/src/status.ts +106 -0
- package/src/storage.ts +34 -0
- package/src/store-html.ts +359 -0
- package/src/storefront/catalog.ts +196 -0
- package/src/storefront/json-ld.ts +144 -0
- package/src/variant-render.ts +139 -0
- package/dist/esm/chunks/account-Q6E2TFEV.js +0 -1
- package/dist/esm/chunks/account-pages-UZXR4R5F.js +0 -1
- package/dist/esm/chunks/analytics-IJBKATUP.js +0 -1
- package/dist/esm/chunks/chunk-4QJKLPYR.js +0 -1
- package/dist/esm/chunks/chunk-64TUD3QR.js +0 -1
- package/dist/esm/chunks/chunk-AJLPU2JC.js +0 -4
- package/dist/esm/chunks/chunk-FIOZPPC5.js +0 -1
- package/dist/esm/chunks/chunk-K2YEQAIH.js +0 -1
- package/dist/esm/chunks/chunk-KIDH76B7.js +0 -1
- package/dist/esm/chunks/chunk-PAYT5ZD7.js +0 -1
- package/dist/esm/chunks/chunk-RREHGH4A.js +0 -1
- package/dist/esm/chunks/chunk-SSJT43CJ.js +0 -1
- package/dist/esm/chunks/chunk-VC46IEJQ.js +0 -1
- package/dist/esm/chunks/diagnose-3WVAWNTX.js +0 -14
- package/dist/esm/chunks/extras-7I7WJX35.js +0 -1
- package/dist/esm/chunks/markets-ui-545XLFTE.js +0 -1
- package/dist/esm/chunks/search-NILMGYXG.js +0 -1
- package/src/account-pages.js +0 -318
- package/src/account.js +0 -385
- package/src/analytics.js +0 -232
- package/src/api-version.js +0 -35
- package/src/astro.js +0 -101
- package/src/cart.js +0 -559
- package/src/client.js +0 -131
- package/src/collection.js +0 -114
- package/src/config.js +0 -85
- package/src/diagnose.js +0 -246
- package/src/dom.js +0 -288
- package/src/extras.js +0 -63
- package/src/fragments.js +0 -144
- package/src/index.js +0 -395
- package/src/initial.js +0 -75
- package/src/lazy-iife.js +0 -46
- package/src/lazy.js +0 -18
- package/src/loader.js +0 -198
- package/src/markets-ui.js +0 -90
- package/src/markets.js +0 -133
- package/src/mounting.js +0 -154
- package/src/parts/account-pages.js +0 -3
- package/src/parts/account.js +0 -3
- package/src/parts/analytics.js +0 -3
- package/src/parts/diagnose.js +0 -3
- package/src/parts/extras.js +0 -3
- package/src/parts/markets.js +0 -3
- package/src/parts/search.js +0 -3
- package/src/presets/barba.js +0 -100
- package/src/product.js +0 -570
- package/src/search.js +0 -153
- package/src/selling-plans.js +0 -94
- package/src/server.js +0 -252
- package/src/status.js +0 -66
- package/types/astro.d.ts +0 -17
- package/types/barba.d.ts +0 -16
- package/types/index.d.ts +0 -426
- package/types/server.d.ts +0 -110
package/dist/tether.diagnose.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
// src/diagnose.
|
|
8
|
+
// src/diagnose.ts
|
|
9
9
|
var diagnose_exports = {};
|
|
10
10
|
__export(diagnose_exports, {
|
|
11
11
|
apiVersionStatus: () => apiVersionStatus,
|
|
@@ -14,143 +14,80 @@
|
|
|
14
14
|
didYouMean: () => didYouMean
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
// tether-core:config.
|
|
18
|
-
var m = window.Tether.__core["config.
|
|
19
|
-
var
|
|
17
|
+
// tether-core:config.ts
|
|
18
|
+
var m = window.Tether.__core["config.ts"];
|
|
19
|
+
var [cfg, isConfigured, log, MARKET_SOURCES, parseMarkets, reportError, warn] = m;
|
|
20
20
|
|
|
21
|
-
// tether-core:client.
|
|
22
|
-
var m2 = window.Tether.__core["client.
|
|
23
|
-
var
|
|
21
|
+
// tether-core:client.ts
|
|
22
|
+
var m2 = window.Tether.__core["client.ts"];
|
|
23
|
+
var [endpoint, gql, orNull, shaped, TetherError] = m2;
|
|
24
24
|
|
|
25
|
-
// tether-core:dom.
|
|
26
|
-
var m3 = window.Tether.__core["dom.
|
|
27
|
-
var
|
|
25
|
+
// tether-core:dom.ts
|
|
26
|
+
var m3 = window.Tether.__core["dom.ts"];
|
|
27
|
+
var [ANALYTICS_EVENTS, attr, attributesFromJson, emit, formatDate, formatMoney, get, has, hasTemplate, isOwnEvent, parseJSONAttr, productUrl, qsa, repeat, sel, setImage, setText, show] = m3;
|
|
28
28
|
|
|
29
|
-
// tether-core:loader.
|
|
30
|
-
var m4 = window.Tether.__core["loader.
|
|
31
|
-
var
|
|
29
|
+
// tether-core:loader.ts
|
|
30
|
+
var m4 = window.Tether.__core["loader.ts"];
|
|
31
|
+
var [clearProductCache, getProduct] = m4;
|
|
32
32
|
|
|
33
|
-
// tether-core:selling-plans.
|
|
34
|
-
var m5 = window.Tether.__core["selling-plans.
|
|
35
|
-
var
|
|
33
|
+
// tether-core:selling-plans.ts
|
|
34
|
+
var m5 = window.Tether.__core["selling-plans.ts"];
|
|
35
|
+
var [allPlans] = m5;
|
|
36
36
|
|
|
37
|
-
// tether-core:status.
|
|
38
|
-
var m6 = window.Tether.__core["status.
|
|
39
|
-
var
|
|
37
|
+
// tether-core:status.ts
|
|
38
|
+
var m6 = window.Tether.__core["status.ts"];
|
|
39
|
+
var [boundary, resolveProductKey] = m6;
|
|
40
40
|
|
|
41
|
-
// src/api-version.
|
|
42
|
-
var
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
var
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return
|
|
41
|
+
// src/api-version.ts
|
|
42
|
+
var QUARTERLY_VERSION = /^(\d{4})-(01|04|07|10)$/;
|
|
43
|
+
var MONTHS_PER_QUARTER = 3;
|
|
44
|
+
var QUARTERS_PER_YEAR = 4;
|
|
45
|
+
var MONTHS_SUPPORTED = 12;
|
|
46
|
+
var UPGRADE_WARNING_MONTHS = 3;
|
|
47
|
+
var AVERAGE_MONTH_MS = 30.44 * 24 * 3600 * 1e3;
|
|
48
|
+
function parseVersion(version) {
|
|
49
|
+
const match = QUARTERLY_VERSION.exec(typeof version === "string" ? version : "");
|
|
50
|
+
if (!match) return null;
|
|
51
|
+
return { year: Number(match[1]), month: Number(match[2]) };
|
|
52
|
+
}
|
|
53
|
+
var formatVersion = (year, month) => `${year}-${String(month).padStart(2, "0")}`;
|
|
54
|
+
function nextApiVersion(version, steps = 1) {
|
|
55
|
+
const parsed = parseVersion(version);
|
|
56
|
+
if (!parsed) throw new Error(`not a quarterly Shopify API version: ${version}`);
|
|
57
|
+
const quarter = parsed.year * QUARTERS_PER_YEAR + (parsed.month - 1) / MONTHS_PER_QUARTER + steps;
|
|
58
|
+
return formatVersion(Math.floor(quarter / QUARTERS_PER_YEAR), quarter % QUARTERS_PER_YEAR * MONTHS_PER_QUARTER + 1);
|
|
52
59
|
}
|
|
53
60
|
function apiVersionStatus(version, now = /* @__PURE__ */ new Date()) {
|
|
54
|
-
if (version === "unstable")
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const
|
|
61
|
+
if (version === "unstable") {
|
|
62
|
+
return { version, ok: false, note: '"unstable" changes without notice: pin a dated version such as 2026-07' };
|
|
63
|
+
}
|
|
64
|
+
const parsed = parseVersion(version);
|
|
65
|
+
if (!parsed) return { version, ok: false, note: "not a quarterly version (YYYY-01, -04, -07 or -10)" };
|
|
66
|
+
const released = new Date(Date.UTC(parsed.year, parsed.month - 1, 1));
|
|
67
|
+
const supportedUntil = new Date(Date.UTC(parsed.year, parsed.month - 1 + MONTHS_SUPPORTED, 1));
|
|
68
|
+
const monthsLeft = (supportedUntil.getTime() - now.getTime()) / AVERAGE_MONTH_MS;
|
|
69
|
+
const isReleased = released <= now;
|
|
60
70
|
let note = `supported until about ${supportedUntil.toISOString().slice(0, 7)}`;
|
|
61
|
-
if (
|
|
62
|
-
else if (monthsLeft <= 0)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// src/markets.js
|
|
68
|
-
var COUNTRY = /^[A-Z]{2}$/;
|
|
69
|
-
var REGIONAL_LANGUAGES = /* @__PURE__ */ new Set(["PT_BR", "PT_PT", "ZH_CN", "ZH_TW"]);
|
|
70
|
-
var storageKey = () => `${cfg.prefix}:market:${cfg.domain}`;
|
|
71
|
-
var defaultEnv = () => ({
|
|
72
|
-
document: typeof document !== "undefined" ? document : null,
|
|
73
|
-
location: typeof window !== "undefined" ? window.location : null,
|
|
74
|
-
storage: (() => {
|
|
75
|
-
try {
|
|
76
|
-
return window.localStorage;
|
|
77
|
-
} catch {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
})(),
|
|
81
|
-
global: typeof window !== "undefined" ? window : {}
|
|
82
|
-
});
|
|
83
|
-
function toCountry(v) {
|
|
84
|
-
const c = String(v || "").trim().toUpperCase();
|
|
85
|
-
return COUNTRY.test(c) && c !== "XX" && c !== "T1" ? c : null;
|
|
86
|
-
}
|
|
87
|
-
function toLanguage(v) {
|
|
88
|
-
const raw = String(v || "").trim().replace("-", "_").toUpperCase();
|
|
89
|
-
if (!raw) return null;
|
|
90
|
-
if (REGIONAL_LANGUAGES.has(raw)) return raw;
|
|
91
|
-
const primary = raw.split("_")[0];
|
|
92
|
-
return /^[A-Z]{2,3}$/.test(primary) ? primary : null;
|
|
93
|
-
}
|
|
94
|
-
function readCookie(doc, name) {
|
|
95
|
-
if (!doc || !name) return null;
|
|
96
|
-
const hit = String(doc.cookie || "").split(";").map((c) => c.trim()).find((c) => c.startsWith(`${name}=`));
|
|
97
|
-
return hit ? decodeURIComponent(hit.slice(name.length + 1)) : null;
|
|
98
|
-
}
|
|
99
|
-
var lookup = (locales, key) => {
|
|
100
|
-
if (!locales || !key) return null;
|
|
101
|
-
const k = String(key).toLowerCase();
|
|
102
|
-
const found = Object.keys(locales).find((x) => x.toLowerCase() === k);
|
|
103
|
-
return found ? locales[found] : null;
|
|
104
|
-
};
|
|
105
|
-
var readers = {
|
|
106
|
-
saved(m7, env) {
|
|
107
|
-
if (m7.remember === false || !env.storage) return null;
|
|
108
|
-
try {
|
|
109
|
-
return JSON.parse(env.storage.getItem(storageKey()) || "null");
|
|
110
|
-
} catch {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
server(m7, env) {
|
|
115
|
-
const meta = (name) => env.document?.querySelector?.(`meta[name="${name}"]`)?.getAttribute("content");
|
|
116
|
-
const country = env.global.TETHER_COUNTRY || meta("tether-country") || readCookie(env.document, m7.cookie || "tether_country");
|
|
117
|
-
const language = env.global.TETHER_LANGUAGE || meta("tether-language");
|
|
118
|
-
return { country, language };
|
|
119
|
-
},
|
|
120
|
-
webflow(m7, env) {
|
|
121
|
-
const segment = (env.location?.pathname || "/").split("/").filter(Boolean)[0];
|
|
122
|
-
const fromPath = lookup(m7.locales, segment);
|
|
123
|
-
if (fromPath) return fromPath;
|
|
124
|
-
const lang = env.document?.documentElement?.getAttribute("lang");
|
|
125
|
-
if (!lang) return null;
|
|
126
|
-
const mapped = lookup(m7.locales, lang) || lookup(m7.locales, lang.split("-")[0]);
|
|
127
|
-
if (mapped) return { locale: lang, ...mapped };
|
|
128
|
-
if (m7.locales && m7.strict) return null;
|
|
129
|
-
const region = lang.split("-")[1];
|
|
130
|
-
return { language: lang, country: region && region.length === 2 ? region : null, locale: lang };
|
|
71
|
+
if (!isReleased) note = "not released yet (release candidate at best)";
|
|
72
|
+
else if (monthsLeft <= 0) {
|
|
73
|
+
note = "no longer supported: Shopify falls back to the oldest supported version. Upgrade (see README)";
|
|
74
|
+
} else if (monthsLeft < UPGRADE_WARNING_MONTHS) {
|
|
75
|
+
note = `${note}: plan the upgrade to ${nextApiVersion(version)} or later (see README)`;
|
|
131
76
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
list.forEach((name) => {
|
|
140
|
-
const r = readers[name]?.(markets, env);
|
|
141
|
-
if (!r) return;
|
|
142
|
-
const vals = { country: toCountry(r.country), language: toLanguage(r.language), locale: r.locale || null };
|
|
143
|
-
Object.entries(vals).forEach(([k, v]) => {
|
|
144
|
-
if (v && !out[k]) {
|
|
145
|
-
out[k] = v;
|
|
146
|
-
out.sources[k] = name;
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
return out;
|
|
77
|
+
return {
|
|
78
|
+
version,
|
|
79
|
+
ok: isReleased && monthsLeft > 0,
|
|
80
|
+
monthsLeft: Math.round(monthsLeft),
|
|
81
|
+
next: nextApiVersion(version),
|
|
82
|
+
note
|
|
83
|
+
};
|
|
151
84
|
}
|
|
152
85
|
|
|
153
|
-
//
|
|
86
|
+
// tether-core:lazy.ts
|
|
87
|
+
var m7 = window.Tether.__core["lazy.ts"];
|
|
88
|
+
var [loadPart] = m7;
|
|
89
|
+
|
|
90
|
+
// src/diagnose-markup.ts
|
|
154
91
|
var SHOW = /* @__PURE__ */ new Set([
|
|
155
92
|
"in-stock",
|
|
156
93
|
"out-of-stock",
|
|
@@ -234,7 +171,8 @@
|
|
|
234
171
|
"swatch",
|
|
235
172
|
"image"
|
|
236
173
|
]);
|
|
237
|
-
var
|
|
174
|
+
var ATTRIBUTES = new Set(
|
|
175
|
+
`account account-bind account-link account-login account-logout add-label add-to-cart adding-text
|
|
238
176
|
always-enabled bind cart-checkout-charge cart-clear cart-close cart-count cart-discounts cart-drawer cart-label cart-lines
|
|
239
177
|
cart-note cart-open cart-subtotal cart-total cart-warning checkout code collection collection-bind countries country
|
|
240
178
|
country-bind country-label country-select default-plan default-purchase discount discount-code discount-form discount-input
|
|
@@ -247,191 +185,345 @@
|
|
|
247
185
|
plan-value product products purchase purchase-mode qty qty-minus qty-plus quantity recommendations reverse search
|
|
248
186
|
search-bind search-collections search-input search-limit search-min search-products search-queries search-results
|
|
249
187
|
search-state show soldout-text sort state subscribe-text variant variant-select variant-url max-width max-height crop
|
|
250
|
-
sig label hydrated busy`.split(/\s+/).filter(Boolean)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
188
|
+
sig label hydrated busy`.split(/\s+/).filter(Boolean)
|
|
189
|
+
);
|
|
190
|
+
var PRODUCT_ONLY = [
|
|
191
|
+
"bind",
|
|
192
|
+
"option-list",
|
|
193
|
+
"option",
|
|
194
|
+
"variant-select",
|
|
195
|
+
"add-to-cart",
|
|
196
|
+
"purchase",
|
|
197
|
+
"plan-list",
|
|
198
|
+
"plan",
|
|
199
|
+
"qty",
|
|
200
|
+
"line-attribute"
|
|
201
|
+
];
|
|
202
|
+
var REPEATERS = ["option-list", "plan-list", "cart-lines", "list"];
|
|
203
|
+
var METAFIELD_BIND = "metafield:";
|
|
204
|
+
var IMAGE_BIND = /^image:\d+$/;
|
|
205
|
+
var DESCRIBED_CLASSES = 2;
|
|
206
|
+
function editDistance(from, to) {
|
|
207
|
+
let previous = Array.from({ length: to.length + 1 }, (_, index) => index);
|
|
208
|
+
for (let i = 1; i <= from.length; i++) {
|
|
209
|
+
const row = [i];
|
|
210
|
+
for (let j = 1; j <= to.length; j++) {
|
|
211
|
+
const substitution = (previous[j - 1] ?? 0) + (from[i - 1] === to[j - 1] ? 0 : 1);
|
|
212
|
+
row.push(Math.min((previous[j] ?? 0) + 1, (row[j - 1] ?? 0) + 1, substitution));
|
|
213
|
+
}
|
|
214
|
+
previous = row;
|
|
256
215
|
}
|
|
257
|
-
return
|
|
216
|
+
return previous[to.length] ?? 0;
|
|
258
217
|
}
|
|
259
218
|
function didYouMean(value, options, prefix = "") {
|
|
260
219
|
let best = null;
|
|
261
|
-
let
|
|
262
|
-
for (const
|
|
263
|
-
const
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
best =
|
|
220
|
+
let bestDistance = Infinity;
|
|
221
|
+
for (const option of options) {
|
|
222
|
+
const distance = editDistance(value, option);
|
|
223
|
+
if (distance < bestDistance) {
|
|
224
|
+
bestDistance = distance;
|
|
225
|
+
best = option;
|
|
267
226
|
}
|
|
268
227
|
}
|
|
269
|
-
|
|
228
|
+
const closeEnough = Math.max(2, Math.floor(value.length / 4));
|
|
229
|
+
return best !== null && bestDistance <= closeEnough ? ` Did you mean "${prefix}${best}"?` : "";
|
|
270
230
|
}
|
|
271
|
-
var mask = (t) => t ? `${String(t).slice(0, 4)}\u2026${String(t).slice(-4)} (${String(t).length} chars)` : "(missing)";
|
|
272
231
|
function describe(el) {
|
|
273
232
|
const id = el.id ? `#${el.id}` : "";
|
|
274
|
-
const
|
|
275
|
-
|
|
233
|
+
const classes = el.className && typeof el.className === "string" ? el.className.trim().split(/\s+/) : [];
|
|
234
|
+
const classText = classes.length ? `.${classes.slice(0, DESCRIBED_CLASSES).join(".")}` : "";
|
|
235
|
+
return `<${el.tagName.toLowerCase()}${id}${classText}>`;
|
|
276
236
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const add = (level, message, el) => problems.push({ level, message, element: el ? describe(el) : void 0, el });
|
|
280
|
-
const inProduct = (el) => Boolean(el.closest(sel("product")));
|
|
281
|
-
const listSel = `${sel("collection")},${sel("products")},${sel("recommendations")}`;
|
|
237
|
+
var listSelector = () => `${sel("collection")},${sel("products")},${sel("recommendations")}`;
|
|
238
|
+
function checkProductKeys(root, add) {
|
|
282
239
|
qsa(root, sel("product")).forEach((el) => {
|
|
283
|
-
if (el.closest(
|
|
240
|
+
if (el.closest(listSelector()) && el.closest(sel("list"))) return;
|
|
284
241
|
const { key, fromUrl, raw } = resolveProductKey(el);
|
|
285
|
-
if (!raw)
|
|
286
|
-
|
|
242
|
+
if (!raw) {
|
|
243
|
+
add(
|
|
244
|
+
"error",
|
|
245
|
+
`${attr("product")} has no value. Bind it to the Shopify handle (CMS field), or use "url:handle".`,
|
|
246
|
+
el
|
|
247
|
+
);
|
|
248
|
+
} else if (fromUrl && !key) {
|
|
249
|
+
add("warn", `${attr("product")}="${raw}" but this URL has no value for it (e.g. ?handle=my-product).`, el);
|
|
250
|
+
}
|
|
287
251
|
});
|
|
288
|
-
|
|
289
|
-
|
|
252
|
+
}
|
|
253
|
+
function checkPlacement(root, add) {
|
|
254
|
+
for (const name of PRODUCT_ONLY) {
|
|
290
255
|
qsa(root, sel(name)).forEach((el) => {
|
|
291
|
-
if (
|
|
256
|
+
if (el.closest(sel("product"))) return;
|
|
292
257
|
if (name === "line-attribute" && el.closest(sel("group"))) return;
|
|
293
258
|
add("warn", `${attr(name)} outside any ${attr("product")}: it does nothing here.`, el);
|
|
294
259
|
});
|
|
295
|
-
}
|
|
260
|
+
}
|
|
296
261
|
qsa(root, sel("group-add")).forEach((el) => {
|
|
297
262
|
if (!el.closest(sel("group"))) add("warn", `${attr("group-add")} outside a ${attr("group")}.`, el);
|
|
298
263
|
});
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
264
|
+
for (const name of REPEATERS) {
|
|
265
|
+
qsa(root, sel(name)).forEach((el) => {
|
|
266
|
+
if (!el.firstElementChild && !hasTemplate(el)) {
|
|
267
|
+
add("warn", `${attr(name)} without a template child: put one example element inside it.`, el);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
qsa(root, listSelector()).forEach((el) => {
|
|
272
|
+
if (!qsa(el, sel("list")).length) {
|
|
273
|
+
add("error", `List without a ${attr("list")} child: products have nowhere to render.`, el);
|
|
302
274
|
}
|
|
303
|
-
}));
|
|
304
|
-
qsa(root, listSel).forEach((el) => {
|
|
305
|
-
if (!qsa(el, sel("list")).length) add("error", `List without a ${attr("list")} child: products have nowhere to render.`, el);
|
|
306
275
|
});
|
|
276
|
+
}
|
|
277
|
+
function checkValues(root, add) {
|
|
307
278
|
qsa(root, sel("show")).forEach((el) => {
|
|
308
|
-
const
|
|
309
|
-
if (!SHOW.has(
|
|
279
|
+
const value = get(el, "show") ?? "";
|
|
280
|
+
if (!SHOW.has(value)) add("warn", `Unknown ${attr("show")}="${value}".${didYouMean(value, SHOW)}`, el);
|
|
310
281
|
});
|
|
311
282
|
qsa(root, sel("bind")).forEach((el) => {
|
|
312
|
-
const
|
|
313
|
-
if (!
|
|
314
|
-
add("warn", `Unknown ${attr("bind")}="${
|
|
283
|
+
const value = get(el, "bind") || "";
|
|
284
|
+
if (!value || BIND.has(value) || IMAGE_BIND.test(value) || value.startsWith(METAFIELD_BIND)) return;
|
|
285
|
+
add("warn", `Unknown ${attr("bind")}="${value}": it stays empty.${didYouMean(value, BIND)}`, el);
|
|
315
286
|
});
|
|
287
|
+
}
|
|
288
|
+
function checkMetafieldBinds(root, add) {
|
|
289
|
+
qsa(root, sel("bind")).forEach((el) => {
|
|
290
|
+
const value = get(el, "bind") || "";
|
|
291
|
+
if (!value.startsWith(METAFIELD_BIND)) return;
|
|
292
|
+
const ref = value.slice(METAFIELD_BIND.length);
|
|
293
|
+
const listed = cfg.metafields.some(
|
|
294
|
+
(metafield) => (typeof metafield === "string" ? metafield : `${metafield.namespace}.${metafield.key}`) === ref
|
|
295
|
+
);
|
|
296
|
+
if (!listed) {
|
|
297
|
+
add("error", `${attr("bind")}="${value}" but "${ref}" is not in config.metafields, so it stays empty.`, el);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
function checkAttributeNames(root, add) {
|
|
316
302
|
const prefix = `${cfg.prefix}-`;
|
|
317
|
-
const
|
|
303
|
+
const reported = /* @__PURE__ */ new Set();
|
|
318
304
|
qsa(root, "*").forEach((el) => {
|
|
319
|
-
for (const
|
|
320
|
-
if (!
|
|
321
|
-
const name =
|
|
322
|
-
if (
|
|
323
|
-
|
|
324
|
-
add("warn", `Unknown attribute ${
|
|
305
|
+
for (const { name: fullName } of el.attributes) {
|
|
306
|
+
if (!fullName.startsWith(prefix)) continue;
|
|
307
|
+
const name = fullName.slice(prefix.length);
|
|
308
|
+
if (ATTRIBUTES.has(name) || reported.has(name)) continue;
|
|
309
|
+
reported.add(name);
|
|
310
|
+
add("warn", `Unknown attribute ${fullName}: Tether ignores it.${didYouMean(name, ATTRIBUTES, prefix)}`, el);
|
|
325
311
|
}
|
|
326
312
|
});
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const listed = (cfg.metafields || []).some((m7) => (typeof m7 === "string" ? m7 : `${m7.namespace}.${m7.key}`) === ref);
|
|
332
|
-
if (!listed) add("error", `${attr("bind")}="${k}" but "${ref}" is not in config.metafields, so it stays empty.`, el);
|
|
333
|
-
});
|
|
334
|
-
if (qsa(root, sel("cart-open")).length && !qsa(root, sel("cart-drawer")).length) {
|
|
313
|
+
}
|
|
314
|
+
function checkCartAndScopes(root, add) {
|
|
315
|
+
const drawers = qsa(root, sel("cart-drawer")).length;
|
|
316
|
+
if (qsa(root, sel("cart-open")).length && !drawers) {
|
|
335
317
|
add("warn", `${attr("cart-open")} exists but there is no ${attr("cart-drawer")} on this page.`);
|
|
336
318
|
}
|
|
337
|
-
if (
|
|
319
|
+
if (drawers > 1) add("warn", `More than one ${attr("cart-drawer")}.`);
|
|
338
320
|
qsa(root, `[${attr("state")}="error"]`).forEach((el) => {
|
|
339
321
|
if (el.matches(boundary())) add("error", `Scope failed to load (${get(el, "error") || "error"}).`, el);
|
|
340
322
|
});
|
|
323
|
+
}
|
|
324
|
+
function checkMarkup(root = document) {
|
|
325
|
+
const problems = [];
|
|
326
|
+
const add = (level, message, el) => {
|
|
327
|
+
problems.push(el ? { level, message, element: describe(el), el } : { level, message });
|
|
328
|
+
};
|
|
329
|
+
checkProductKeys(root, add);
|
|
330
|
+
checkPlacement(root, add);
|
|
331
|
+
checkValues(root, add);
|
|
332
|
+
checkAttributeNames(root, add);
|
|
333
|
+
checkMetafieldBinds(root, add);
|
|
334
|
+
checkCartAndScopes(root, add);
|
|
341
335
|
return problems;
|
|
342
336
|
}
|
|
343
|
-
|
|
337
|
+
|
|
338
|
+
// src/diagnose.ts
|
|
339
|
+
var MAX_PRODUCTS_CHECKED = 20;
|
|
340
|
+
var API_UPGRADE_WARNING_MONTHS = 3;
|
|
341
|
+
var TOKEN_EDGE_CHARACTERS = 4;
|
|
342
|
+
function maskToken(token) {
|
|
343
|
+
if (!token) return "(missing)";
|
|
344
|
+
return `${token.slice(0, TOKEN_EDGE_CHARACTERS)}\u2026${token.slice(-TOKEN_EDGE_CHARACTERS)} (${token.length} chars)`;
|
|
345
|
+
}
|
|
346
|
+
function errorText(error, fallback) {
|
|
347
|
+
if (error instanceof Error && error.message) return error.message;
|
|
348
|
+
const code = typeof error === "object" && error !== null ? Reflect.get(error, "code") : void 0;
|
|
349
|
+
return typeof code === "string" && code ? code : fallback;
|
|
350
|
+
}
|
|
351
|
+
function configSummary() {
|
|
352
|
+
return {
|
|
353
|
+
domain: cfg.domain || "(missing)",
|
|
354
|
+
token: maskToken(cfg.token),
|
|
355
|
+
apiVersion: cfg.apiVersion,
|
|
356
|
+
endpoint: cfg.domain ? endpoint() : null,
|
|
357
|
+
country: cfg.country,
|
|
358
|
+
language: cfg.language,
|
|
359
|
+
locale: cfg.locale,
|
|
360
|
+
markets: cfg.markets,
|
|
361
|
+
prefix: cfg.prefix,
|
|
362
|
+
productPath: cfg.productPath,
|
|
363
|
+
metafields: cfg.metafields,
|
|
364
|
+
autoMount: cfg.autoMount,
|
|
365
|
+
observe: cfg.observe,
|
|
366
|
+
onError: typeof cfg.onError === "function"
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
async function marketSummary() {
|
|
370
|
+
return {
|
|
371
|
+
country: cfg.country || null,
|
|
372
|
+
language: cfg.language || null,
|
|
373
|
+
locale: cfg.locale || null,
|
|
374
|
+
detected: cfg.markets?.detect ? (await loadPart("markets")).detectMarket(cfg.markets) : null
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function apiVersionProblem({ ok, monthsLeft, note }) {
|
|
378
|
+
if (ok && (monthsLeft === void 0 || monthsLeft >= API_UPGRADE_WARNING_MONTHS)) return null;
|
|
379
|
+
return { level: ok ? "warn" : "error", message: `apiVersion ${cfg.apiVersion}: ${note}` };
|
|
380
|
+
}
|
|
381
|
+
var isShopAnswer = shaped({ shop: { name: "string", primaryDomain: { url: "string" }, paymentSettings: { currencyCode: "string" } } });
|
|
382
|
+
async function checkStorefront() {
|
|
383
|
+
if (!isConfigured()) return { kind: "not-configured" };
|
|
384
|
+
const startedAt = Date.now();
|
|
385
|
+
try {
|
|
386
|
+
const data = await gql(
|
|
387
|
+
"query TetherDiagnose { shop { name primaryDomain { url } paymentSettings { currencyCode } } }",
|
|
388
|
+
{},
|
|
389
|
+
isShopAnswer,
|
|
390
|
+
{ context: false }
|
|
391
|
+
);
|
|
392
|
+
const shop = {
|
|
393
|
+
name: data.shop.name,
|
|
394
|
+
url: data.shop.primaryDomain.url,
|
|
395
|
+
currency: data.shop.paymentSettings.currencyCode
|
|
396
|
+
};
|
|
397
|
+
return { kind: "reachable", shop, latencyMs: Date.now() - startedAt };
|
|
398
|
+
} catch (error) {
|
|
399
|
+
return { kind: "unreachable", error, latencyMs: Date.now() - startedAt };
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function checkOptions(root, key, product) {
|
|
403
|
+
const problems = [];
|
|
404
|
+
const names = product.options.map((option) => option.name);
|
|
405
|
+
const roots = qsa(root, sel("product")).filter(
|
|
406
|
+
(el) => resolveProductKey(el).key === key && el.querySelector(sel("add-to-cart"))
|
|
407
|
+
);
|
|
408
|
+
for (const el of roots) {
|
|
409
|
+
const shown = new Set(
|
|
410
|
+
qsa(el, `${sel("option-list")},select${sel("option")}`).map(
|
|
411
|
+
(list) => get(list, "option-list") || get(list, "option")
|
|
412
|
+
)
|
|
413
|
+
);
|
|
414
|
+
if (!shown.size && qsa(el, `select${sel("variant-select")}`).length) continue;
|
|
415
|
+
if (!cfg.language) {
|
|
416
|
+
for (const name of shown) {
|
|
417
|
+
if (!name || names.includes(name)) continue;
|
|
418
|
+
problems.push({
|
|
419
|
+
level: "warn",
|
|
420
|
+
message: `Product "${product.handle}" has no option "${name}" (its options: ${names.join(", ") || "none"}).${didYouMean(name, names)}`
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
for (const option of product.options) {
|
|
425
|
+
if (option.optionValues.length <= 1 || shown.has(option.name)) continue;
|
|
426
|
+
problems.push({
|
|
427
|
+
level: "warn",
|
|
428
|
+
message: `Product "${product.handle}": option "${option.name}" (${option.optionValues.length} values) has no tether-option-list, so visitors can't choose it.`
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return problems;
|
|
433
|
+
}
|
|
434
|
+
async function checkProducts(root, report) {
|
|
435
|
+
const allKeys = qsa(root, sel("product")).map((el) => resolveProductKey(el).key);
|
|
436
|
+
const keys = [...new Set(allKeys.filter((key) => key !== null && key !== ""))].slice(0, MAX_PRODUCTS_CHECKED);
|
|
437
|
+
const results = await Promise.allSettled(keys.map((key) => getProduct(key)));
|
|
438
|
+
results.forEach((result, index) => {
|
|
439
|
+
const key = keys[index] ?? "";
|
|
440
|
+
if (result.status === "rejected") {
|
|
441
|
+
const reason = errorText(result.reason, "not loaded");
|
|
442
|
+
report.products.push({ key, error: result.reason instanceof Error ? result.reason.message : void 0 });
|
|
443
|
+
report.problems.push({
|
|
444
|
+
level: "error",
|
|
445
|
+
message: `Product "${key}": ${reason}. Is it published to the Headless channel?`
|
|
446
|
+
});
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const product = result.value;
|
|
450
|
+
const plans = allPlans(product);
|
|
451
|
+
report.products.push({
|
|
452
|
+
key,
|
|
453
|
+
handle: product.handle,
|
|
454
|
+
title: product.title,
|
|
455
|
+
plans: plans.length,
|
|
456
|
+
requiresSellingPlan: product.requiresSellingPlan
|
|
457
|
+
});
|
|
458
|
+
for (const plan of plans) {
|
|
459
|
+
report.sellingPlans.push({ product: product.handle, group: plan.group.name, plan: plan.name, id: plan.id });
|
|
460
|
+
}
|
|
461
|
+
report.problems.push(...checkOptions(root, key, product));
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
async function diagnose({
|
|
465
|
+
root = document,
|
|
466
|
+
silent = false,
|
|
467
|
+
version = "",
|
|
468
|
+
now = /* @__PURE__ */ new Date()
|
|
469
|
+
} = {}) {
|
|
470
|
+
const storefront = await checkStorefront();
|
|
344
471
|
const report = {
|
|
345
472
|
version,
|
|
346
|
-
config:
|
|
347
|
-
domain: cfg.domain || "(missing)",
|
|
348
|
-
token: mask(cfg.token),
|
|
349
|
-
apiVersion: cfg.apiVersion,
|
|
350
|
-
endpoint: cfg.domain ? endpoint() : null,
|
|
351
|
-
country: cfg.country,
|
|
352
|
-
language: cfg.language,
|
|
353
|
-
locale: cfg.locale,
|
|
354
|
-
markets: cfg.markets || null,
|
|
355
|
-
prefix: cfg.prefix,
|
|
356
|
-
productPath: cfg.productPath,
|
|
357
|
-
metafields: cfg.metafields,
|
|
358
|
-
autoMount: cfg.autoMount,
|
|
359
|
-
observe: cfg.observe,
|
|
360
|
-
onError: typeof cfg.onError === "function"
|
|
361
|
-
},
|
|
473
|
+
config: configSummary(),
|
|
362
474
|
apiVersion: apiVersionStatus(cfg.apiVersion, now),
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
reachable:
|
|
366
|
-
|
|
367
|
-
latencyMs: null,
|
|
475
|
+
market: await marketSummary(),
|
|
476
|
+
reachable: storefront.kind === "reachable",
|
|
477
|
+
shop: storefront.kind === "reachable" ? storefront.shop : null,
|
|
478
|
+
latencyMs: storefront.kind === "not-configured" ? null : storefront.latencyMs,
|
|
368
479
|
products: [],
|
|
369
480
|
sellingPlans: [],
|
|
370
481
|
problems: []
|
|
371
482
|
};
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
} catch (err) {
|
|
381
|
-
report.problems.push({ level: "error", message: `Storefront API not reachable: ${err.message || err.code || "unknown error"}` });
|
|
382
|
-
}
|
|
383
|
-
report.latencyMs = Date.now() - t0;
|
|
384
|
-
if (report.reachable) {
|
|
385
|
-
const keys = [...new Set(qsa(root, sel("product")).map((el) => resolveProductKey(el).key).filter(Boolean))].slice(0, 20);
|
|
386
|
-
const results = await Promise.allSettled(keys.map((k) => getProduct(k)));
|
|
387
|
-
results.forEach((r, i) => {
|
|
388
|
-
if (r.status === "fulfilled") {
|
|
389
|
-
const p = r.value;
|
|
390
|
-
const plans = allPlans(p);
|
|
391
|
-
report.products.push({ key: keys[i], handle: p.handle, title: p.title, plans: plans.length, requiresSellingPlan: p.requiresSellingPlan });
|
|
392
|
-
plans.forEach((pl) => report.sellingPlans.push({ product: p.handle, group: pl.group?.name, plan: pl.name, id: pl.id }));
|
|
393
|
-
qsa(root, sel("product")).filter((el) => resolveProductKey(el).key === keys[i] && el.querySelector(sel("add-to-cart"))).forEach((el) => {
|
|
394
|
-
const shown = new Set(qsa(el, `${sel("option-list")},select${sel("option")}`).map((x) => get(x, "option-list") || get(x, "option")));
|
|
395
|
-
if (!shown.size && qsa(el, `select${sel("variant-select")}`).length) return;
|
|
396
|
-
const names = (p.options || []).map((o) => o.name);
|
|
397
|
-
if (!cfg.language) {
|
|
398
|
-
[...shown].filter((n) => n && !names.includes(n)).forEach((n) => {
|
|
399
|
-
report.problems.push({ level: "warn", message: `Product "${p.handle}" has no option "${n}" (its options: ${names.join(", ") || "none"}).${didYouMean(n, names)}` });
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
(p.options || []).filter((o) => o.optionValues.length > 1 && !shown.has(o.name)).forEach((o) => {
|
|
403
|
-
report.problems.push({ level: "warn", message: `Product "${p.handle}": option "${o.name}" (${o.optionValues.length} values) has no tether-option-list, so visitors can't choose it.` });
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
} else {
|
|
407
|
-
report.products.push({ key: keys[i], error: r.reason?.message });
|
|
408
|
-
report.problems.push({ level: "error", message: `Product "${keys[i]}": ${r.reason?.message || r.reason?.code || "not loaded"}. Is it published to the Headless channel?` });
|
|
409
|
-
}
|
|
483
|
+
switch (storefront.kind) {
|
|
484
|
+
case "not-configured":
|
|
485
|
+
report.problems.push({ level: "error", message: "TETHER_CONFIG needs domain and token." });
|
|
486
|
+
break;
|
|
487
|
+
case "unreachable":
|
|
488
|
+
report.problems.push({
|
|
489
|
+
level: "error",
|
|
490
|
+
message: `Storefront API not reachable: ${errorText(storefront.error, "unknown error")}`
|
|
410
491
|
});
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
492
|
+
break;
|
|
493
|
+
case "reachable":
|
|
494
|
+
await checkProducts(root, report);
|
|
495
|
+
break;
|
|
415
496
|
}
|
|
497
|
+
const versionProblem = apiVersionProblem(report.apiVersion);
|
|
498
|
+
if (versionProblem) report.problems.push(versionProblem);
|
|
416
499
|
if (typeof document !== "undefined") report.problems.push(...checkMarkup(root));
|
|
417
500
|
if (!silent) print(report);
|
|
418
501
|
return report;
|
|
419
502
|
}
|
|
420
|
-
function print(
|
|
421
|
-
const
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
503
|
+
function print(report) {
|
|
504
|
+
const errors = report.problems.filter((problem) => problem.level === "error").length;
|
|
505
|
+
const warnings = report.problems.length - errors;
|
|
506
|
+
console.group(`[${cfg.prefix}] diagnose: ${errors ? `${errors} error(s)` : "no errors"}, ${warnings} warning(s)`);
|
|
507
|
+
console.log("version", report.version, "| API", report.apiVersion.version, `(${report.apiVersion.note})`);
|
|
508
|
+
console.log("config", report.config);
|
|
509
|
+
const { country, language, detected } = report.market;
|
|
510
|
+
const inUse = [country, language].filter(Boolean).join(" / ") || "the store default";
|
|
511
|
+
console.log("market", `in use: ${inUse}`, detected ? `(detection picks ${JSON.stringify(detected)})` : "");
|
|
512
|
+
console.log(
|
|
513
|
+
report.shop ? `Storefront API reachable: ${report.shop.name} (${report.latencyMs ?? 0} ms)` : "Storefront API NOT reachable"
|
|
514
|
+
);
|
|
515
|
+
if (report.products.length) console.table(report.products);
|
|
516
|
+
if (report.sellingPlans.length) console.table(report.sellingPlans);
|
|
517
|
+
else if (report.reachable) console.log("No selling plans on the products of this page.");
|
|
518
|
+
for (const problem of report.problems) {
|
|
519
|
+
if (problem.level === "error") console.error(problem.message, problem.el ?? "");
|
|
520
|
+
else console.warn(problem.message, problem.el ?? "");
|
|
521
|
+
}
|
|
522
|
+
console.groupEnd();
|
|
433
523
|
}
|
|
434
524
|
|
|
435
|
-
// src/parts/diagnose.
|
|
436
|
-
|
|
525
|
+
// src/parts/diagnose.ts
|
|
526
|
+
var { Tether } = window;
|
|
527
|
+
if (!Tether) throw new Error("tether.diagnose.js runs after the Tether script, which loads it");
|
|
528
|
+
Tether.__parts.diagnose = diagnose_exports;
|
|
437
529
|
})();
|