@sonordev/site-kit 3.0.4 → 3.2.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/AGENTS.md +107 -0
- package/agent-manifest.json +377 -0
- package/dist/AnalyticsProvider-CD635CHQ.mjs +8 -0
- package/dist/{AnalyticsProvider-MLT26JRP.mjs.map → AnalyticsProvider-CD635CHQ.mjs.map} +1 -1
- package/dist/AnalyticsProvider-WK2Z6AIN.js +29 -0
- package/dist/{AnalyticsProvider-WTOGN7LV.js.map → AnalyticsProvider-WK2Z6AIN.js.map} +1 -1
- package/dist/BlogPostFaqSection-4AD2NIGG.js +13 -0
- package/dist/{BlogPostFaqSection-H556RV62.js.map → BlogPostFaqSection-4AD2NIGG.js.map} +1 -1
- package/dist/{BlogPostFaqSection-VSHOKKUD.mjs → BlogPostFaqSection-TU6YEC7P.mjs} +3 -3
- package/dist/{BlogPostFaqSection-VSHOKKUD.mjs.map → BlogPostFaqSection-TU6YEC7P.mjs.map} +1 -1
- package/dist/ChatWidget-AIOOZY6H.js +17 -0
- package/dist/{ChatWidget-MAL7FB4M.js.map → ChatWidget-AIOOZY6H.js.map} +1 -1
- package/dist/ChatWidget-UAAWDBNS.mjs +8 -0
- package/dist/{ChatWidget-QPZTPSPE.mjs.map → ChatWidget-UAAWDBNS.mjs.map} +1 -1
- package/dist/EngageWidget-EZ5T6H3K.mjs +7 -0
- package/dist/{EngageWidget-IPBUA4DW.mjs.map → EngageWidget-EZ5T6H3K.mjs.map} +1 -1
- package/dist/EngageWidget-RWVWW56C.js +16 -0
- package/dist/{EngageWidget-N3CABK3L.js.map → EngageWidget-RWVWW56C.js.map} +1 -1
- package/dist/{SignalCore-4MDIJUAP.mjs → SignalCore-4B4RNYLV.mjs} +60 -47
- package/dist/SignalCore-4B4RNYLV.mjs.map +1 -0
- package/dist/{SignalCore-ZMFUE3N4.js → SignalCore-AECW2JFP.js} +60 -47
- package/dist/SignalCore-AECW2JFP.js.map +1 -0
- package/dist/SitemapSync-AICU4SSV.js +15 -0
- package/dist/{SitemapSync-FUCH6Y6J.js.map → SitemapSync-AICU4SSV.js.map} +1 -1
- package/dist/SitemapSync-CIZCAZXK.mjs +6 -0
- package/dist/{SitemapSync-LCSPRAWU.mjs.map → SitemapSync-CIZCAZXK.mjs.map} +1 -1
- package/dist/analytics/index.js +11 -9
- package/dist/analytics/index.mjs +4 -2
- package/dist/blog/index.js +12 -12
- package/dist/blog/index.mjs +2 -2
- package/dist/blog/server-ui.js +5 -5
- package/dist/blog/server-ui.mjs +1 -1
- package/dist/brand.css +8 -3
- package/dist/{chunk-QTWA44S3.mjs → chunk-2WYEJOGA.mjs} +7 -8
- package/dist/chunk-2WYEJOGA.mjs.map +1 -0
- package/dist/{chunk-AN4ATCYQ.mjs → chunk-45QHDA7Q.mjs} +3 -3
- package/dist/{chunk-AN4ATCYQ.mjs.map → chunk-45QHDA7Q.mjs.map} +1 -1
- package/dist/{chunk-RI6JZUAE.js → chunk-4FBV5BJW.js} +7 -8
- package/dist/chunk-4FBV5BJW.js.map +1 -0
- package/dist/{chunk-YJWKHCOB.js → chunk-4NTMIU6V.js} +13 -11
- package/dist/chunk-4NTMIU6V.js.map +1 -0
- package/dist/{chunk-YFGKIKXA.mjs → chunk-57QV6NIY.mjs} +3 -3
- package/dist/{chunk-YFGKIKXA.mjs.map → chunk-57QV6NIY.mjs.map} +1 -1
- package/dist/chunk-5OWZUNNE.js +102 -0
- package/dist/chunk-5OWZUNNE.js.map +1 -0
- package/dist/{chunk-EUDTPXUI.mjs → chunk-6HPNFWSC.mjs} +3 -3
- package/dist/{chunk-EUDTPXUI.mjs.map → chunk-6HPNFWSC.mjs.map} +1 -1
- package/dist/{chunk-ZM2ALSBM.js → chunk-7TX5BKVA.js} +18 -7
- package/dist/chunk-7TX5BKVA.js.map +1 -0
- package/dist/{chunk-FT5JNCD4.mjs → chunk-AB2VYIYU.mjs} +11 -11
- package/dist/{chunk-FT5JNCD4.mjs.map → chunk-AB2VYIYU.mjs.map} +1 -1
- package/dist/{chunk-I5TJIESQ.js → chunk-BMKZHXWQ.js} +11 -11
- package/dist/{chunk-I5TJIESQ.js.map → chunk-BMKZHXWQ.js.map} +1 -1
- package/dist/{chunk-KHFNPPOX.mjs → chunk-DSRPKUQI.mjs} +6 -6
- package/dist/{chunk-KHFNPPOX.mjs.map → chunk-DSRPKUQI.mjs.map} +1 -1
- package/dist/chunk-EAASMIWX.js +258 -0
- package/dist/chunk-EAASMIWX.js.map +1 -0
- package/dist/{chunk-T4QBSRA4.mjs → chunk-EIWRPGOK.mjs} +37 -60
- package/dist/chunk-EIWRPGOK.mjs.map +1 -0
- package/dist/{chunk-O7E6QVK3.js → chunk-GCDVKOSM.js} +3 -3
- package/dist/{chunk-O7E6QVK3.js.map → chunk-GCDVKOSM.js.map} +1 -1
- package/dist/{chunk-KMZ527EM.mjs → chunk-GN62H6EG.mjs} +34 -8
- package/dist/chunk-GN62H6EG.mjs.map +1 -0
- package/dist/{chunk-UJQYSVYV.js → chunk-GQF6QAQS.js} +4 -4
- package/dist/{chunk-UJQYSVYV.js.map → chunk-GQF6QAQS.js.map} +1 -1
- package/dist/{chunk-MLJXELPA.js → chunk-HAZN43I6.js} +60 -94
- package/dist/chunk-HAZN43I6.js.map +1 -0
- package/dist/chunk-LZSCCJ4O.mjs +253 -0
- package/dist/chunk-LZSCCJ4O.mjs.map +1 -0
- package/dist/{chunk-TCVHI3JP.mjs → chunk-N2HR2E4Z.mjs} +60 -92
- package/dist/chunk-N2HR2E4Z.mjs.map +1 -0
- package/dist/{chunk-VCWSSGCU.js → chunk-NAVDN4AE.js} +7 -7
- package/dist/{chunk-VCWSSGCU.js.map → chunk-NAVDN4AE.js.map} +1 -1
- package/dist/chunk-NDHFU4HV.mjs +97 -0
- package/dist/chunk-NDHFU4HV.mjs.map +1 -0
- package/dist/{chunk-PST3NOEM.mjs → chunk-O237KKCX.mjs} +4 -4
- package/dist/{chunk-PST3NOEM.mjs.map → chunk-O237KKCX.mjs.map} +1 -1
- package/dist/{chunk-5AESOLXS.mjs → chunk-OTY7EWET.mjs} +13 -11
- package/dist/chunk-OTY7EWET.mjs.map +1 -0
- package/dist/chunk-Q2NBD54V.js +69 -0
- package/dist/chunk-Q2NBD54V.js.map +1 -0
- package/dist/{chunk-DGHPOWLU.js → chunk-R5A64DCX.js} +8 -8
- package/dist/{chunk-DGHPOWLU.js.map → chunk-R5A64DCX.js.map} +1 -1
- package/dist/{chunk-3YQCPLGP.mjs → chunk-RFIWVH3D.mjs} +41 -79
- package/dist/chunk-RFIWVH3D.mjs.map +1 -0
- package/dist/{chunk-NNZDHLXN.js → chunk-S3YQGTBF.js} +35 -9
- package/dist/chunk-S3YQGTBF.js.map +1 -0
- package/dist/{chunk-IBDVZ6BF.js → chunk-SLWTG2LJ.js} +69 -74
- package/dist/chunk-SLWTG2LJ.js.map +1 -0
- package/dist/chunk-SN2O72UF.mjs +6 -0
- package/dist/chunk-SN2O72UF.mjs.map +1 -0
- package/dist/{chunk-65SMJBHW.mjs → chunk-T2DEEKVQ.mjs} +69 -74
- package/dist/chunk-T2DEEKVQ.mjs.map +1 -0
- package/dist/{chunk-3GCEFS73.js → chunk-TE3W5REY.js} +39 -62
- package/dist/chunk-TE3W5REY.js.map +1 -0
- package/dist/{chunk-IFVMZFNT.js → chunk-TVCCZ7NR.js} +41 -79
- package/dist/chunk-TVCCZ7NR.js.map +1 -0
- package/dist/{chunk-EBJ4S5DU.js → chunk-UT2CF4FC.js} +4 -4
- package/dist/{chunk-EBJ4S5DU.js.map → chunk-UT2CF4FC.js.map} +1 -1
- package/dist/chunk-V6NVBFEP.js +54 -0
- package/dist/chunk-V6NVBFEP.js.map +1 -0
- package/dist/{chunk-6FWQMKVO.mjs → chunk-WN5A3KSY.mjs} +18 -7
- package/dist/chunk-WN5A3KSY.mjs.map +1 -0
- package/dist/chunk-WRZQS7O4.js +8 -0
- package/dist/chunk-WRZQS7O4.js.map +1 -0
- package/dist/chunk-WZHWWOUC.js +51 -0
- package/dist/chunk-WZHWWOUC.js.map +1 -0
- package/dist/chunk-X3S6KXAP.mjs +47 -0
- package/dist/chunk-X3S6KXAP.mjs.map +1 -0
- package/dist/chunk-X4OPM3SK.mjs +43 -0
- package/dist/chunk-X4OPM3SK.mjs.map +1 -0
- package/dist/chunk-ZPLN537Q.mjs +57 -0
- package/dist/chunk-ZPLN537Q.mjs.map +1 -0
- package/dist/cli/index.js +8986 -1276
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +8972 -1280
- package/dist/cli/index.mjs.map +1 -1
- package/dist/commerce/index.js +50 -48
- package/dist/commerce/index.mjs +5 -3
- package/dist/engage/index.js +11 -8
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +8 -5
- package/dist/engage/index.mjs.map +1 -1
- package/dist/fleet/contract.d.mts +99 -0
- package/dist/fleet/contract.d.ts +99 -0
- package/dist/fleet/contract.js +53 -0
- package/dist/fleet/contract.js.map +1 -0
- package/dist/fleet/contract.mjs +4 -0
- package/dist/fleet/contract.mjs.map +1 -0
- package/dist/fleet/index.d.mts +89 -0
- package/dist/fleet/index.d.ts +89 -0
- package/dist/fleet/index.js +74 -0
- package/dist/fleet/index.js.map +1 -0
- package/dist/fleet/index.mjs +9 -0
- package/dist/fleet/index.mjs.map +1 -0
- package/dist/forms/contract.d.mts +69 -0
- package/dist/forms/contract.d.ts +69 -0
- package/dist/forms/contract.js +33 -0
- package/dist/forms/contract.js.map +1 -0
- package/dist/forms/contract.mjs +4 -0
- package/dist/forms/contract.mjs.map +1 -0
- package/dist/forms/index.js +21 -17
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +14 -10
- package/dist/forms/index.mjs.map +1 -1
- package/dist/forms/styles.css +10 -8
- package/dist/images/index.js +10 -8
- package/dist/images/index.mjs +3 -1
- package/dist/index.js +98 -96
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9 -7
- package/dist/index.mjs.map +1 -1
- package/dist/layout/client.d.mts +8 -1
- package/dist/layout/client.d.ts +8 -1
- package/dist/layout/client.js +8 -3
- package/dist/layout/client.mjs +7 -2
- package/dist/layout/index.d.mts +7 -1
- package/dist/layout/index.d.ts +7 -1
- package/dist/layout/index.js +57 -4
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/index.mjs +56 -3
- package/dist/layout/index.mjs.map +1 -1
- package/dist/llms/index.d.mts +4 -0
- package/dist/llms/index.d.ts +4 -0
- package/dist/llms/index.js +12 -12
- package/dist/llms/index.mjs +2 -2
- package/dist/maps/index.js +9 -18
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/index.mjs +9 -18
- package/dist/maps/index.mjs.map +1 -1
- package/dist/portfolio/contract.d.mts +61 -0
- package/dist/portfolio/contract.d.ts +61 -0
- package/dist/portfolio/contract.js +43 -0
- package/dist/portfolio/contract.js.map +1 -0
- package/dist/portfolio/contract.mjs +38 -0
- package/dist/portfolio/contract.mjs.map +1 -0
- package/dist/seo/client.js +4 -2
- package/dist/seo/client.mjs +3 -1
- package/dist/seo/index.js +4 -2
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +3 -1
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo-pages/contract.d.mts +62 -0
- package/dist/seo-pages/contract.d.ts +62 -0
- package/dist/seo-pages/contract.js +48 -0
- package/dist/seo-pages/contract.js.map +1 -0
- package/dist/seo-pages/contract.mjs +44 -0
- package/dist/seo-pages/contract.mjs.map +1 -0
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sitemap/index.js +2 -2
- package/dist/sitemap/index.mjs +1 -1
- package/dist/sites/contract.d.mts +57 -0
- package/dist/sites/contract.d.ts +57 -0
- package/dist/sites/contract.js +37 -0
- package/dist/sites/contract.js.map +1 -0
- package/dist/sites/contract.mjs +4 -0
- package/dist/sites/contract.mjs.map +1 -0
- package/package.json +44 -4
- package/skills/site-kit/SKILL.md +66 -0
- package/dist/AnalyticsProvider-MLT26JRP.mjs +0 -6
- package/dist/AnalyticsProvider-WTOGN7LV.js +0 -27
- package/dist/BlogPostFaqSection-H556RV62.js +0 -13
- package/dist/ChatWidget-MAL7FB4M.js +0 -14
- package/dist/ChatWidget-QPZTPSPE.mjs +0 -5
- package/dist/EngageWidget-IPBUA4DW.mjs +0 -5
- package/dist/EngageWidget-N3CABK3L.js +0 -14
- package/dist/SignalCore-4MDIJUAP.mjs.map +0 -1
- package/dist/SignalCore-ZMFUE3N4.js.map +0 -1
- package/dist/SitemapSync-FUCH6Y6J.js +0 -13
- package/dist/SitemapSync-LCSPRAWU.mjs +0 -4
- package/dist/chunk-3GCEFS73.js.map +0 -1
- package/dist/chunk-3YQCPLGP.mjs.map +0 -1
- package/dist/chunk-5AESOLXS.mjs.map +0 -1
- package/dist/chunk-65SMJBHW.mjs.map +0 -1
- package/dist/chunk-6FWQMKVO.mjs.map +0 -1
- package/dist/chunk-IBDVZ6BF.js.map +0 -1
- package/dist/chunk-IFVMZFNT.js.map +0 -1
- package/dist/chunk-KMZ527EM.mjs.map +0 -1
- package/dist/chunk-MLJXELPA.js.map +0 -1
- package/dist/chunk-NNZDHLXN.js.map +0 -1
- package/dist/chunk-QTWA44S3.mjs.map +0 -1
- package/dist/chunk-RI6JZUAE.js.map +0 -1
- package/dist/chunk-T4QBSRA4.mjs.map +0 -1
- package/dist/chunk-TCVHI3JP.mjs.map +0 -1
- package/dist/chunk-YJWKHCOB.js.map +0 -1
- package/dist/chunk-ZM2ALSBM.js.map +0 -1
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkWRZQS7O4_js = require('./chunk-WRZQS7O4.js');
|
|
4
|
+
|
|
5
|
+
// src/shared/siteToken.ts
|
|
6
|
+
var SITE_TOKEN_PREFIX = "st1.";
|
|
7
|
+
var REFRESH_SKEW_MS = 5 * 6e4;
|
|
8
|
+
var REFRESH_TIMEOUT_MS = 6e3;
|
|
9
|
+
var STORAGE_KEY = "__sonor_site_token__";
|
|
10
|
+
function isSiteToken(credential) {
|
|
11
|
+
return typeof credential === "string" && credential.startsWith(SITE_TOKEN_PREFIX);
|
|
12
|
+
}
|
|
13
|
+
function decodeSiteTokenClaims(token) {
|
|
14
|
+
if (!isSiteToken(token)) return null;
|
|
15
|
+
const seg = token.split(".")[1];
|
|
16
|
+
if (!seg) return null;
|
|
17
|
+
try {
|
|
18
|
+
const b64 = seg.replace(/-/g, "+").replace(/_/g, "/");
|
|
19
|
+
const json = typeof atob === "function" ? atob(b64) : Buffer.from(seg, "base64url").toString("utf8");
|
|
20
|
+
const claims = JSON.parse(json);
|
|
21
|
+
return typeof claims === "object" && claims ? claims : null;
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function credentialBreakerId(credential) {
|
|
27
|
+
if (!credential) return "(anonymous)";
|
|
28
|
+
const claims = decodeSiteTokenClaims(credential);
|
|
29
|
+
if (claims?.pid) return `pid:${claims.pid}`;
|
|
30
|
+
return credential.slice(0, 16);
|
|
31
|
+
}
|
|
32
|
+
var state = {
|
|
33
|
+
seed: void 0,
|
|
34
|
+
isToken: false,
|
|
35
|
+
apiUrl: "https://api.sonor.io",
|
|
36
|
+
token: null,
|
|
37
|
+
refreshing: null
|
|
38
|
+
};
|
|
39
|
+
function readStoredToken() {
|
|
40
|
+
if (typeof window === "undefined") return null;
|
|
41
|
+
try {
|
|
42
|
+
const raw = window.sessionStorage.getItem(STORAGE_KEY);
|
|
43
|
+
if (!raw) return null;
|
|
44
|
+
const parsed = JSON.parse(raw);
|
|
45
|
+
return typeof parsed?.token === "string" ? parsed.token : null;
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function storeToken(token) {
|
|
51
|
+
if (typeof window === "undefined") return;
|
|
52
|
+
try {
|
|
53
|
+
window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ token }));
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
;
|
|
58
|
+
window.__SITE_KIT_API_KEY__ = token;
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function tokenExp(token) {
|
|
63
|
+
const claims = decodeSiteTokenClaims(token);
|
|
64
|
+
return typeof claims?.exp === "number" ? claims.exp * 1e3 : 0;
|
|
65
|
+
}
|
|
66
|
+
function configureSiteCredential(opts) {
|
|
67
|
+
state.seed = opts.credential;
|
|
68
|
+
state.isToken = isSiteToken(opts.credential);
|
|
69
|
+
if (opts.apiUrl) state.apiUrl = opts.apiUrl.replace(/\/+$/, "");
|
|
70
|
+
if (!state.isToken) {
|
|
71
|
+
state.token = null;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const prior = state.token;
|
|
75
|
+
let best = opts.credential ?? null;
|
|
76
|
+
const stored = readStoredToken();
|
|
77
|
+
if (stored && tokenExp(stored) > tokenExp(best)) best = stored;
|
|
78
|
+
if (prior && tokenExp(prior) > tokenExp(best)) best = prior;
|
|
79
|
+
state.token = best;
|
|
80
|
+
}
|
|
81
|
+
function needsRefresh() {
|
|
82
|
+
if (!state.isToken) return false;
|
|
83
|
+
if (!state.token) return true;
|
|
84
|
+
return Date.now() >= tokenExp(state.token) - REFRESH_SKEW_MS;
|
|
85
|
+
}
|
|
86
|
+
async function doRefresh() {
|
|
87
|
+
const current = state.token;
|
|
88
|
+
if (!current) return null;
|
|
89
|
+
try {
|
|
90
|
+
const res = await fetch(`${state.apiUrl}/api/public/site-token/refresh`, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: {
|
|
93
|
+
"content-type": "application/json",
|
|
94
|
+
"x-sitekit-version": chunkWRZQS7O4_js.SITE_KIT_VERSION,
|
|
95
|
+
// Send the current token as x-api-key too, so the server's key-scoped
|
|
96
|
+
// throttler buckets refreshes by token rather than by shared CDN IP.
|
|
97
|
+
"x-api-key": current
|
|
98
|
+
},
|
|
99
|
+
body: JSON.stringify({ token: current }),
|
|
100
|
+
signal: typeof AbortSignal !== "undefined" && AbortSignal.timeout ? AbortSignal.timeout(REFRESH_TIMEOUT_MS) : void 0
|
|
101
|
+
});
|
|
102
|
+
if (!res.ok) return null;
|
|
103
|
+
const data = await res.json().catch(() => null);
|
|
104
|
+
const next = data?.token;
|
|
105
|
+
if (typeof next === "string" && isSiteToken(next)) {
|
|
106
|
+
state.token = next;
|
|
107
|
+
storeToken(next);
|
|
108
|
+
return next;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
} catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function refreshSiteToken() {
|
|
116
|
+
if (!state.isToken) return Promise.resolve(null);
|
|
117
|
+
if (state.refreshing) return state.refreshing;
|
|
118
|
+
state.refreshing = doRefresh().finally(() => {
|
|
119
|
+
state.refreshing = null;
|
|
120
|
+
});
|
|
121
|
+
return state.refreshing;
|
|
122
|
+
}
|
|
123
|
+
async function getFreshCredential(seed) {
|
|
124
|
+
if (!state.isToken) return seed ?? state.seed;
|
|
125
|
+
if (needsRefresh()) {
|
|
126
|
+
const refreshed = await refreshSiteToken();
|
|
127
|
+
if (refreshed) return refreshed;
|
|
128
|
+
}
|
|
129
|
+
return state.token ?? seed ?? state.seed;
|
|
130
|
+
}
|
|
131
|
+
function isTokenMode() {
|
|
132
|
+
return state.isToken;
|
|
133
|
+
}
|
|
134
|
+
function currentCredential(seed) {
|
|
135
|
+
if (!state.isToken) return seed ?? state.seed;
|
|
136
|
+
return state.token ?? seed ?? state.seed;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/shared/fetchWithRetry.ts
|
|
140
|
+
function backoffDelay(attempt, response) {
|
|
141
|
+
if (response?.status === 429) {
|
|
142
|
+
const header = response.headers.get("retry-after");
|
|
143
|
+
const seconds = header ? parseInt(header, 10) : NaN;
|
|
144
|
+
if (!Number.isNaN(seconds) && seconds > 0) return Math.min(seconds * 1e3, 1e4);
|
|
145
|
+
}
|
|
146
|
+
return Math.min(8e3, 500 * 2 ** attempt);
|
|
147
|
+
}
|
|
148
|
+
async function fetchWithRetry(url, init, options = {}) {
|
|
149
|
+
const retries = options.retries ?? 2;
|
|
150
|
+
const timeoutMs = options.timeoutMs ?? 15e3;
|
|
151
|
+
let lastError;
|
|
152
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
153
|
+
const controller = new AbortController();
|
|
154
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
155
|
+
try {
|
|
156
|
+
const response = await fetch(url, { ...init, signal: controller.signal });
|
|
157
|
+
clearTimeout(timer);
|
|
158
|
+
if ((response.status === 429 || response.status >= 500) && attempt < retries) {
|
|
159
|
+
await new Promise((resolve) => setTimeout(resolve, backoffDelay(attempt, response)));
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
return response;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
lastError = error;
|
|
166
|
+
if (attempt < retries) {
|
|
167
|
+
await new Promise((resolve) => setTimeout(resolve, backoffDelay(attempt)));
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
throw lastError instanceof Error ? lastError : new Error("Network request failed after multiple attempts. Please try again.");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/shared/sonorFetch.ts
|
|
176
|
+
var AUTH_BREAK_MS = 5 * 6e4;
|
|
177
|
+
var pausedKeys = /* @__PURE__ */ new Map();
|
|
178
|
+
var warnedThisPage = false;
|
|
179
|
+
function isAuthPaused(credential) {
|
|
180
|
+
if (typeof window === "undefined") return false;
|
|
181
|
+
const id = credentialBreakerId(credential);
|
|
182
|
+
const until = pausedKeys.get(id);
|
|
183
|
+
if (!until) return false;
|
|
184
|
+
if (Date.now() >= until) {
|
|
185
|
+
pausedKeys.delete(id);
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
function tripBreaker(credential) {
|
|
191
|
+
pausedKeys.set(credentialBreakerId(credential), Date.now() + AUTH_BREAK_MS);
|
|
192
|
+
if (!warnedThisPage) {
|
|
193
|
+
warnedThisPage = true;
|
|
194
|
+
console.info(
|
|
195
|
+
"[Sonor] This site couldn't authenticate with Sonor, so data features are paused for a few minutes. If this keeps happening, the site is likely running an outdated API key."
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async function sonorFetch(url, init = {}, options = {}) {
|
|
200
|
+
let credential = options.apiKey;
|
|
201
|
+
if (credential !== void 0 || isTokenMode()) {
|
|
202
|
+
credential = await getFreshCredential(options.apiKey);
|
|
203
|
+
}
|
|
204
|
+
const headers = new Headers(init.headers || {});
|
|
205
|
+
headers.set("x-sitekit-version", chunkWRZQS7O4_js.SITE_KIT_VERSION);
|
|
206
|
+
if (credential && !headers.has("x-api-key")) {
|
|
207
|
+
headers.set("x-api-key", credential);
|
|
208
|
+
}
|
|
209
|
+
if (isAuthPaused(credential)) {
|
|
210
|
+
return new Response(null, { status: 401, statusText: "sonor-auth-paused" });
|
|
211
|
+
}
|
|
212
|
+
let response = await fetchWithRetry(url, { ...init, headers }, options);
|
|
213
|
+
if ((response.status === 401 || response.status === 403) && typeof window !== "undefined" && isSiteToken(credential)) {
|
|
214
|
+
const refreshed = await refreshSiteToken();
|
|
215
|
+
if (refreshed && refreshed !== credential) {
|
|
216
|
+
const retryHeaders = new Headers(init.headers || {});
|
|
217
|
+
retryHeaders.set("x-sitekit-version", chunkWRZQS7O4_js.SITE_KIT_VERSION);
|
|
218
|
+
retryHeaders.set("x-api-key", refreshed);
|
|
219
|
+
credential = refreshed;
|
|
220
|
+
response = await fetchWithRetry(url, { ...init, headers: retryHeaders }, options);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if ((response.status === 401 || response.status === 403) && typeof window !== "undefined" && credential) {
|
|
224
|
+
tripBreaker(credential);
|
|
225
|
+
}
|
|
226
|
+
return response;
|
|
227
|
+
}
|
|
228
|
+
function sonorBeacon(url, payload, apiKey) {
|
|
229
|
+
const credential = currentCredential(apiKey);
|
|
230
|
+
const body = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
231
|
+
try {
|
|
232
|
+
void fetch(url, {
|
|
233
|
+
method: "POST",
|
|
234
|
+
keepalive: true,
|
|
235
|
+
headers: {
|
|
236
|
+
"Content-Type": "application/json",
|
|
237
|
+
"x-sitekit-version": chunkWRZQS7O4_js.SITE_KIT_VERSION,
|
|
238
|
+
...credential ? { "x-api-key": credential } : {}
|
|
239
|
+
},
|
|
240
|
+
body
|
|
241
|
+
}).catch(() => {
|
|
242
|
+
});
|
|
243
|
+
} catch {
|
|
244
|
+
try {
|
|
245
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
246
|
+
navigator.sendBeacon(url, new Blob([body], { type: "application/json" }));
|
|
247
|
+
}
|
|
248
|
+
} catch {
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
exports.configureSiteCredential = configureSiteCredential;
|
|
254
|
+
exports.currentCredential = currentCredential;
|
|
255
|
+
exports.sonorBeacon = sonorBeacon;
|
|
256
|
+
exports.sonorFetch = sonorFetch;
|
|
257
|
+
//# sourceMappingURL=chunk-EAASMIWX.js.map
|
|
258
|
+
//# sourceMappingURL=chunk-EAASMIWX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/siteToken.ts","../src/shared/fetchWithRetry.ts","../src/shared/sonorFetch.ts"],"names":["SITE_KIT_VERSION"],"mappings":";;;;;AAuBO,IAAM,iBAAA,GAAoB,MAAA;AAGjC,IAAM,kBAAkB,CAAA,GAAI,GAAA;AAC5B,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,WAAA,GAAc,sBAAA;AAEb,SAAS,YAAY,UAAA,EAAqC;AAC/D,EAAA,OAAO,OAAO,UAAA,KAAe,QAAA,IAAY,UAAA,CAAW,WAAW,iBAAiB,CAAA;AAClF;AASO,SAAS,sBAAsB,KAAA,EAA6C;AACjF,EAAA,IAAI,CAAC,WAAA,CAAY,KAAK,CAAA,EAAG,OAAO,IAAA;AAChC,EAAA,MAAM,GAAA,GAAO,KAAA,CAAiB,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA;AAC1C,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,IAAI;AAEF,IAAA,MAAM,GAAA,GAAM,IAAI,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAM,GAAG,CAAA;AACpD,IAAA,MAAM,IAAA,GACJ,OAAO,IAAA,KAAS,UAAA,GACZ,IAAA,CAAK,GAAG,CAAA,GACR,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,WAAW,CAAA,CAAE,SAAS,MAAM,CAAA;AACnD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC9B,IAAA,OAAO,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,GAAS,MAAA,GAAS,IAAA;AAAA,EACzD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAOO,SAAS,oBAAoB,UAAA,EAAoC;AACtE,EAAA,IAAI,CAAC,YAAY,OAAO,aAAA;AACxB,EAAA,MAAM,MAAA,GAAS,sBAAsB,UAAU,CAAA;AAC/C,EAAA,IAAI,MAAA,EAAQ,GAAA,EAAK,OAAO,CAAA,IAAA,EAAO,OAAO,GAAG,CAAA,CAAA;AACzC,EAAA,OAAO,UAAA,CAAW,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAC/B;AAeA,IAAM,KAAA,GAAoB;AAAA,EACxB,IAAA,EAAM,MAAA;AAAA,EACN,OAAA,EAAS,KAAA;AAAA,EACT,MAAA,EAAQ,sBAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,UAAA,EAAY;AACd,CAAA;AAEA,SAAS,eAAA,GAAiC;AACxC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAC1C,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,cAAA,CAAe,OAAA,CAAQ,WAAW,CAAA;AACrD,IAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,OAAO,MAAA,EAAQ,KAAA,KAAU,QAAA,GAAW,OAAO,KAAA,GAAQ,IAAA;AAAA,EAC5D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,WAAW,KAAA,EAAqB;AACvC,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,cAAA,CAAe,QAAQ,WAAA,EAAa,IAAA,CAAK,UAAU,EAAE,KAAA,EAAO,CAAC,CAAA;AAAA,EACtE,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,IAAI;AACF,IAAA;AAAC,IAAC,OAAe,oBAAA,GAAuB,KAAA;AAAA,EAC1C,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAEA,SAAS,SAAS,KAAA,EAA8B;AAC9C,EAAA,MAAM,MAAA,GAAS,sBAAsB,KAAK,CAAA;AAC1C,EAAA,OAAO,OAAO,MAAA,EAAQ,GAAA,KAAQ,QAAA,GAAW,MAAA,CAAO,MAAM,GAAA,GAAO,CAAA;AAC/D;AAMO,SAAS,wBAAwB,IAAA,EAG/B;AACP,EAAA,KAAA,CAAM,OAAO,IAAA,CAAK,UAAA;AAClB,EAAA,KAAA,CAAM,OAAA,GAAU,WAAA,CAAY,IAAA,CAAK,UAAU,CAAA;AAC3C,EAAA,IAAI,IAAA,CAAK,QAAQ,KAAA,CAAM,MAAA,GAAS,KAAK,MAAA,CAAO,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAE9D,EAAA,IAAI,CAAC,MAAM,OAAA,EAAS;AAClB,IAAA,KAAA,CAAM,KAAA,GAAQ,IAAA;AACd,IAAA;AAAA,EACF;AAKA,EAAA,MAAM,QAAQ,KAAA,CAAM,KAAA;AACpB,EAAA,IAAI,IAAA,GAAO,KAAK,UAAA,IAAc,IAAA;AAC9B,EAAA,MAAM,SAAS,eAAA,EAAgB;AAC/B,EAAA,IAAI,UAAU,QAAA,CAAS,MAAM,IAAI,QAAA,CAAS,IAAI,GAAG,IAAA,GAAO,MAAA;AACxD,EAAA,IAAI,SAAS,QAAA,CAAS,KAAK,IAAI,QAAA,CAAS,IAAI,GAAG,IAAA,GAAO,KAAA;AACtD,EAAA,KAAA,CAAM,KAAA,GAAQ,IAAA;AAChB;AAEA,SAAS,YAAA,GAAwB;AAC/B,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,OAAO,KAAA;AAC3B,EAAA,IAAI,CAAC,KAAA,CAAM,KAAA,EAAO,OAAO,IAAA;AACzB,EAAA,OAAO,KAAK,GAAA,EAAI,IAAK,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA,GAAI,eAAA;AAC/C;AAEA,eAAe,SAAA,GAAoC;AACjD,EAAA,MAAM,UAAU,KAAA,CAAM,KAAA;AACtB,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,MAAM,MAAM,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,MAAM,CAAA,8BAAA,CAAA,EAAkC;AAAA,MACvE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,mBAAA,EAAqBA,iCAAA;AAAA;AAAA;AAAA,QAGrB,WAAA,EAAa;AAAA,OACf;AAAA,MACA,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,SAAS,CAAA;AAAA,MACvC,MAAA,EACE,OAAO,WAAA,KAAgB,WAAA,IAAe,YAAY,OAAA,GAC9C,WAAA,CAAY,OAAA,CAAQ,kBAAkB,CAAA,GACtC,KAAA;AAAA,KACP,CAAA;AACD,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,OAAO,IAAA;AACpB,IAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AAC9C,IAAA,MAAM,OAAO,IAAA,EAAM,KAAA;AACnB,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,WAAA,CAAY,IAAI,CAAA,EAAG;AACjD,MAAA,KAAA,CAAM,KAAA,GAAQ,IAAA;AACd,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGO,SAAS,gBAAA,GAA2C;AACzD,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,OAAO,OAAA,CAAQ,QAAQ,IAAI,CAAA;AAC/C,EAAA,IAAI,KAAA,CAAM,UAAA,EAAY,OAAO,KAAA,CAAM,UAAA;AACnC,EAAA,KAAA,CAAM,UAAA,GAAa,SAAA,EAAU,CAAE,OAAA,CAAQ,MAAM;AAC3C,IAAA,KAAA,CAAM,UAAA,GAAa,IAAA;AAAA,EACrB,CAAC,CAAA;AACD,EAAA,OAAO,KAAA,CAAM,UAAA;AACf;AAMA,eAAsB,mBACpB,IAAA,EAC6B;AAE7B,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,OAAO,QAAQ,KAAA,CAAM,IAAA;AACzC,EAAA,IAAI,cAAa,EAAG;AAClB,IAAA,MAAM,SAAA,GAAY,MAAM,gBAAA,EAAiB;AACzC,IAAA,IAAI,WAAW,OAAO,SAAA;AAAA,EAGxB;AACA,EAAA,OAAO,KAAA,CAAM,KAAA,IAAS,IAAA,IAAQ,KAAA,CAAM,IAAA;AACtC;AAGO,SAAS,WAAA,GAAuB;AACrC,EAAA,OAAO,KAAA,CAAM,OAAA;AACf;AAOO,SAAS,kBAAkB,IAAA,EAAmC;AACnE,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,OAAO,QAAQ,KAAA,CAAM,IAAA;AACzC,EAAA,OAAO,KAAA,CAAM,KAAA,IAAS,IAAA,IAAQ,KAAA,CAAM,IAAA;AACtC;;;ACjNA,SAAS,YAAA,CAAa,SAAiB,QAAA,EAA6B;AAElE,EAAA,IAAI,QAAA,EAAU,WAAW,GAAA,EAAK;AAC5B,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA;AACjD,IAAA,MAAM,OAAA,GAAU,MAAA,GAAS,QAAA,CAAS,MAAA,EAAQ,EAAE,CAAA,GAAI,GAAA;AAChD,IAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,OAAO,CAAA,IAAK,OAAA,GAAU,CAAA,EAAG,OAAO,IAAA,CAAK,GAAA,CAAI,OAAA,GAAU,GAAA,EAAM,GAAK,CAAA;AAAA,EAClF;AAEA,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,GAAA,EAAM,GAAA,GAAM,KAAK,OAAO,CAAA;AAC1C;AASA,eAAsB,cAAA,CACpB,GAAA,EACA,IAAA,EACA,OAAA,GAA6B,EAAC,EACX;AACnB,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,CAAA;AACnC,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,IAAA;AACvC,EAAA,IAAI,SAAA;AAEJ,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,OAAA,EAAS,OAAA,EAAA,EAAW;AACnD,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,SAAS,CAAA;AAC5D,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,UAAA,CAAW,MAAA,EAAQ,CAAA;AACxE,MAAA,YAAA,CAAa,KAAK,CAAA;AAElB,MAAA,IAAA,CAAK,SAAS,MAAA,KAAW,GAAA,IAAO,SAAS,MAAA,IAAU,GAAA,KAAQ,UAAU,OAAA,EAAS;AAC5E,QAAA,MAAM,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,SAAS,YAAA,CAAa,OAAA,EAAS,QAAQ,CAAC,CAAC,CAAA;AACnF,QAAA;AAAA,MACF;AACA,MAAA,OAAO,QAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,SAAA,GAAY,KAAA;AAEZ,MAAA,IAAI,UAAU,OAAA,EAAS;AACrB,QAAA,MAAM,IAAI,QAAQ,CAAC,OAAA,KAAY,WAAW,OAAA,EAAS,YAAA,CAAa,OAAO,CAAC,CAAC,CAAA;AACzE,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,YAAqB,KAAA,GACvB,SAAA,GACA,IAAI,MAAM,mEAAmE,CAAA;AACnF;;;AC7BA,IAAM,gBAAgB,CAAA,GAAI,GAAA;AAI1B,IAAM,UAAA,uBAAiB,GAAA,EAAoB;AAC3C,IAAI,cAAA,GAAiB,KAAA;AAGd,SAAS,aAAa,UAAA,EAA8B;AACzD,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,KAAA;AAC1C,EAAA,MAAM,EAAA,GAAK,oBAAoB,UAAU,CAAA;AACzC,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,GAAA,CAAI,EAAE,CAAA;AAC/B,EAAA,IAAI,CAAC,OAAO,OAAO,KAAA;AACnB,EAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,KAAA,EAAO;AACvB,IAAA,UAAA,CAAW,OAAO,EAAE,CAAA;AACpB,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,YAAY,UAAA,EAA2B;AAC9C,EAAA,UAAA,CAAW,IAAI,mBAAA,CAAoB,UAAU,GAAG,IAAA,CAAK,GAAA,KAAQ,aAAa,CAAA;AAC1E,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,cAAA,GAAiB,IAAA;AAGjB,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN;AAAA,KACF;AAAA,EACF;AACF;AAEA,eAAsB,WACpB,GAAA,EACA,IAAA,GAAoB,EAAC,EACrB,OAAA,GAA6B,EAAC,EACX;AAGnB,EAAA,IAAI,aAAa,OAAA,CAAQ,MAAA;AACzB,EAAA,IAAI,UAAA,KAAe,MAAA,IAAa,WAAA,EAAY,EAAG;AAC7C,IAAA,UAAA,GAAa,MAAM,kBAAA,CAAmB,OAAA,CAAQ,MAAM,CAAA;AAAA,EACtD;AAEA,EAAA,MAAM,UAAU,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AAC9C,EAAA,OAAA,CAAQ,GAAA,CAAI,qBAAqBA,iCAAgB,CAAA;AACjD,EAAA,IAAI,UAAA,IAAc,CAAC,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA,EAAG;AAC3C,IAAA,OAAA,CAAQ,GAAA,CAAI,aAAa,UAAU,CAAA;AAAA,EACrC;AAEA,EAAA,IAAI,YAAA,CAAa,UAAU,CAAA,EAAG;AAG5B,IAAA,OAAO,IAAI,SAAS,IAAA,EAAM,EAAE,QAAQ,GAAA,EAAK,UAAA,EAAY,qBAAqB,CAAA;AAAA,EAC5E;AAEA,EAAA,IAAI,QAAA,GAAW,MAAM,cAAA,CAAe,GAAA,EAAK,EAAE,GAAG,IAAA,EAAM,OAAA,EAAQ,EAAG,OAAO,CAAA;AAKtE,EAAA,IAAA,CACG,QAAA,CAAS,MAAA,KAAW,GAAA,IAAO,QAAA,CAAS,MAAA,KAAW,GAAA,KAChD,OAAO,MAAA,KAAW,WAAA,IAClB,WAAA,CAAY,UAAU,CAAA,EACtB;AACA,IAAA,MAAM,SAAA,GAAY,MAAM,gBAAA,EAAiB;AACzC,IAAA,IAAI,SAAA,IAAa,cAAc,UAAA,EAAY;AACzC,MAAA,MAAM,eAAe,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AACnD,MAAA,YAAA,CAAa,GAAA,CAAI,qBAAqBA,iCAAgB,CAAA;AACtD,MAAA,YAAA,CAAa,GAAA,CAAI,aAAa,SAAS,CAAA;AACvC,MAAA,UAAA,GAAa,SAAA;AACb,MAAA,QAAA,GAAW,MAAM,eAAe,GAAA,EAAK,EAAE,GAAG,IAAA,EAAM,OAAA,EAAS,YAAA,EAAa,EAAG,OAAO,CAAA;AAAA,IAClF;AAAA,EACF;AAEA,EAAA,IAAA,CACG,QAAA,CAAS,WAAW,GAAA,IAAO,QAAA,CAAS,WAAW,GAAA,KAChD,OAAO,MAAA,KAAW,WAAA,IAClB,UAAA,EACA;AACA,IAAA,WAAA,CAAY,UAAU,CAAA;AAAA,EACxB;AAEA,EAAA,OAAO,QAAA;AACT;AAYO,SAAS,WAAA,CAAY,GAAA,EAAa,OAAA,EAAkB,MAAA,EAAuB;AAChF,EAAA,MAAM,UAAA,GAAa,kBAAkB,MAAM,CAAA;AAC3C,EAAA,MAAM,OAAO,OAAO,OAAA,KAAY,WAAW,OAAA,GAAU,IAAA,CAAK,UAAU,OAAO,CAAA;AAC3E,EAAA,IAAI;AACF,IAAA,KAAK,MAAM,GAAA,EAAK;AAAA,MACd,MAAA,EAAQ,MAAA;AAAA,MACR,SAAA,EAAW,IAAA;AAAA,MACX,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,mBAAA,EAAqBA,iCAAA;AAAA,QACrB,GAAI,UAAA,GAAa,EAAE,WAAA,EAAa,UAAA,KAAe;AAAC,OAClD;AAAA,MACA;AAAA,KACD,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,IAEf,CAAC,CAAA;AAAA,EACH,CAAA,CAAA,MAAQ;AACN,IAAA,IAAI;AACF,MAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,SAAA,CAAU,UAAA,EAAY;AAC5D,QAAA,SAAA,CAAU,UAAA,CAAW,GAAA,EAAK,IAAI,IAAA,CAAK,CAAC,IAAI,CAAA,EAAG,EAAE,IAAA,EAAM,kBAAA,EAAoB,CAAC,CAAA;AAAA,MAC1E;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACF","file":"chunk-EAASMIWX.js","sourcesContent":["/**\n * @sonordev/site-kit shared — Client token manager\n *\n * SiteKitLayout (a server component) no longer ships the raw `sonor_` API key to\n * the browser. Instead it mints a short-lived, project-scoped token server-side\n * and injects THAT. This module is the browser-side lifecycle for that token:\n *\n * - holds the current token (seeded from the injected value)\n * - a static page's seed can be days old and already expired on first view, so\n * it transparently REFRESHES via the public endpoint before first use\n * - dedupes concurrent refreshes (one in-flight request, awaited by all)\n * - persists the freshest token in sessionStorage so navigations within a\n * session don't each re-refresh\n *\n * Everything here is a no-op passthrough when the injected credential is a raw\n * key (a 2.x kit, or the mint-failed fallback) — legacy behavior is unchanged.\n * Fully SSR-safe: on the server there is no refresh, just the seed.\n *\n * The token payload is NOT secret (only its HMAC is unforgeable), so decoding it\n * client-side to read `exp`/`pid` is fine and needs no crypto.\n */\nimport { SITE_KIT_VERSION } from './version'\n\nexport const SITE_TOKEN_PREFIX = 'st1.'\n\n/** Refresh this many ms before expiry, so a request never races the deadline. */\nconst REFRESH_SKEW_MS = 5 * 60_000\nconst REFRESH_TIMEOUT_MS = 6_000\nconst STORAGE_KEY = '__sonor_site_token__'\n\nexport function isSiteToken(credential?: string | null): boolean {\n return typeof credential === 'string' && credential.startsWith(SITE_TOKEN_PREFIX)\n}\n\ninterface DecodedClaims {\n pid?: string\n iat?: number\n exp?: number\n}\n\n/** Decode the (non-secret) token payload. Returns null if not a token / malformed. */\nexport function decodeSiteTokenClaims(token?: string | null): DecodedClaims | null {\n if (!isSiteToken(token)) return null\n const seg = (token as string).split('.')[1]\n if (!seg) return null\n try {\n // base64url → JSON. atob handles standard base64; restore url-safe chars.\n const b64 = seg.replace(/-/g, '+').replace(/_/g, '/')\n const json =\n typeof atob === 'function'\n ? atob(b64)\n : Buffer.from(seg, 'base64url').toString('utf8')\n const claims = JSON.parse(json)\n return typeof claims === 'object' && claims ? claims : null\n } catch {\n return null\n }\n}\n\n/**\n * Stable id for the auth circuit breaker. Tokens rotate, so keying the breaker\n * by the raw value would reset it every refresh — key by the project id encoded\n * in the token instead. Raw keys use a safe prefix.\n */\nexport function credentialBreakerId(credential?: string | null): string {\n if (!credential) return '(anonymous)'\n const claims = decodeSiteTokenClaims(credential)\n if (claims?.pid) return `pid:${claims.pid}`\n return credential.slice(0, 16)\n}\n\ninterface TokenState {\n /** The credential injected by the layout (token or raw key). */\n seed: string | undefined\n /** Whether we're in token mode (seed is a token). */\n isToken: boolean\n /** Base API URL for the refresh endpoint. */\n apiUrl: string\n /** The freshest known token (>= seed). Null in raw-key mode. */\n token: string | null\n /** In-flight refresh, deduped. */\n refreshing: Promise<string | null> | null\n}\n\nconst state: TokenState = {\n seed: undefined,\n isToken: false,\n apiUrl: 'https://api.sonor.io',\n token: null,\n refreshing: null,\n}\n\nfunction readStoredToken(): string | null {\n if (typeof window === 'undefined') return null\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY)\n if (!raw) return null\n const parsed = JSON.parse(raw)\n return typeof parsed?.token === 'string' ? parsed.token : null\n } catch {\n return null\n }\n}\n\nfunction storeToken(token: string): void {\n if (typeof window === 'undefined') return\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ token }))\n } catch {\n /* private mode / disabled storage — memory-only is fine */\n }\n try {\n ;(window as any).__SITE_KIT_API_KEY__ = token\n } catch {\n /* ignore */\n }\n}\n\nfunction tokenExp(token: string | null): number {\n const claims = decodeSiteTokenClaims(token)\n return typeof claims?.exp === 'number' ? claims.exp * 1000 : 0\n}\n\n/**\n * Configure the manager from the layout-injected values. Adopts a fresher token\n * from sessionStorage if a prior page in this session already refreshed.\n */\nexport function configureSiteCredential(opts: {\n credential?: string\n apiUrl?: string\n}): void {\n state.seed = opts.credential\n state.isToken = isSiteToken(opts.credential)\n if (opts.apiUrl) state.apiUrl = opts.apiUrl.replace(/\\/+$/, '')\n\n if (!state.isToken) {\n state.token = null\n return\n }\n\n // configure runs on every render — never downgrade. Keep the freshest of the\n // injected seed, a token stored by an earlier page this session, and whatever\n // an in-flight/prior refresh already put in memory.\n const prior = state.token\n let best = opts.credential ?? null\n const stored = readStoredToken()\n if (stored && tokenExp(stored) > tokenExp(best)) best = stored\n if (prior && tokenExp(prior) > tokenExp(best)) best = prior\n state.token = best\n}\n\nfunction needsRefresh(): boolean {\n if (!state.isToken) return false\n if (!state.token) return true\n return Date.now() >= tokenExp(state.token) - REFRESH_SKEW_MS\n}\n\nasync function doRefresh(): Promise<string | null> {\n const current = state.token\n if (!current) return null\n try {\n const res = await fetch(`${state.apiUrl}/api/public/site-token/refresh`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-sitekit-version': SITE_KIT_VERSION,\n // Send the current token as x-api-key too, so the server's key-scoped\n // throttler buckets refreshes by token rather than by shared CDN IP.\n 'x-api-key': current,\n },\n body: JSON.stringify({ token: current }),\n signal:\n typeof AbortSignal !== 'undefined' && AbortSignal.timeout\n ? AbortSignal.timeout(REFRESH_TIMEOUT_MS)\n : undefined,\n })\n if (!res.ok) return null\n const data = await res.json().catch(() => null)\n const next = data?.token\n if (typeof next === 'string' && isSiteToken(next)) {\n state.token = next\n storeToken(next)\n return next\n }\n return null\n } catch {\n return null\n }\n}\n\n/** Refresh now (deduped). Returns the new token, or null on failure. */\nexport function refreshSiteToken(): Promise<string | null> {\n if (!state.isToken) return Promise.resolve(null)\n if (state.refreshing) return state.refreshing\n state.refreshing = doRefresh().finally(() => {\n state.refreshing = null\n })\n return state.refreshing\n}\n\n/**\n * The credential to put on the next request. In token mode, refreshes a stale\n * seed first. In raw-key mode, returns the seed unchanged (legacy passthrough).\n */\nexport async function getFreshCredential(\n seed?: string,\n): Promise<string | undefined> {\n // A raw key (or nothing configured) — no token machinery.\n if (!state.isToken) return seed ?? state.seed\n if (needsRefresh()) {\n const refreshed = await refreshSiteToken()\n if (refreshed) return refreshed\n // Refresh failed — fall through to whatever we have; the request may 401 and\n // trip the breaker with friendly copy.\n }\n return state.token ?? seed ?? state.seed\n}\n\n/** Whether the given credential is being managed as a token. */\nexport function isTokenMode(): boolean {\n return state.isToken\n}\n\n/**\n * Best-known credential WITHOUT refreshing — for synchronous unload paths\n * (sonorBeacon) that can't await. In token mode returns the freshest token held;\n * in raw-key mode returns the seed.\n */\nexport function currentCredential(seed?: string): string | undefined {\n if (!state.isToken) return seed ?? state.seed\n return state.token ?? seed ?? state.seed\n}\n","/**\n * @sonordev/site-kit shared - Resilient fetch\n *\n * Single source of truth for client-side resilient fetch (forms, SitemapSync).\n * Adds a per-attempt timeout and retries transient failures (network errors,\n * request timeouts, HTTP 429, and 5xx) with exponential backoff.\n *\n * A form submission must survive a brief API blip — a deploy, a cold start, a\n * dropped packet. A single un-retried fetch turning into \"Something went wrong\"\n * is how leads get lost. The explicit abort also matters on its own: a request\n * left to hang until the browser's own network timeout logs a console error\n * (net::ERR_TIMED_OUT) that fails Lighthouse best-practices; an aborted fetch\n * logs nothing.\n */\n\nexport interface FetchRetryOptions {\n /** Number of retries AFTER the first attempt (default 2 → up to 3 tries total). */\n retries?: number\n /** Per-attempt timeout in milliseconds (default 15000). */\n timeoutMs?: number\n}\n\nfunction backoffDelay(attempt: number, response?: Response): number {\n // Honor a Retry-After header on 429 responses when present.\n if (response?.status === 429) {\n const header = response.headers.get('retry-after')\n const seconds = header ? parseInt(header, 10) : NaN\n if (!Number.isNaN(seconds) && seconds > 0) return Math.min(seconds * 1000, 10000)\n }\n // Exponential backoff: 500ms, 1s, 2s, ... capped at 8s.\n return Math.min(8000, 500 * 2 ** attempt)\n}\n\n/**\n * fetch() with a timeout and automatic retries for transient failures.\n *\n * Non-transient responses (2xx, 3xx, and 4xx other than 429) are returned to\n * the caller as-is — only 429/5xx and thrown network/timeout errors are retried.\n * If every attempt fails with a thrown error, the last error is re-thrown.\n */\nexport async function fetchWithRetry(\n url: string,\n init: RequestInit,\n options: FetchRetryOptions = {},\n): Promise<Response> {\n const retries = options.retries ?? 2\n const timeoutMs = options.timeoutMs ?? 15000\n let lastError: unknown\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n const response = await fetch(url, { ...init, signal: controller.signal })\n clearTimeout(timer)\n\n if ((response.status === 429 || response.status >= 500) && attempt < retries) {\n await new Promise((resolve) => setTimeout(resolve, backoffDelay(attempt, response)))\n continue\n }\n return response\n } catch (error) {\n clearTimeout(timer)\n lastError = error\n // Network failure or timeout (AbortController) — retry while attempts remain.\n if (attempt < retries) {\n await new Promise((resolve) => setTimeout(resolve, backoffDelay(attempt)))\n continue\n }\n }\n }\n\n throw lastError instanceof Error\n ? lastError\n : new Error('Network request failed after multiple attempts. Please try again.')\n}\n","/**\n * @sonordev/site-kit shared - Canonical client transport\n *\n * Single source of truth for how site-kit talks to Sonor from the browser.\n * Every client-side module (analytics, forms, commerce, engage, maps, images,\n * SitemapSync) routes through here instead of bare fetch(), which gives the\n * whole kit, in one place:\n *\n * - per-attempt timeout + retry with backoff (via fetchWithRetry) — a hung\n * request left to the browser's own network timeout logs a console error\n * (net::ERR_TIMED_OUT) that fails Lighthouse best-practices\n * - the x-sitekit-version header on every request, so the platform can see\n * which kit version each site actually runs from live traffic\n * - CREDENTIAL LIFECYCLE: sites on 3.2+ ship a short-lived minted token instead\n * of the raw key. This transport resolves the freshest token (refreshing a\n * stale seed transparently), and on a 401/403 for a token it refreshes once\n * and retries before giving up. A raw key (2.x kit, or the mint-failed\n * fallback) is a pure passthrough — legacy behavior is unchanged.\n * - an auth circuit breaker: after a 401/403 the credential is paused for a few\n * minutes and ONE friendly console.info is emitted — a site on a stale or\n * canceled key must not spam the API or the visitor's console. Keyed by the\n * project (from the token) so it survives token rotation.\n * - sonorBeacon for unload-time telemetry that keeps the credential in headers;\n * navigator.sendBeacon can't set headers and forced the key into the URL,\n * where server and CDN access logs capture it\n *\n * Non-idempotent endpoints (checkout, payment intents, uploads) must pass\n * { retries: 0 } — they still get the timeout, but never an automatic retry.\n */\nimport { fetchWithRetry, type FetchRetryOptions } from './fetchWithRetry'\nimport { SITE_KIT_VERSION } from './version'\nimport {\n credentialBreakerId,\n currentCredential,\n getFreshCredential,\n isSiteToken,\n isTokenMode,\n refreshSiteToken,\n} from './siteToken'\n\nexport interface SonorFetchOptions extends FetchRetryOptions {\n /** Project credential — the minted token (3.2+) or raw key. Sent as x-api-key. */\n apiKey?: string\n}\n\n/** How long a credential stays paused after an auth failure. */\nconst AUTH_BREAK_MS = 5 * 60_000\n\n// breaker id → epoch ms until which requests are paused. Module-scoped: the\n// breaker lives for the page's lifetime and never applies on the server.\nconst pausedKeys = new Map<string, number>()\nlet warnedThisPage = false\n\n/** True when a previous 401/403 has paused this credential (browser only). */\nexport function isAuthPaused(credential?: string): boolean {\n if (typeof window === 'undefined') return false\n const id = credentialBreakerId(credential)\n const until = pausedKeys.get(id)\n if (!until) return false\n if (Date.now() >= until) {\n pausedKeys.delete(id)\n return false\n }\n return true\n}\n\nfunction tripBreaker(credential?: string): void {\n pausedKeys.set(credentialBreakerId(credential), Date.now() + AUTH_BREAK_MS)\n if (!warnedThisPage) {\n warnedThisPage = true\n // info, not error: a visitor's console must stay clean (Lighthouse\n // errors-in-console), and copy never names env vars or key formats.\n console.info(\n \"[Sonor] This site couldn't authenticate with Sonor, so data features are paused for a few minutes. If this keeps happening, the site is likely running an outdated API key.\",\n )\n }\n}\n\nexport async function sonorFetch(\n url: string,\n init: RequestInit = {},\n options: SonorFetchOptions = {},\n): Promise<Response> {\n // Resolve the credential to send. In token mode this may transparently refresh\n // a stale seed before the first request; in raw-key mode it's a passthrough.\n let credential = options.apiKey\n if (credential !== undefined || isTokenMode()) {\n credential = await getFreshCredential(options.apiKey)\n }\n\n const headers = new Headers(init.headers || {})\n headers.set('x-sitekit-version', SITE_KIT_VERSION)\n if (credential && !headers.has('x-api-key')) {\n headers.set('x-api-key', credential)\n }\n\n if (isAuthPaused(credential)) {\n // Synthetic response keeps every caller's !response.ok path working\n // without a network round trip while the breaker is open.\n return new Response(null, { status: 401, statusText: 'sonor-auth-paused' })\n }\n\n let response = await fetchWithRetry(url, { ...init, headers }, options)\n\n // A token can rotate or expire mid-session. On the first auth failure, try ONE\n // refresh + retry before tripping the breaker — only for token credentials\n // (raw keys have nothing to refresh).\n if (\n (response.status === 401 || response.status === 403) &&\n typeof window !== 'undefined' &&\n isSiteToken(credential)\n ) {\n const refreshed = await refreshSiteToken()\n if (refreshed && refreshed !== credential) {\n const retryHeaders = new Headers(init.headers || {})\n retryHeaders.set('x-sitekit-version', SITE_KIT_VERSION)\n retryHeaders.set('x-api-key', refreshed)\n credential = refreshed\n response = await fetchWithRetry(url, { ...init, headers: retryHeaders }, options)\n }\n }\n\n if (\n (response.status === 401 || response.status === 403) &&\n typeof window !== 'undefined' &&\n credential\n ) {\n tripBreaker(credential)\n }\n\n return response\n}\n\n/**\n * Fire-and-forget telemetry that survives page unload.\n *\n * Uses fetch({ keepalive: true }) so auth travels in headers. Falls back to\n * navigator.sendBeacon (no auth headers possible — the server may reject it,\n * but we never put the key in the URL) only when keepalive fetch is missing.\n *\n * Cannot await a refresh at unload time, so it sends the freshest token already\n * held (currentCredential) rather than the possibly-stale seed the caller passed.\n */\nexport function sonorBeacon(url: string, payload: unknown, apiKey?: string): void {\n const credential = currentCredential(apiKey)\n const body = typeof payload === 'string' ? payload : JSON.stringify(payload)\n try {\n void fetch(url, {\n method: 'POST',\n keepalive: true,\n headers: {\n 'Content-Type': 'application/json',\n 'x-sitekit-version': SITE_KIT_VERSION,\n ...(credential ? { 'x-api-key': credential } : {}),\n },\n body,\n }).catch(() => {\n /* page is closing — best effort */\n })\n } catch {\n try {\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n navigator.sendBeacon(url, new Blob([body], { type: 'application/json' }))\n }\n } catch {\n /* nothing left to try */\n }\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useAnalyticsOptional } from './chunk-
|
|
2
|
+
import { useAnalyticsOptional } from './chunk-T2DEEKVQ.mjs';
|
|
3
|
+
import { sonorFetch } from './chunk-LZSCCJ4O.mjs';
|
|
3
4
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
5
|
import React5, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
|
|
5
6
|
|
|
@@ -101,18 +102,15 @@ function getApiKey() {
|
|
|
101
102
|
async function apiPost(endpoint, body = {}) {
|
|
102
103
|
const { apiUrl, apiKey } = getApiConfig();
|
|
103
104
|
if (!apiKey) {
|
|
104
|
-
console.
|
|
105
|
+
console.warn("[Commerce] No API key configured");
|
|
105
106
|
return null;
|
|
106
107
|
}
|
|
107
108
|
try {
|
|
108
|
-
const response = await
|
|
109
|
+
const response = await sonorFetch(`${apiUrl}${endpoint}`, {
|
|
109
110
|
method: "POST",
|
|
110
|
-
headers: {
|
|
111
|
-
"Content-Type": "application/json",
|
|
112
|
-
"x-api-key": apiKey
|
|
113
|
-
},
|
|
111
|
+
headers: { "Content-Type": "application/json" },
|
|
114
112
|
body: JSON.stringify(body)
|
|
115
|
-
});
|
|
113
|
+
}, { apiKey });
|
|
116
114
|
if (!response.ok) {
|
|
117
115
|
const text = await response.text();
|
|
118
116
|
let body2 = null;
|
|
@@ -121,12 +119,12 @@ async function apiPost(endpoint, body = {}) {
|
|
|
121
119
|
} catch {
|
|
122
120
|
body2 = text;
|
|
123
121
|
}
|
|
124
|
-
console.
|
|
122
|
+
console.warn(`[Commerce] API error:`, response.status, response.statusText || "Unknown", body2);
|
|
125
123
|
return null;
|
|
126
124
|
}
|
|
127
125
|
return await response.json();
|
|
128
126
|
} catch (error) {
|
|
129
|
-
console.
|
|
127
|
+
console.warn("[Commerce] Network error:", error);
|
|
130
128
|
return null;
|
|
131
129
|
}
|
|
132
130
|
}
|
|
@@ -266,14 +264,11 @@ async function fetchActiveProcessor() {
|
|
|
266
264
|
const { apiUrl, apiKey } = getApiConfig();
|
|
267
265
|
if (!apiKey) return null;
|
|
268
266
|
try {
|
|
269
|
-
const response = await
|
|
267
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/processor`, {
|
|
270
268
|
method: "POST",
|
|
271
|
-
headers: {
|
|
272
|
-
"Content-Type": "application/json",
|
|
273
|
-
"x-api-key": apiKey
|
|
274
|
-
},
|
|
269
|
+
headers: { "Content-Type": "application/json" },
|
|
275
270
|
body: JSON.stringify({})
|
|
276
|
-
});
|
|
271
|
+
}, { apiKey });
|
|
277
272
|
if (!response.ok) return null;
|
|
278
273
|
const data = await response.json();
|
|
279
274
|
return data?.processor || null;
|
|
@@ -285,12 +280,9 @@ async function registerForEvent(eventId, scheduleId, customer) {
|
|
|
285
280
|
const { apiUrl, apiKey } = getApiConfig();
|
|
286
281
|
const analyticsSessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_sk_sid") : null;
|
|
287
282
|
try {
|
|
288
|
-
const response = await
|
|
283
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/register`, {
|
|
289
284
|
method: "POST",
|
|
290
|
-
headers: {
|
|
291
|
-
"Content-Type": "application/json",
|
|
292
|
-
"x-api-key": apiKey
|
|
293
|
-
},
|
|
285
|
+
headers: { "Content-Type": "application/json" },
|
|
294
286
|
body: JSON.stringify({
|
|
295
287
|
offeringId: eventId,
|
|
296
288
|
scheduleId,
|
|
@@ -298,7 +290,7 @@ async function registerForEvent(eventId, scheduleId, customer) {
|
|
|
298
290
|
analyticsSessionId
|
|
299
291
|
// Pass for conversion tracking
|
|
300
292
|
})
|
|
301
|
-
});
|
|
293
|
+
}, { apiKey, retries: 0 });
|
|
302
294
|
if (!response.ok) {
|
|
303
295
|
const error = await response.json();
|
|
304
296
|
return { success: false, error: error.message || "Registration failed" };
|
|
@@ -316,14 +308,11 @@ async function registerForEvent(eventId, scheduleId, customer) {
|
|
|
316
308
|
async function validateDiscountCode(code, subtotal, offeringIds = []) {
|
|
317
309
|
const { apiUrl, apiKey } = getApiConfig();
|
|
318
310
|
try {
|
|
319
|
-
const response = await
|
|
311
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/discount/validate`, {
|
|
320
312
|
method: "POST",
|
|
321
|
-
headers: {
|
|
322
|
-
"Content-Type": "application/json",
|
|
323
|
-
"x-api-key": apiKey
|
|
324
|
-
},
|
|
313
|
+
headers: { "Content-Type": "application/json" },
|
|
325
314
|
body: JSON.stringify({ code, subtotal, offeringIds })
|
|
326
|
-
});
|
|
315
|
+
}, { apiKey });
|
|
327
316
|
if (!response.ok) {
|
|
328
317
|
const body = await response.json().catch(() => ({}));
|
|
329
318
|
return { valid: false, message: body?.message || "Invalid discount code" };
|
|
@@ -337,14 +326,11 @@ async function fetchProcessorConfig() {
|
|
|
337
326
|
const { apiUrl, apiKey } = getApiConfig();
|
|
338
327
|
if (!apiKey) return null;
|
|
339
328
|
try {
|
|
340
|
-
const response = await
|
|
329
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/processor-config`, {
|
|
341
330
|
method: "POST",
|
|
342
|
-
headers: {
|
|
343
|
-
"Content-Type": "application/json",
|
|
344
|
-
"x-api-key": apiKey
|
|
345
|
-
},
|
|
331
|
+
headers: { "Content-Type": "application/json" },
|
|
346
332
|
body: JSON.stringify({})
|
|
347
|
-
});
|
|
333
|
+
}, { apiKey });
|
|
348
334
|
if (!response.ok) return null;
|
|
349
335
|
return await response.json();
|
|
350
336
|
} catch {
|
|
@@ -356,17 +342,14 @@ async function createPaymentIntent(options) {
|
|
|
356
342
|
const apiKey = getApiKey();
|
|
357
343
|
const sessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_sk_sid") : null;
|
|
358
344
|
try {
|
|
359
|
-
const response = await
|
|
345
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/create-payment-intent`, {
|
|
360
346
|
method: "POST",
|
|
361
|
-
headers: {
|
|
362
|
-
"Content-Type": "application/json",
|
|
363
|
-
"x-api-key": apiKey
|
|
364
|
-
},
|
|
347
|
+
headers: { "Content-Type": "application/json" },
|
|
365
348
|
body: JSON.stringify({
|
|
366
349
|
...options,
|
|
367
350
|
analyticsSessionId: sessionId
|
|
368
351
|
})
|
|
369
|
-
});
|
|
352
|
+
}, { apiKey, retries: 0 });
|
|
370
353
|
const data = await response.json();
|
|
371
354
|
if (!response.ok) throw new Error(data.message || "Failed to create payment intent");
|
|
372
355
|
return data;
|
|
@@ -379,12 +362,9 @@ async function createCheckoutSession(optionsOrOfferingId, legacyOptions) {
|
|
|
379
362
|
const options = typeof optionsOrOfferingId === "string" ? { offeringId: optionsOrOfferingId, ...legacyOptions } : optionsOrOfferingId;
|
|
380
363
|
const analyticsSessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_sk_sid") : null;
|
|
381
364
|
try {
|
|
382
|
-
const response = await
|
|
365
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/checkout`, {
|
|
383
366
|
method: "POST",
|
|
384
|
-
headers: {
|
|
385
|
-
"Content-Type": "application/json",
|
|
386
|
-
"x-api-key": apiKey
|
|
387
|
-
},
|
|
367
|
+
headers: { "Content-Type": "application/json" },
|
|
388
368
|
body: JSON.stringify({
|
|
389
369
|
...options,
|
|
390
370
|
analyticsSessionId,
|
|
@@ -392,7 +372,7 @@ async function createCheckoutSession(optionsOrOfferingId, legacyOptions) {
|
|
|
392
372
|
successUrl: options.successUrl || (typeof window !== "undefined" ? window.location.href : ""),
|
|
393
373
|
cancelUrl: options.cancelUrl || (typeof window !== "undefined" ? window.location.href : "")
|
|
394
374
|
})
|
|
395
|
-
});
|
|
375
|
+
}, { apiKey, retries: 0 });
|
|
396
376
|
if (!response.ok) {
|
|
397
377
|
const text = await response.text();
|
|
398
378
|
let body = {};
|
|
@@ -402,8 +382,8 @@ async function createCheckoutSession(optionsOrOfferingId, legacyOptions) {
|
|
|
402
382
|
}
|
|
403
383
|
const errObj = body?.error && typeof body.error === "object" ? body.error : body;
|
|
404
384
|
const message = (typeof body?.message === "string" ? body.message : null) || (typeof errObj?.message === "string" ? errObj.message : null) || (typeof errObj?.detail === "string" ? errObj.detail : null) || (typeof body?.error === "string" ? body.error : null) || "Payment could not be processed. Please try again or use a different card.";
|
|
405
|
-
if (typeof console !== "undefined"
|
|
406
|
-
console.
|
|
385
|
+
if (typeof console !== "undefined") {
|
|
386
|
+
console.warn("[Commerce] Checkout failed:", response.status, message, body);
|
|
407
387
|
}
|
|
408
388
|
return { success: false, error: message };
|
|
409
389
|
}
|
|
@@ -687,7 +667,7 @@ function OfferingList({
|
|
|
687
667
|
}
|
|
688
668
|
setOfferings(data);
|
|
689
669
|
} catch (e) {
|
|
690
|
-
console.
|
|
670
|
+
console.warn("Failed to load offerings:", e);
|
|
691
671
|
setError("Failed to load items.");
|
|
692
672
|
} finally {
|
|
693
673
|
setLoading(false);
|
|
@@ -1175,7 +1155,7 @@ function ProductEmbed({
|
|
|
1175
1155
|
}
|
|
1176
1156
|
setProduct(data);
|
|
1177
1157
|
} catch (e) {
|
|
1178
|
-
console.
|
|
1158
|
+
console.warn("Failed to load product:", e);
|
|
1179
1159
|
} finally {
|
|
1180
1160
|
setLoading(false);
|
|
1181
1161
|
}
|
|
@@ -3952,7 +3932,7 @@ function ProductGrid({
|
|
|
3952
3932
|
setProducts(data);
|
|
3953
3933
|
setTotal(count);
|
|
3954
3934
|
} catch (e) {
|
|
3955
|
-
console.
|
|
3935
|
+
console.warn("Failed to load products:", e);
|
|
3956
3936
|
} finally {
|
|
3957
3937
|
setLoading(false);
|
|
3958
3938
|
}
|
|
@@ -7121,26 +7101,23 @@ function EventsWidget({
|
|
|
7121
7101
|
setLoading(true);
|
|
7122
7102
|
setError(null);
|
|
7123
7103
|
try {
|
|
7124
|
-
const response = await
|
|
7104
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/events`, {
|
|
7125
7105
|
method: "POST",
|
|
7126
|
-
headers: {
|
|
7127
|
-
"Content-Type": "application/json",
|
|
7128
|
-
"x-api-key": apiKey
|
|
7129
|
-
},
|
|
7106
|
+
headers: { "Content-Type": "application/json" },
|
|
7130
7107
|
body: JSON.stringify({
|
|
7131
7108
|
type: "event",
|
|
7132
7109
|
category,
|
|
7133
7110
|
limit: limit * 2
|
|
7134
7111
|
// Fetch extra for calendar view
|
|
7135
7112
|
})
|
|
7136
|
-
});
|
|
7113
|
+
}, { apiKey });
|
|
7137
7114
|
if (!response.ok) {
|
|
7138
7115
|
throw new Error("Failed to fetch events");
|
|
7139
7116
|
}
|
|
7140
7117
|
const data = await response.json();
|
|
7141
7118
|
setEvents(data.events || []);
|
|
7142
7119
|
} catch (err) {
|
|
7143
|
-
console.
|
|
7120
|
+
console.warn("Error loading events:", err);
|
|
7144
7121
|
setError("Unable to load events. Please try again later.");
|
|
7145
7122
|
} finally {
|
|
7146
7123
|
setLoading(false);
|
|
@@ -7759,5 +7736,5 @@ function groupEventsByOffering(events) {
|
|
|
7759
7736
|
}
|
|
7760
7737
|
|
|
7761
7738
|
export { CalendarView, CheckoutForm, EventCalendar, EventCheckout, EventEmbed, EventModal, EventTile, EventsWidget, OfferingCard, OfferingList, ProductDetail, ProductEmbed, ProductGrid, ProductPage, RegistrationForm, SizeChart, UpcomingEvents, createCheckoutSession, createPaymentIntent, fetchActiveProcessor, fetchCategories, fetchLatestOffering, fetchNextEvent, fetchOffering, fetchOfferings, fetchProcessorConfig, fetchProductBySlug, fetchProducts, fetchProductsPublic, fetchServices, fetchShippingRates, fetchUpcomingEvents, formatDate, formatDateRange, formatDateTime, formatPrice, formatTime, getOfferingUrl, getRelativeTimeUntil, getSpotsRemaining, isEventSoldOut, registerForEvent, useEventModal, validateAddress, validateDiscountCode };
|
|
7762
|
-
//# sourceMappingURL=chunk-
|
|
7763
|
-
//# sourceMappingURL=chunk-
|
|
7739
|
+
//# sourceMappingURL=chunk-EIWRPGOK.mjs.map
|
|
7740
|
+
//# sourceMappingURL=chunk-EIWRPGOK.mjs.map
|