@sonordev/site-kit 5.8.2 → 5.8.3
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/agent-manifest.json +6 -1
- package/dist/{AnalyticsProvider-4JV3OFCG.js → AnalyticsProvider-DPXR6FSV.js} +10 -10
- package/dist/{AnalyticsProvider-4JV3OFCG.js.map → AnalyticsProvider-DPXR6FSV.js.map} +1 -1
- package/dist/{AnalyticsProvider-LUEUDZZC.mjs → AnalyticsProvider-IGOD64MY.mjs} +6 -6
- package/dist/{AnalyticsProvider-LUEUDZZC.mjs.map → AnalyticsProvider-IGOD64MY.mjs.map} +1 -1
- package/dist/{BlogViewTracker-YQMTEGYZ.mjs → BlogViewTracker-Q7Y4MN4B.mjs} +5 -5
- package/dist/{BlogViewTracker-YQMTEGYZ.mjs.map → BlogViewTracker-Q7Y4MN4B.mjs.map} +1 -1
- package/dist/{BlogViewTracker-32C4SCHA.js → BlogViewTracker-S3CSRBIZ.js} +6 -6
- package/dist/{BlogViewTracker-32C4SCHA.js.map → BlogViewTracker-S3CSRBIZ.js.map} +1 -1
- package/dist/ChatWidget-76R7NOWD.js +24 -0
- package/dist/{ChatWidget-KCXQXNUF.js.map → ChatWidget-76R7NOWD.js.map} +1 -1
- package/dist/ChatWidget-G3KOUDX5.mjs +15 -0
- package/dist/{ChatWidget-IRTAMRQS.mjs.map → ChatWidget-G3KOUDX5.mjs.map} +1 -1
- package/dist/EngageWidget-HD4F2ZVE.js +21 -0
- package/dist/{EngageWidget-EUUZHQOU.js.map → EngageWidget-HD4F2ZVE.js.map} +1 -1
- package/dist/EngageWidget-UJ47PQFG.mjs +12 -0
- package/dist/{EngageWidget-7AIUJRXV.mjs.map → EngageWidget-UJ47PQFG.mjs.map} +1 -1
- package/dist/{FileField-SNI5XCHQ.js → FileField-FV6WSZMX.js} +6 -6
- package/dist/{FileField-SNI5XCHQ.js.map → FileField-FV6WSZMX.js.map} +1 -1
- package/dist/{FileField-XJYJO5HE.mjs → FileField-WNMEA3PK.mjs} +5 -5
- package/dist/{FileField-XJYJO5HE.mjs.map → FileField-WNMEA3PK.mjs.map} +1 -1
- package/dist/{FormSpotlight-S64G4CMM.js → FormSpotlight-2VRQXEFI.js} +9 -9
- package/dist/{FormSpotlight-S64G4CMM.js.map → FormSpotlight-2VRQXEFI.js.map} +1 -1
- package/dist/{FormSpotlight-BCXI4A4R.mjs → FormSpotlight-NGWEPGI4.mjs} +3 -3
- package/dist/{FormSpotlight-BCXI4A4R.mjs.map → FormSpotlight-NGWEPGI4.mjs.map} +1 -1
- package/dist/{FormStage-RHARCSPS.mjs → FormStage-7L4BBOLC.mjs} +3 -3
- package/dist/{FormStage-RHARCSPS.mjs.map → FormStage-7L4BBOLC.mjs.map} +1 -1
- package/dist/{FormStage-PX5TVY25.js → FormStage-Q3KQVFVW.js} +9 -9
- package/dist/{FormStage-PX5TVY25.js.map → FormStage-Q3KQVFVW.js.map} +1 -1
- package/dist/ManagedForm-4ZGU4R3G.js +25 -0
- package/dist/{ManagedForm-RI2TSUZD.js.map → ManagedForm-4ZGU4R3G.js.map} +1 -1
- package/dist/ManagedForm-Z7QE4KYI.mjs +16 -0
- package/dist/{ManagedForm-7IDXBQS6.mjs.map → ManagedForm-Z7QE4KYI.mjs.map} +1 -1
- package/dist/{ManagedNewsletterForm-IAGIHBNT.js → ManagedNewsletterForm-22EPZB7Z.js} +8 -8
- package/dist/{ManagedNewsletterForm-IAGIHBNT.js.map → ManagedNewsletterForm-22EPZB7Z.js.map} +1 -1
- package/dist/{ManagedNewsletterForm-UXBJ5OJB.mjs → ManagedNewsletterForm-4TVO2VL4.mjs} +7 -7
- package/dist/{ManagedNewsletterForm-UXBJ5OJB.mjs.map → ManagedNewsletterForm-4TVO2VL4.mjs.map} +1 -1
- package/dist/{SignalCore-Q2BQMPCJ.js → SignalCore-2N7UZGF3.js} +11 -11
- package/dist/{SignalCore-Q2BQMPCJ.js.map → SignalCore-2N7UZGF3.js.map} +1 -1
- package/dist/{SignalCore-37WGILFY.mjs → SignalCore-57OK3DHA.mjs} +5 -5
- package/dist/{SignalCore-37WGILFY.mjs.map → SignalCore-57OK3DHA.mjs.map} +1 -1
- package/dist/SitemapSync-GF4OKN4Z.js +18 -0
- package/dist/{SitemapSync-DWEL7HTB.js.map → SitemapSync-GF4OKN4Z.js.map} +1 -1
- package/dist/SitemapSync-WIUEYOBS.mjs +9 -0
- package/dist/{SitemapSync-YIAI7PMT.mjs.map → SitemapSync-WIUEYOBS.mjs.map} +1 -1
- package/dist/analytics/index.js +9 -9
- package/dist/analytics/index.mjs +4 -4
- package/dist/blog/index.js +18 -18
- package/dist/blog/index.mjs +4 -4
- package/dist/blog/server-ui.js +14 -14
- package/dist/blog/server-ui.mjs +2 -2
- package/dist/{chunk-EZ5DX7ED.mjs → chunk-25F2EXOC.mjs} +3 -3
- package/dist/{chunk-EZ5DX7ED.mjs.map → chunk-25F2EXOC.mjs.map} +1 -1
- package/dist/{chunk-3Y7IKQDD.js → chunk-2TS4ALOA.js} +14 -14
- package/dist/{chunk-3Y7IKQDD.js.map → chunk-2TS4ALOA.js.map} +1 -1
- package/dist/{chunk-NHX6YJ7G.mjs → chunk-3OO5EDKD.mjs} +8 -8
- package/dist/{chunk-NHX6YJ7G.mjs.map → chunk-3OO5EDKD.mjs.map} +1 -1
- package/dist/{chunk-3EXBBFXX.mjs → chunk-4C5CZJIN.mjs} +4 -4
- package/dist/{chunk-3EXBBFXX.mjs.map → chunk-4C5CZJIN.mjs.map} +1 -1
- package/dist/{chunk-7SLYI62M.mjs → chunk-4NVMAYMQ.mjs} +4 -4
- package/dist/{chunk-7SLYI62M.mjs.map → chunk-4NVMAYMQ.mjs.map} +1 -1
- package/dist/chunk-5FETEH3Y.mjs +6 -0
- package/dist/{chunk-TAPCWMBV.mjs.map → chunk-5FETEH3Y.mjs.map} +1 -1
- package/dist/{chunk-D7CF3OPZ.js → chunk-5HFD36AN.js} +5 -5
- package/dist/{chunk-D7CF3OPZ.js.map → chunk-5HFD36AN.js.map} +1 -1
- package/dist/{chunk-PXWYMOZY.js → chunk-6CCS2EGF.js} +11 -11
- package/dist/{chunk-PXWYMOZY.js.map → chunk-6CCS2EGF.js.map} +1 -1
- package/dist/chunk-7R6H3GQ4.js +8 -0
- package/dist/{chunk-TJVZEDE3.js.map → chunk-7R6H3GQ4.js.map} +1 -1
- package/dist/{chunk-U6O5NG56.js → chunk-7VZYP4K5.js} +15 -15
- package/dist/{chunk-U6O5NG56.js.map → chunk-7VZYP4K5.js.map} +1 -1
- package/dist/chunk-AJBOEV4I.mjs +453 -0
- package/dist/chunk-AJBOEV4I.mjs.map +1 -0
- package/dist/{chunk-3HGHWDCY.js → chunk-CNTDV7HM.js} +4 -4
- package/dist/{chunk-3HGHWDCY.js.map → chunk-CNTDV7HM.js.map} +1 -1
- package/dist/{chunk-QWXTQC3N.js → chunk-CY2RFEW6.js} +3 -3
- package/dist/{chunk-QWXTQC3N.js.map → chunk-CY2RFEW6.js.map} +1 -1
- package/dist/{chunk-7BI2RVQD.js → chunk-CZEIHFLW.js} +4 -4
- package/dist/{chunk-7BI2RVQD.js.map → chunk-CZEIHFLW.js.map} +1 -1
- package/dist/{chunk-NM567VXC.mjs → chunk-F2KW4OJF.mjs} +4 -4
- package/dist/{chunk-NM567VXC.mjs.map → chunk-F2KW4OJF.mjs.map} +1 -1
- package/dist/{chunk-3Z3TOPND.js → chunk-F3KA6V2Y.js} +3 -3
- package/dist/{chunk-3Z3TOPND.js.map → chunk-F3KA6V2Y.js.map} +1 -1
- package/dist/{chunk-5BZNVKNK.mjs → chunk-FD72QL42.mjs} +3 -3
- package/dist/{chunk-5BZNVKNK.mjs.map → chunk-FD72QL42.mjs.map} +1 -1
- package/dist/{chunk-U5WMGUDV.js → chunk-FTB5LAD3.js} +4 -4
- package/dist/{chunk-U5WMGUDV.js.map → chunk-FTB5LAD3.js.map} +1 -1
- package/dist/{chunk-TCVOGK6U.mjs → chunk-HBHS5VRN.mjs} +3 -3
- package/dist/{chunk-TCVOGK6U.mjs.map → chunk-HBHS5VRN.mjs.map} +1 -1
- package/dist/{chunk-4PXUMDHL.mjs → chunk-HEOLGDUX.mjs} +3 -3
- package/dist/{chunk-4PXUMDHL.mjs.map → chunk-HEOLGDUX.mjs.map} +1 -1
- package/dist/{chunk-GDH42JAS.js → chunk-I7HOMMIK.js} +15 -15
- package/dist/{chunk-GDH42JAS.js.map → chunk-I7HOMMIK.js.map} +1 -1
- package/dist/{chunk-73EBIAF3.js → chunk-IIHIRHSW.js} +18 -18
- package/dist/{chunk-73EBIAF3.js.map → chunk-IIHIRHSW.js.map} +1 -1
- package/dist/{chunk-M45AL7EA.js → chunk-LB44BNJ2.js} +2 -2
- package/dist/{chunk-M45AL7EA.js.map → chunk-LB44BNJ2.js.map} +1 -1
- package/dist/{chunk-6FTC6EYD.mjs → chunk-LGOQ65JQ.mjs} +7 -7
- package/dist/{chunk-6FTC6EYD.mjs.map → chunk-LGOQ65JQ.mjs.map} +1 -1
- package/dist/{chunk-X6NPTILR.mjs → chunk-MQS6AF5K.mjs} +3 -3
- package/dist/{chunk-X6NPTILR.mjs.map → chunk-MQS6AF5K.mjs.map} +1 -1
- package/dist/{chunk-RA4DCRMR.mjs → chunk-MWKI6ZIS.mjs} +3 -3
- package/dist/{chunk-RA4DCRMR.mjs.map → chunk-MWKI6ZIS.mjs.map} +1 -1
- package/dist/{chunk-GKVEWOYN.js → chunk-MYMZRHTC.js} +8 -8
- package/dist/{chunk-GKVEWOYN.js.map → chunk-MYMZRHTC.js.map} +1 -1
- package/dist/{chunk-LUF22UGR.js → chunk-NBT4L2D7.js} +8 -8
- package/dist/{chunk-LUF22UGR.js.map → chunk-NBT4L2D7.js.map} +1 -1
- package/dist/{chunk-SCVSPTXJ.mjs → chunk-NCDF2RK4.mjs} +3 -3
- package/dist/{chunk-SCVSPTXJ.mjs.map → chunk-NCDF2RK4.mjs.map} +1 -1
- package/dist/{chunk-ZTY4YS7Q.js → chunk-NMM27UOF.js} +3 -3
- package/dist/{chunk-ZTY4YS7Q.js.map → chunk-NMM27UOF.js.map} +1 -1
- package/dist/{chunk-ZDXY44FH.js → chunk-NR7YZQRR.js} +4 -4
- package/dist/{chunk-ZDXY44FH.js.map → chunk-NR7YZQRR.js.map} +1 -1
- package/dist/{chunk-PXK4WNSU.js → chunk-PI3FHABB.js} +10 -10
- package/dist/{chunk-PXK4WNSU.js.map → chunk-PI3FHABB.js.map} +1 -1
- package/dist/{chunk-DTWR7VRQ.js → chunk-PIEHBSCN.js} +5 -5
- package/dist/{chunk-DTWR7VRQ.js.map → chunk-PIEHBSCN.js.map} +1 -1
- package/dist/{chunk-OX2GTNMB.mjs → chunk-PIPERXI7.mjs} +3 -3
- package/dist/{chunk-OX2GTNMB.mjs.map → chunk-PIPERXI7.mjs.map} +1 -1
- package/dist/{chunk-FWFJZV52.mjs → chunk-POJZA67T.mjs} +4 -4
- package/dist/{chunk-FWFJZV52.mjs.map → chunk-POJZA67T.mjs.map} +1 -1
- package/dist/{chunk-HOJ4J4X2.mjs → chunk-PQYQHZWV.mjs} +2 -2
- package/dist/{chunk-HOJ4J4X2.mjs.map → chunk-PQYQHZWV.mjs.map} +1 -1
- package/dist/{chunk-YVQNOB3Q.mjs → chunk-QOOLMSBY.mjs} +3 -3
- package/dist/{chunk-YVQNOB3Q.mjs.map → chunk-QOOLMSBY.mjs.map} +1 -1
- package/dist/{chunk-JR2FT6T5.js → chunk-QQQAW6WY.js} +6 -6
- package/dist/{chunk-JR2FT6T5.js.map → chunk-QQQAW6WY.js.map} +1 -1
- package/dist/{chunk-SJPI34DL.mjs → chunk-QXMWNIKL.mjs} +3 -3
- package/dist/{chunk-SJPI34DL.mjs.map → chunk-QXMWNIKL.mjs.map} +1 -1
- package/dist/{chunk-AHKVOYFO.mjs → chunk-R5IPDAMM.mjs} +3 -3
- package/dist/{chunk-AHKVOYFO.mjs.map → chunk-R5IPDAMM.mjs.map} +1 -1
- package/dist/{chunk-RQOKQC7J.mjs → chunk-RFAAY3BW.mjs} +3 -3
- package/dist/{chunk-RQOKQC7J.mjs.map → chunk-RFAAY3BW.mjs.map} +1 -1
- package/dist/{chunk-QK54SZPF.mjs → chunk-ROSYCNXG.mjs} +4 -4
- package/dist/{chunk-QK54SZPF.mjs.map → chunk-ROSYCNXG.mjs.map} +1 -1
- package/dist/{chunk-OBNMSO66.js → chunk-S2Y7LVQ2.js} +14 -14
- package/dist/{chunk-OBNMSO66.js.map → chunk-S2Y7LVQ2.js.map} +1 -1
- package/dist/{chunk-ALVQOG4M.mjs → chunk-SFC3OWSE.mjs} +3 -3
- package/dist/{chunk-ALVQOG4M.mjs.map → chunk-SFC3OWSE.mjs.map} +1 -1
- package/dist/{chunk-F2ZFMPW4.js → chunk-TR3F3CLV.js} +7 -7
- package/dist/{chunk-F2ZFMPW4.js.map → chunk-TR3F3CLV.js.map} +1 -1
- package/dist/{chunk-RI25UGHE.mjs → chunk-UEUWC3PH.mjs} +3 -3
- package/dist/{chunk-RI25UGHE.mjs.map → chunk-UEUWC3PH.mjs.map} +1 -1
- package/dist/{chunk-YC2CKOX6.js → chunk-UHM3CCCC.js} +12 -12
- package/dist/{chunk-YC2CKOX6.js.map → chunk-UHM3CCCC.js.map} +1 -1
- package/dist/{chunk-AUTJQGZ2.mjs → chunk-UQY5KC64.mjs} +4 -4
- package/dist/{chunk-AUTJQGZ2.mjs.map → chunk-UQY5KC64.mjs.map} +1 -1
- package/dist/{chunk-HQ2EPU5R.js → chunk-VVBMWV4O.js} +5 -5
- package/dist/{chunk-HQ2EPU5R.js.map → chunk-VVBMWV4O.js.map} +1 -1
- package/dist/{chunk-KPWK23G7.js → chunk-W2U5SLMY.js} +3 -3
- package/dist/{chunk-KPWK23G7.js.map → chunk-W2U5SLMY.js.map} +1 -1
- package/dist/{chunk-FX232N4P.mjs → chunk-WINDP776.mjs} +4 -4
- package/dist/{chunk-FX232N4P.mjs.map → chunk-WINDP776.mjs.map} +1 -1
- package/dist/chunk-XEB77DQS.js +468 -0
- package/dist/chunk-XEB77DQS.js.map +1 -0
- package/dist/cli/index.js +3 -3
- package/dist/cli/index.mjs +1 -1
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/commerce/index.js +57 -57
- package/dist/commerce/index.mjs +5 -5
- package/dist/commerce/server.d.ts +1 -1
- package/dist/commerce/server.js +7 -7
- package/dist/commerce/server.js.map +1 -1
- package/dist/commerce/server.mjs +7 -7
- package/dist/commerce/server.mjs.map +1 -1
- package/dist/engage/index.js +10 -10
- package/dist/engage/index.mjs +7 -7
- package/dist/fleet/index.js +8 -8
- package/dist/fleet/index.mjs +4 -4
- package/dist/forms/index.js +21 -21
- package/dist/forms/index.mjs +10 -10
- package/dist/forms/server.js +10 -10
- package/dist/forms/server.mjs +8 -8
- package/dist/forms/static.js +7 -7
- package/dist/forms/static.mjs +6 -6
- package/dist/images/index.js +11 -11
- package/dist/images/index.mjs +4 -4
- package/dist/index.js +63 -63
- package/dist/index.mjs +9 -9
- package/dist/layout/client.js +8 -8
- package/dist/layout/client.mjs +7 -7
- package/dist/layout/index.js +10 -10
- package/dist/layout/index.mjs +8 -8
- package/dist/llms/client.d.ts +18 -0
- package/dist/llms/client.d.ts.map +1 -0
- package/dist/llms/client.js +66 -0
- package/dist/llms/client.js.map +1 -0
- package/dist/llms/client.mjs +5 -0
- package/dist/llms/client.mjs.map +1 -0
- package/dist/llms/index.js +58 -462
- package/dist/llms/index.js.map +1 -1
- package/dist/llms/index.mjs +3 -449
- package/dist/llms/index.mjs.map +1 -1
- package/dist/maps/index.js +5 -5
- package/dist/maps/index.mjs +3 -3
- package/dist/search/index.js +4 -4
- package/dist/search/index.mjs +3 -3
- package/dist/seo/ManagedSchema.d.ts.map +1 -1
- package/dist/seo/client.js +5 -5
- package/dist/seo/client.mjs +4 -4
- package/dist/seo/index.js +25 -17
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +17 -9
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo/server.js +5 -5
- package/dist/seo/server.mjs +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/dist/shared/build-entries.d.ts +6 -0
- package/dist/shared/build-entries.d.ts.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sync/index.js +17 -17
- package/dist/sync/index.mjs +4 -4
- package/package.json +6 -1
- package/dist/ChatWidget-IRTAMRQS.mjs +0 -15
- package/dist/ChatWidget-KCXQXNUF.js +0 -24
- package/dist/EngageWidget-7AIUJRXV.mjs +0 -12
- package/dist/EngageWidget-EUUZHQOU.js +0 -21
- package/dist/ManagedForm-7IDXBQS6.mjs +0 -16
- package/dist/ManagedForm-RI2TSUZD.js +0 -25
- package/dist/SitemapSync-DWEL7HTB.js +0 -18
- package/dist/SitemapSync-YIAI7PMT.mjs +0 -9
- package/dist/chunk-TAPCWMBV.mjs +0 -6
- package/dist/chunk-TJVZEDE3.js +0 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkI7HOMMIK_js = require('./chunk-I7HOMMIK.js');
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
|
|
@@ -40,7 +40,7 @@ function ManagedImage({
|
|
|
40
40
|
}
|
|
41
41
|
try {
|
|
42
42
|
const params = new URLSearchParams({ page_path: currentPath });
|
|
43
|
-
const res = await
|
|
43
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(
|
|
44
44
|
`${apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
|
|
45
45
|
{ headers: { "Content-Type": "application/json" } },
|
|
46
46
|
{ apiKey }
|
|
@@ -214,7 +214,7 @@ function ImagePickerModal({
|
|
|
214
214
|
const params = new URLSearchParams();
|
|
215
215
|
if (currentFolder) params.set("folder", currentFolder);
|
|
216
216
|
if (search) params.set("search", search);
|
|
217
|
-
const res = await
|
|
217
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(
|
|
218
218
|
`${config.apiUrl}/public/images/files?${params}`,
|
|
219
219
|
{ headers: { "Content-Type": "application/json" } },
|
|
220
220
|
{ apiKey: config.apiKey }
|
|
@@ -236,7 +236,7 @@ function ImagePickerModal({
|
|
|
236
236
|
const handleSelectFile = async (file) => {
|
|
237
237
|
if (!config?.apiKey || !config?.apiUrl) return;
|
|
238
238
|
try {
|
|
239
|
-
const res = await
|
|
239
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(
|
|
240
240
|
`${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,
|
|
241
241
|
{
|
|
242
242
|
method: "POST",
|
|
@@ -267,7 +267,7 @@ function ImagePickerModal({
|
|
|
267
267
|
formData.append("page_path", pagePath);
|
|
268
268
|
formData.append("folder", currentFolder || "Website/Images");
|
|
269
269
|
if (altText) formData.append("alt_text", altText);
|
|
270
|
-
const res = await
|
|
270
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(`${config.apiUrl}/public/images/upload`, {
|
|
271
271
|
method: "POST",
|
|
272
272
|
body: formData
|
|
273
273
|
}, { apiKey: config.apiKey, retries: 0, timeoutMs: 6e4 });
|
|
@@ -284,7 +284,7 @@ function ImagePickerModal({
|
|
|
284
284
|
if (!config?.apiKey || !config?.apiUrl) return;
|
|
285
285
|
try {
|
|
286
286
|
const params = new URLSearchParams({ page_path: pagePath });
|
|
287
|
-
await
|
|
287
|
+
await chunkI7HOMMIK_js.sonorFetch(
|
|
288
288
|
`${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
|
|
289
289
|
{ method: "DELETE" },
|
|
290
290
|
{ apiKey: config.apiKey, retries: 0 }
|
|
@@ -428,7 +428,7 @@ function ImagePickerModal({
|
|
|
428
428
|
async function fetchManagedImage(config, slotId, pagePath) {
|
|
429
429
|
const params = new URLSearchParams();
|
|
430
430
|
if (pagePath) params.set("page_path", pagePath);
|
|
431
|
-
const res = await
|
|
431
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(
|
|
432
432
|
`${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
|
|
433
433
|
{ headers: { "Content-Type": "application/json" } },
|
|
434
434
|
{ apiKey: config.apiKey }
|
|
@@ -443,7 +443,7 @@ async function fetchManagedImages(config, options) {
|
|
|
443
443
|
if (options?.pagePath) params.set("page_path", options.pagePath);
|
|
444
444
|
if (options?.category) params.set("category", options.category);
|
|
445
445
|
if (options?.includePlaceholders) params.set("include_placeholders", "true");
|
|
446
|
-
const res = await
|
|
446
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(
|
|
447
447
|
`${config.apiUrl}/public/images?${params}`,
|
|
448
448
|
{ headers: { "Content-Type": "application/json" } },
|
|
449
449
|
{ apiKey: config.apiKey }
|
|
@@ -457,7 +457,7 @@ async function listImageFiles(config, options) {
|
|
|
457
457
|
const params = new URLSearchParams();
|
|
458
458
|
if (options?.folder) params.set("folder", options.folder);
|
|
459
459
|
if (options?.search) params.set("search", options.search);
|
|
460
|
-
const res = await
|
|
460
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(
|
|
461
461
|
`${config.apiUrl}/public/images/files?${params}`,
|
|
462
462
|
{ headers: { "Content-Type": "application/json" } },
|
|
463
463
|
{ apiKey: config.apiKey }
|
|
@@ -474,7 +474,7 @@ async function uploadImage(config, file, options) {
|
|
|
474
474
|
if (options?.pagePath) formData.append("page_path", options.pagePath);
|
|
475
475
|
if (options?.folder) formData.append("folder", options.folder);
|
|
476
476
|
if (options?.altText) formData.append("alt_text", options.altText);
|
|
477
|
-
const res = await
|
|
477
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(`${config.apiUrl}/public/images/upload`, {
|
|
478
478
|
method: "POST",
|
|
479
479
|
body: formData
|
|
480
480
|
}, { apiKey: config.apiKey, retries: 0, timeoutMs: 6e4 });
|
|
@@ -484,7 +484,7 @@ async function uploadImage(config, file, options) {
|
|
|
484
484
|
return res.json();
|
|
485
485
|
}
|
|
486
486
|
async function assignImageToSlot(config, slotId, options) {
|
|
487
|
-
const res = await
|
|
487
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(
|
|
488
488
|
`${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,
|
|
489
489
|
{
|
|
490
490
|
method: "POST",
|
|
@@ -511,7 +511,7 @@ async function assignImageToSlot(config, slotId, options) {
|
|
|
511
511
|
async function clearImageSlot(config, slotId, pagePath) {
|
|
512
512
|
const params = new URLSearchParams();
|
|
513
513
|
if (pagePath) params.set("page_path", pagePath);
|
|
514
|
-
const res = await
|
|
514
|
+
const res = await chunkI7HOMMIK_js.sonorFetch(
|
|
515
515
|
`${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
|
|
516
516
|
{ method: "DELETE" },
|
|
517
517
|
{ apiKey: config.apiKey, retries: 0 }
|
|
@@ -529,5 +529,5 @@ exports.fetchManagedImage = fetchManagedImage;
|
|
|
529
529
|
exports.fetchManagedImages = fetchManagedImages;
|
|
530
530
|
exports.listImageFiles = listImageFiles;
|
|
531
531
|
exports.uploadImage = uploadImage;
|
|
532
|
-
//# sourceMappingURL=chunk-
|
|
533
|
-
//# sourceMappingURL=chunk-
|
|
532
|
+
//# sourceMappingURL=chunk-2TS4ALOA.js.map
|
|
533
|
+
//# sourceMappingURL=chunk-2TS4ALOA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/images/ManagedImage.tsx","../src/images/api.ts"],"names":["useState","useCallback","sonorFetch","useEffect","jsx","jsxs"],"mappings":"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","file":"chunk-3Y7IKQDD.js","sourcesContent":["/**\n * ManagedImage - Portal-managed image component\n * \n * Features:\n * - Fetches images from Portal API via API key (never direct Supabase)\n * - Dev mode: Click to open image picker modal\n * - Supports responsive variants\n * - Automatic focal point handling\n * - Placeholder state for empty slots\n * \n * @example\n * ```tsx\n * <ManagedImage \n * slotId=\"hero-background\"\n * alt=\"Hero background image\"\n * className=\"w-full h-96 object-cover\"\n * />\n * ```\n */\n\n'use client'\n\nimport React, { useState, useEffect, useCallback } from 'react'\nimport { sonorFetch } from '../shared/sonorFetch'\n\nexport interface ManagedImageData {\n id: string\n slot_id: string\n page_path: string | null\n file_id: string | null\n external_url: string | null\n alt_text: string | null\n title: string | null\n caption: string | null\n focal_point_x: number\n focal_point_y: number\n aspect_ratio: string | null\n public_url?: string\n is_placeholder: boolean\n}\n\nexport interface ImageFile {\n id: string\n filename: string\n storage_path: string\n mime_type: string\n file_size: number\n folder_path: string | null\n public_url?: string\n}\n\nexport interface ManagedImageProps {\n /** API key for Portal API */\n apiKey?: string\n /** API URL (defaults to https://api.sonor.io) */\n apiUrl?: string\n /** Unique slot identifier (e.g., 'hero-background', 'about-team-1') */\n slotId: string\n /** Page path for page-specific slots (defaults to current path) */\n pagePath?: string\n /** Fallback alt text if not set in Portal */\n alt?: string\n /** CSS class names */\n className?: string\n /** Image width */\n width?: number | string\n /** Image height */\n height?: number | string\n /** CSS object-fit property */\n objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\n /** Fallback image URL when no image assigned */\n fallback?: string\n /** Custom placeholder component */\n placeholder?: React.ReactNode\n /** Called when image loads */\n onLoad?: () => void\n /** Called on error */\n onError?: (error: Error) => void\n /** Priority loading (Next.js Image optimization) */\n priority?: boolean\n /** Additional styles */\n style?: React.CSSProperties\n /** Enable dev picker even outside dev mode */\n forceDevMode?: boolean\n}\n\n// Check if we're in dev mode. `?sonor_dev=true` opens the picker on any host.\n// (The Uptrade-era `uptrade_dev` param is gone: nothing in the workspace sent it.)\nconst isDevMode = (): boolean => {\n if (typeof window === 'undefined') return false\n return (\n process.env.NODE_ENV === 'development' ||\n window.location.hostname === 'localhost' ||\n window.location.hostname === '127.0.0.1' ||\n new URLSearchParams(window.location.search).get('sonor_dev') === 'true'\n )\n}\n\nexport function ManagedImage({\n apiKey = process.env.SONOR_API_KEY,\n apiUrl = process.env.SONOR_API_URL || 'https://api.sonor.io',\n slotId,\n pagePath,\n alt,\n className = '',\n width,\n height,\n objectFit = 'cover',\n fallback,\n placeholder,\n onLoad,\n onError,\n priority,\n style,\n forceDevMode,\n}: ManagedImageProps) {\n const [imageData, setImageData] = useState<ManagedImageData | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n const [showPicker, setShowPicker] = useState(false)\n const [devMode] = useState(() => forceDevMode || isDevMode())\n\n // Get current page path if not provided\n const currentPath = pagePath ?? (typeof window !== 'undefined' ? window.location.pathname : '/')\n\n // Fetch image data from Portal API\n const fetchImage = useCallback(async () => {\n if (!apiKey || !apiUrl) {\n setLoading(false)\n return\n }\n\n try {\n const params = new URLSearchParams({ page_path: currentPath })\n const res = await sonorFetch(\n `${apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch image: ${res.status}`)\n }\n\n const data = await res.json()\n setImageData(data.image)\n setError(null)\n } catch (err) {\n // warn, not error: a failed slot fetch must not fail the Lighthouse\n // best-practices errors-in-console audit on every page using this slot.\n console.warn('[ManagedImage] Fetch error:', err)\n setError(err instanceof Error ? err : new Error(String(err)))\n onError?.(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setLoading(false)\n }\n }, [apiKey, apiUrl, slotId, currentPath, onError])\n\n useEffect(() => {\n fetchImage()\n }, [fetchImage])\n\n // Calculate object-position from focal point\n const objectPosition = imageData\n ? `${imageData.focal_point_x}% ${imageData.focal_point_y}%`\n : '50% 50%'\n\n // Get the image URL\n const imageUrl = imageData?.public_url || imageData?.external_url || fallback\n\n // Handle click in dev mode\n const handleClick = (e: React.MouseEvent) => {\n if (devMode) {\n e.preventDefault()\n e.stopPropagation()\n setShowPicker(true)\n }\n }\n\n // Render placeholder state\n if (loading) {\n return (\n <div\n className={`bg-gray-200 animate-pulse ${className}`}\n style={{\n width: width ?? '100%',\n height: height ?? 200,\n ...style,\n }}\n />\n )\n }\n\n // No image assigned - show placeholder or dev picker hint\n if (!imageUrl) {\n if (placeholder) {\n return <>{placeholder}</>\n }\n\n return (\n <div\n onClick={handleClick}\n className={`\n bg-gray-100 border-2 border-dashed border-gray-300 \n flex items-center justify-center text-gray-400\n ${devMode ? 'cursor-pointer hover:border-blue-400 hover:text-blue-500 hover:bg-blue-50' : ''}\n ${className}\n `}\n style={{\n width: width ?? '100%',\n height: height ?? 200,\n ...style,\n }}\n title={devMode ? `Click to add image for slot: ${slotId}` : undefined}\n >\n <div className=\"text-center p-4\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n {devMode && (\n <p className=\"text-sm font-medium\">Click to add image</p>\n )}\n <p className=\"text-xs mt-1\">{slotId}</p>\n </div>\n\n {showPicker && (\n <ImagePickerModal\n slotId={slotId}\n pagePath={currentPath}\n config={{ apiKey, apiUrl }}\n onClose={() => setShowPicker(false)}\n onSelect={() => {\n setShowPicker(false)\n fetchImage()\n }}\n />\n )}\n </div>\n )\n }\n\n // Render the image\n return (\n <div className=\"relative\" style={{ width, height }}>\n <img\n src={imageUrl}\n alt={imageData?.alt_text || alt || ''}\n title={imageData?.title || undefined}\n data-managed-image=\"true\"\n data-slot-id={slotId}\n data-page-path={currentPath}\n className={className}\n style={{\n objectFit,\n objectPosition,\n width: width ?? '100%',\n height: height ?? 'auto',\n ...style,\n }}\n onLoad={onLoad}\n onError={() => onError?.(new Error('Image failed to load'))}\n loading={priority ? 'eager' : 'lazy'}\n onClick={handleClick}\n />\n\n {/* Dev mode overlay */}\n {devMode && (\n <div\n className=\"absolute inset-0 bg-black/0 hover:bg-black/30 transition-colors cursor-pointer flex items-center justify-center opacity-0 hover:opacity-100\"\n onClick={handleClick}\n >\n <div className=\"bg-white/90 px-3 py-1.5 rounded-lg shadow-lg text-sm font-medium text-gray-700\">\n Edit Image\n </div>\n </div>\n )}\n\n {showPicker && (\n <ImagePickerModal\n slotId={slotId}\n pagePath={currentPath}\n config={{ apiKey, apiUrl }}\n currentImage={imageData}\n onClose={() => setShowPicker(false)}\n onSelect={() => {\n setShowPicker(false)\n fetchImage()\n }}\n />\n )}\n </div>\n )\n}\n\n// ============================================================================\n// IMAGE PICKER MODAL\n// ============================================================================\n\ninterface ImagePickerModalProps {\n slotId: string\n pagePath: string\n config: any\n currentImage?: ManagedImageData | null\n onClose: () => void\n onSelect: () => void\n}\n\nfunction ImagePickerModal({\n slotId,\n pagePath,\n config,\n currentImage,\n onClose,\n onSelect,\n}: ImagePickerModalProps) {\n const [files, setFiles] = useState<ImageFile[]>([])\n const [folders, setFolders] = useState<string[]>([])\n const [currentFolder, setCurrentFolder] = useState<string>('')\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(true)\n const [uploading, setUploading] = useState(false)\n const [altText, setAltText] = useState(currentImage?.alt_text || '')\n\n // Fetch available files\n const fetchFiles = useCallback(async () => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n setLoading(true)\n try {\n const params = new URLSearchParams()\n if (currentFolder) params.set('folder', currentFolder)\n if (search) params.set('search', search)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/files?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (res.ok) {\n const data = await res.json()\n setFiles(data.files || [])\n setFolders(data.folders || [])\n }\n } catch (err) {\n console.warn('[ImagePicker] Fetch error:', err)\n } finally {\n setLoading(false)\n }\n }, [config?.apiKey, config?.apiUrl, currentFolder, search])\n\n useEffect(() => {\n fetchFiles()\n }, [fetchFiles])\n\n // Select an existing file\n const handleSelectFile = async (file: ImageFile) => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n try {\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n page_path: pagePath,\n file_id: file.id,\n alt_text: altText || file.filename,\n }),\n },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (res.ok) {\n onSelect()\n }\n } catch (err) {\n console.warn('[ImagePicker] Select error:', err)\n }\n }\n\n // Upload new file\n const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (!file || !config?.apiKey || !config?.apiUrl) return\n\n setUploading(true)\n try {\n const formData = new FormData()\n formData.append('file', file)\n formData.append('slot_id', slotId)\n formData.append('page_path', pagePath)\n formData.append('folder', currentFolder || 'Website/Images')\n if (altText) formData.append('alt_text', altText)\n\n // No Content-Type — the browser sets the multipart boundary. Long\n // timeout, no retry: a retried upload would duplicate the file.\n const res = await sonorFetch(`${config.apiUrl}/public/images/upload`, {\n method: 'POST',\n body: formData,\n }, { apiKey: config.apiKey, retries: 0, timeoutMs: 60000 })\n\n if (res.ok) {\n onSelect()\n }\n } catch (err) {\n console.warn('[ImagePicker] Upload error:', err)\n } finally {\n setUploading(false)\n }\n }\n\n // Clear the slot\n const handleClear = async () => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n try {\n const params = new URLSearchParams({ page_path: pagePath })\n await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { method: 'DELETE' },\n { apiKey: config.apiKey, retries: 0 },\n )\n onSelect()\n } catch (err) {\n console.warn('[ImagePicker] Clear error:', err)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-[99999] bg-black/50 flex items-center justify-center p-4\"\n onClick={onClose}\n >\n <div\n className=\"bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden\"\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-4 border-b\">\n <div>\n <h2 className=\"text-lg font-semibold\">Select Image</h2>\n <p className=\"text-sm text-gray-500\">Slot: {slotId}</p>\n </div>\n <button\n onClick={onClose}\n className=\"text-gray-400 hover:text-gray-600 p-2\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-4 overflow-y-auto\" style={{ maxHeight: 'calc(90vh - 180px)' }}>\n {/* Upload & Search */}\n <div className=\"flex gap-4 mb-4\">\n <div className=\"flex-1\">\n <input\n type=\"text\"\n placeholder=\"Search images...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"w-full px-3 py-2 border rounded-lg text-sm\"\n />\n </div>\n <label className=\"px-4 py-2 bg-blue-600 text-white rounded-lg cursor-pointer hover:bg-blue-700 text-sm font-medium flex items-center gap-2\">\n {uploading ? 'Uploading...' : 'Upload New'}\n <input\n type=\"file\"\n accept=\"image/*\"\n onChange={handleUpload}\n disabled={uploading}\n className=\"hidden\"\n />\n </label>\n {currentImage?.file_id && (\n <button\n onClick={handleClear}\n className=\"px-4 py-2 border border-red-200 text-red-600 rounded-lg hover:bg-red-50 text-sm\"\n >\n Remove\n </button>\n )}\n </div>\n\n {/* Alt text input */}\n <div className=\"mb-4\">\n <input\n type=\"text\"\n placeholder=\"Alt text for image...\"\n value={altText}\n onChange={(e) => setAltText(e.target.value)}\n className=\"w-full px-3 py-2 border rounded-lg text-sm\"\n />\n </div>\n\n {/* Folder navigation */}\n {folders.length > 0 && (\n <div className=\"flex gap-2 mb-4 flex-wrap\">\n <button\n onClick={() => setCurrentFolder('')}\n className={`px-3 py-1 text-sm rounded-full ${\n !currentFolder ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 hover:bg-gray-200'\n }`}\n >\n All\n </button>\n {folders.map((folder) => (\n <button\n key={folder}\n onClick={() => setCurrentFolder(folder)}\n className={`px-3 py-1 text-sm rounded-full ${\n currentFolder === folder ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 hover:bg-gray-200'\n }`}\n >\n {folder}\n </button>\n ))}\n </div>\n )}\n\n {/* File grid */}\n {loading ? (\n <div className=\"grid grid-cols-4 gap-4\">\n {[...Array(8)].map((_, i) => (\n <div key={i} className=\"aspect-square bg-gray-200 rounded-lg animate-pulse\" />\n ))}\n </div>\n ) : files.length === 0 ? (\n <div className=\"text-center py-12 text-gray-500\">\n <p>No images found</p>\n <p className=\"text-sm mt-1\">Upload a new image to get started</p>\n </div>\n ) : (\n <div className=\"grid grid-cols-4 gap-4\">\n {files.map((file) => (\n <button\n key={file.id}\n onClick={() => handleSelectFile(file)}\n className={`\n aspect-square rounded-lg overflow-hidden border-2 transition-all\n hover:border-blue-400 hover:shadow-lg\n ${currentImage?.file_id === file.id ? 'border-blue-500 ring-2 ring-blue-200' : 'border-gray-200'}\n `}\n >\n <img\n src={file.public_url}\n alt={file.filename}\n className=\"w-full h-full object-cover\"\n />\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"p-4 border-t bg-gray-50 flex justify-end\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-lg text-sm\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport default ManagedImage\n","/**\n * Images API functions\n * \n * All functions use Portal API with API key authentication.\n * Never makes direct Supabase calls.\n */\n\nimport type { ManagedImageData, ImageFile } from './ManagedImage'\nimport { sonorFetch } from '../shared/sonorFetch'\n\nexport interface ImageApiConfig {\n apiUrl: string\n apiKey: string\n}\n\n/**\n * Fetch a managed image for a specific slot\n */\nexport async function fetchManagedImage(\n config: ImageApiConfig,\n slotId: string,\n pagePath?: string,\n): Promise<{ image: ManagedImageData | null; is_placeholder: boolean }> {\n const params = new URLSearchParams()\n if (pagePath) params.set('page_path', pagePath)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Fetch all managed images for the project\n */\nexport async function fetchManagedImages(\n config: ImageApiConfig,\n options?: {\n pagePath?: string\n category?: string\n includePlaceholders?: boolean\n },\n): Promise<{ images: ManagedImageData[] }> {\n const params = new URLSearchParams()\n if (options?.pagePath) params.set('page_path', options.pagePath)\n if (options?.category) params.set('category', options.category)\n if (options?.includePlaceholders) params.set('include_placeholders', 'true')\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch images: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * List available image files in the project\n */\nexport async function listImageFiles(\n config: ImageApiConfig,\n options?: {\n folder?: string\n search?: string\n },\n): Promise<{ files: ImageFile[]; folders: string[] }> {\n const params = new URLSearchParams()\n if (options?.folder) params.set('folder', options.folder)\n if (options?.search) params.set('search', options.search)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/files?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to list files: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Upload a new image\n */\nexport async function uploadImage(\n config: ImageApiConfig,\n file: File,\n options?: {\n slotId?: string\n pagePath?: string\n folder?: string\n altText?: string\n },\n): Promise<{ file: ImageFile; image?: ManagedImageData }> {\n const formData = new FormData()\n formData.append('file', file)\n if (options?.slotId) formData.append('slot_id', options.slotId)\n if (options?.pagePath) formData.append('page_path', options.pagePath)\n if (options?.folder) formData.append('folder', options.folder)\n if (options?.altText) formData.append('alt_text', options.altText)\n\n // No Content-Type — the browser sets the multipart boundary. Long timeout,\n // no retry: a retried upload would duplicate the file.\n const res = await sonorFetch(`${config.apiUrl}/public/images/upload`, {\n method: 'POST',\n body: formData,\n }, { apiKey: config.apiKey, retries: 0, timeoutMs: 60000 })\n\n if (!res.ok) {\n throw new Error(`Failed to upload image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Assign an existing file to an image slot\n */\nexport async function assignImageToSlot(\n config: ImageApiConfig,\n slotId: string,\n options: {\n fileId?: string\n externalUrl?: string\n pagePath?: string\n altText?: string\n title?: string\n caption?: string\n focalPointX?: number\n focalPointY?: number\n aspectRatio?: string\n },\n): Promise<{ image: ManagedImageData }> {\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n page_path: options.pagePath,\n file_id: options.fileId,\n external_url: options.externalUrl,\n alt_text: options.altText,\n title: options.title,\n caption: options.caption,\n focal_point_x: options.focalPointX,\n focal_point_y: options.focalPointY,\n aspect_ratio: options.aspectRatio,\n }),\n },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to assign image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Clear an image from a slot (keeps the file)\n */\nexport async function clearImageSlot(\n config: ImageApiConfig,\n slotId: string,\n pagePath?: string,\n): Promise<{ success: boolean }> {\n const params = new URLSearchParams()\n if (pagePath) params.set('page_path', pagePath)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { method: 'DELETE' },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to clear slot: ${res.status}`)\n }\n\n return res.json()\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/images/ManagedImage.tsx","../src/images/api.ts"],"names":["useState","useCallback","sonorFetch","useEffect","jsx","jsxs"],"mappings":"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","file":"chunk-2TS4ALOA.js","sourcesContent":["/**\n * ManagedImage - Portal-managed image component\n * \n * Features:\n * - Fetches images from Portal API via API key (never direct Supabase)\n * - Dev mode: Click to open image picker modal\n * - Supports responsive variants\n * - Automatic focal point handling\n * - Placeholder state for empty slots\n * \n * @example\n * ```tsx\n * <ManagedImage \n * slotId=\"hero-background\"\n * alt=\"Hero background image\"\n * className=\"w-full h-96 object-cover\"\n * />\n * ```\n */\n\n'use client'\n\nimport React, { useState, useEffect, useCallback } from 'react'\nimport { sonorFetch } from '../shared/sonorFetch'\n\nexport interface ManagedImageData {\n id: string\n slot_id: string\n page_path: string | null\n file_id: string | null\n external_url: string | null\n alt_text: string | null\n title: string | null\n caption: string | null\n focal_point_x: number\n focal_point_y: number\n aspect_ratio: string | null\n public_url?: string\n is_placeholder: boolean\n}\n\nexport interface ImageFile {\n id: string\n filename: string\n storage_path: string\n mime_type: string\n file_size: number\n folder_path: string | null\n public_url?: string\n}\n\nexport interface ManagedImageProps {\n /** API key for Portal API */\n apiKey?: string\n /** API URL (defaults to https://api.sonor.io) */\n apiUrl?: string\n /** Unique slot identifier (e.g., 'hero-background', 'about-team-1') */\n slotId: string\n /** Page path for page-specific slots (defaults to current path) */\n pagePath?: string\n /** Fallback alt text if not set in Portal */\n alt?: string\n /** CSS class names */\n className?: string\n /** Image width */\n width?: number | string\n /** Image height */\n height?: number | string\n /** CSS object-fit property */\n objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\n /** Fallback image URL when no image assigned */\n fallback?: string\n /** Custom placeholder component */\n placeholder?: React.ReactNode\n /** Called when image loads */\n onLoad?: () => void\n /** Called on error */\n onError?: (error: Error) => void\n /** Priority loading (Next.js Image optimization) */\n priority?: boolean\n /** Additional styles */\n style?: React.CSSProperties\n /** Enable dev picker even outside dev mode */\n forceDevMode?: boolean\n}\n\n// Check if we're in dev mode. `?sonor_dev=true` opens the picker on any host.\n// (The Uptrade-era `uptrade_dev` param is gone: nothing in the workspace sent it.)\nconst isDevMode = (): boolean => {\n if (typeof window === 'undefined') return false\n return (\n process.env.NODE_ENV === 'development' ||\n window.location.hostname === 'localhost' ||\n window.location.hostname === '127.0.0.1' ||\n new URLSearchParams(window.location.search).get('sonor_dev') === 'true'\n )\n}\n\nexport function ManagedImage({\n apiKey = process.env.SONOR_API_KEY,\n apiUrl = process.env.SONOR_API_URL || 'https://api.sonor.io',\n slotId,\n pagePath,\n alt,\n className = '',\n width,\n height,\n objectFit = 'cover',\n fallback,\n placeholder,\n onLoad,\n onError,\n priority,\n style,\n forceDevMode,\n}: ManagedImageProps) {\n const [imageData, setImageData] = useState<ManagedImageData | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n const [showPicker, setShowPicker] = useState(false)\n const [devMode] = useState(() => forceDevMode || isDevMode())\n\n // Get current page path if not provided\n const currentPath = pagePath ?? (typeof window !== 'undefined' ? window.location.pathname : '/')\n\n // Fetch image data from Portal API\n const fetchImage = useCallback(async () => {\n if (!apiKey || !apiUrl) {\n setLoading(false)\n return\n }\n\n try {\n const params = new URLSearchParams({ page_path: currentPath })\n const res = await sonorFetch(\n `${apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch image: ${res.status}`)\n }\n\n const data = await res.json()\n setImageData(data.image)\n setError(null)\n } catch (err) {\n // warn, not error: a failed slot fetch must not fail the Lighthouse\n // best-practices errors-in-console audit on every page using this slot.\n console.warn('[ManagedImage] Fetch error:', err)\n setError(err instanceof Error ? err : new Error(String(err)))\n onError?.(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setLoading(false)\n }\n }, [apiKey, apiUrl, slotId, currentPath, onError])\n\n useEffect(() => {\n fetchImage()\n }, [fetchImage])\n\n // Calculate object-position from focal point\n const objectPosition = imageData\n ? `${imageData.focal_point_x}% ${imageData.focal_point_y}%`\n : '50% 50%'\n\n // Get the image URL\n const imageUrl = imageData?.public_url || imageData?.external_url || fallback\n\n // Handle click in dev mode\n const handleClick = (e: React.MouseEvent) => {\n if (devMode) {\n e.preventDefault()\n e.stopPropagation()\n setShowPicker(true)\n }\n }\n\n // Render placeholder state\n if (loading) {\n return (\n <div\n className={`bg-gray-200 animate-pulse ${className}`}\n style={{\n width: width ?? '100%',\n height: height ?? 200,\n ...style,\n }}\n />\n )\n }\n\n // No image assigned - show placeholder or dev picker hint\n if (!imageUrl) {\n if (placeholder) {\n return <>{placeholder}</>\n }\n\n return (\n <div\n onClick={handleClick}\n className={`\n bg-gray-100 border-2 border-dashed border-gray-300 \n flex items-center justify-center text-gray-400\n ${devMode ? 'cursor-pointer hover:border-blue-400 hover:text-blue-500 hover:bg-blue-50' : ''}\n ${className}\n `}\n style={{\n width: width ?? '100%',\n height: height ?? 200,\n ...style,\n }}\n title={devMode ? `Click to add image for slot: ${slotId}` : undefined}\n >\n <div className=\"text-center p-4\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n {devMode && (\n <p className=\"text-sm font-medium\">Click to add image</p>\n )}\n <p className=\"text-xs mt-1\">{slotId}</p>\n </div>\n\n {showPicker && (\n <ImagePickerModal\n slotId={slotId}\n pagePath={currentPath}\n config={{ apiKey, apiUrl }}\n onClose={() => setShowPicker(false)}\n onSelect={() => {\n setShowPicker(false)\n fetchImage()\n }}\n />\n )}\n </div>\n )\n }\n\n // Render the image\n return (\n <div className=\"relative\" style={{ width, height }}>\n <img\n src={imageUrl}\n alt={imageData?.alt_text || alt || ''}\n title={imageData?.title || undefined}\n data-managed-image=\"true\"\n data-slot-id={slotId}\n data-page-path={currentPath}\n className={className}\n style={{\n objectFit,\n objectPosition,\n width: width ?? '100%',\n height: height ?? 'auto',\n ...style,\n }}\n onLoad={onLoad}\n onError={() => onError?.(new Error('Image failed to load'))}\n loading={priority ? 'eager' : 'lazy'}\n onClick={handleClick}\n />\n\n {/* Dev mode overlay */}\n {devMode && (\n <div\n className=\"absolute inset-0 bg-black/0 hover:bg-black/30 transition-colors cursor-pointer flex items-center justify-center opacity-0 hover:opacity-100\"\n onClick={handleClick}\n >\n <div className=\"bg-white/90 px-3 py-1.5 rounded-lg shadow-lg text-sm font-medium text-gray-700\">\n Edit Image\n </div>\n </div>\n )}\n\n {showPicker && (\n <ImagePickerModal\n slotId={slotId}\n pagePath={currentPath}\n config={{ apiKey, apiUrl }}\n currentImage={imageData}\n onClose={() => setShowPicker(false)}\n onSelect={() => {\n setShowPicker(false)\n fetchImage()\n }}\n />\n )}\n </div>\n )\n}\n\n// ============================================================================\n// IMAGE PICKER MODAL\n// ============================================================================\n\ninterface ImagePickerModalProps {\n slotId: string\n pagePath: string\n config: any\n currentImage?: ManagedImageData | null\n onClose: () => void\n onSelect: () => void\n}\n\nfunction ImagePickerModal({\n slotId,\n pagePath,\n config,\n currentImage,\n onClose,\n onSelect,\n}: ImagePickerModalProps) {\n const [files, setFiles] = useState<ImageFile[]>([])\n const [folders, setFolders] = useState<string[]>([])\n const [currentFolder, setCurrentFolder] = useState<string>('')\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(true)\n const [uploading, setUploading] = useState(false)\n const [altText, setAltText] = useState(currentImage?.alt_text || '')\n\n // Fetch available files\n const fetchFiles = useCallback(async () => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n setLoading(true)\n try {\n const params = new URLSearchParams()\n if (currentFolder) params.set('folder', currentFolder)\n if (search) params.set('search', search)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/files?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (res.ok) {\n const data = await res.json()\n setFiles(data.files || [])\n setFolders(data.folders || [])\n }\n } catch (err) {\n console.warn('[ImagePicker] Fetch error:', err)\n } finally {\n setLoading(false)\n }\n }, [config?.apiKey, config?.apiUrl, currentFolder, search])\n\n useEffect(() => {\n fetchFiles()\n }, [fetchFiles])\n\n // Select an existing file\n const handleSelectFile = async (file: ImageFile) => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n try {\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n page_path: pagePath,\n file_id: file.id,\n alt_text: altText || file.filename,\n }),\n },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (res.ok) {\n onSelect()\n }\n } catch (err) {\n console.warn('[ImagePicker] Select error:', err)\n }\n }\n\n // Upload new file\n const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (!file || !config?.apiKey || !config?.apiUrl) return\n\n setUploading(true)\n try {\n const formData = new FormData()\n formData.append('file', file)\n formData.append('slot_id', slotId)\n formData.append('page_path', pagePath)\n formData.append('folder', currentFolder || 'Website/Images')\n if (altText) formData.append('alt_text', altText)\n\n // No Content-Type — the browser sets the multipart boundary. Long\n // timeout, no retry: a retried upload would duplicate the file.\n const res = await sonorFetch(`${config.apiUrl}/public/images/upload`, {\n method: 'POST',\n body: formData,\n }, { apiKey: config.apiKey, retries: 0, timeoutMs: 60000 })\n\n if (res.ok) {\n onSelect()\n }\n } catch (err) {\n console.warn('[ImagePicker] Upload error:', err)\n } finally {\n setUploading(false)\n }\n }\n\n // Clear the slot\n const handleClear = async () => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n try {\n const params = new URLSearchParams({ page_path: pagePath })\n await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { method: 'DELETE' },\n { apiKey: config.apiKey, retries: 0 },\n )\n onSelect()\n } catch (err) {\n console.warn('[ImagePicker] Clear error:', err)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-[99999] bg-black/50 flex items-center justify-center p-4\"\n onClick={onClose}\n >\n <div\n className=\"bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden\"\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-4 border-b\">\n <div>\n <h2 className=\"text-lg font-semibold\">Select Image</h2>\n <p className=\"text-sm text-gray-500\">Slot: {slotId}</p>\n </div>\n <button\n onClick={onClose}\n className=\"text-gray-400 hover:text-gray-600 p-2\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-4 overflow-y-auto\" style={{ maxHeight: 'calc(90vh - 180px)' }}>\n {/* Upload & Search */}\n <div className=\"flex gap-4 mb-4\">\n <div className=\"flex-1\">\n <input\n type=\"text\"\n placeholder=\"Search images...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"w-full px-3 py-2 border rounded-lg text-sm\"\n />\n </div>\n <label className=\"px-4 py-2 bg-blue-600 text-white rounded-lg cursor-pointer hover:bg-blue-700 text-sm font-medium flex items-center gap-2\">\n {uploading ? 'Uploading...' : 'Upload New'}\n <input\n type=\"file\"\n accept=\"image/*\"\n onChange={handleUpload}\n disabled={uploading}\n className=\"hidden\"\n />\n </label>\n {currentImage?.file_id && (\n <button\n onClick={handleClear}\n className=\"px-4 py-2 border border-red-200 text-red-600 rounded-lg hover:bg-red-50 text-sm\"\n >\n Remove\n </button>\n )}\n </div>\n\n {/* Alt text input */}\n <div className=\"mb-4\">\n <input\n type=\"text\"\n placeholder=\"Alt text for image...\"\n value={altText}\n onChange={(e) => setAltText(e.target.value)}\n className=\"w-full px-3 py-2 border rounded-lg text-sm\"\n />\n </div>\n\n {/* Folder navigation */}\n {folders.length > 0 && (\n <div className=\"flex gap-2 mb-4 flex-wrap\">\n <button\n onClick={() => setCurrentFolder('')}\n className={`px-3 py-1 text-sm rounded-full ${\n !currentFolder ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 hover:bg-gray-200'\n }`}\n >\n All\n </button>\n {folders.map((folder) => (\n <button\n key={folder}\n onClick={() => setCurrentFolder(folder)}\n className={`px-3 py-1 text-sm rounded-full ${\n currentFolder === folder ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 hover:bg-gray-200'\n }`}\n >\n {folder}\n </button>\n ))}\n </div>\n )}\n\n {/* File grid */}\n {loading ? (\n <div className=\"grid grid-cols-4 gap-4\">\n {[...Array(8)].map((_, i) => (\n <div key={i} className=\"aspect-square bg-gray-200 rounded-lg animate-pulse\" />\n ))}\n </div>\n ) : files.length === 0 ? (\n <div className=\"text-center py-12 text-gray-500\">\n <p>No images found</p>\n <p className=\"text-sm mt-1\">Upload a new image to get started</p>\n </div>\n ) : (\n <div className=\"grid grid-cols-4 gap-4\">\n {files.map((file) => (\n <button\n key={file.id}\n onClick={() => handleSelectFile(file)}\n className={`\n aspect-square rounded-lg overflow-hidden border-2 transition-all\n hover:border-blue-400 hover:shadow-lg\n ${currentImage?.file_id === file.id ? 'border-blue-500 ring-2 ring-blue-200' : 'border-gray-200'}\n `}\n >\n <img\n src={file.public_url}\n alt={file.filename}\n className=\"w-full h-full object-cover\"\n />\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"p-4 border-t bg-gray-50 flex justify-end\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-lg text-sm\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport default ManagedImage\n","/**\n * Images API functions\n * \n * All functions use Portal API with API key authentication.\n * Never makes direct Supabase calls.\n */\n\nimport type { ManagedImageData, ImageFile } from './ManagedImage'\nimport { sonorFetch } from '../shared/sonorFetch'\n\nexport interface ImageApiConfig {\n apiUrl: string\n apiKey: string\n}\n\n/**\n * Fetch a managed image for a specific slot\n */\nexport async function fetchManagedImage(\n config: ImageApiConfig,\n slotId: string,\n pagePath?: string,\n): Promise<{ image: ManagedImageData | null; is_placeholder: boolean }> {\n const params = new URLSearchParams()\n if (pagePath) params.set('page_path', pagePath)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Fetch all managed images for the project\n */\nexport async function fetchManagedImages(\n config: ImageApiConfig,\n options?: {\n pagePath?: string\n category?: string\n includePlaceholders?: boolean\n },\n): Promise<{ images: ManagedImageData[] }> {\n const params = new URLSearchParams()\n if (options?.pagePath) params.set('page_path', options.pagePath)\n if (options?.category) params.set('category', options.category)\n if (options?.includePlaceholders) params.set('include_placeholders', 'true')\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch images: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * List available image files in the project\n */\nexport async function listImageFiles(\n config: ImageApiConfig,\n options?: {\n folder?: string\n search?: string\n },\n): Promise<{ files: ImageFile[]; folders: string[] }> {\n const params = new URLSearchParams()\n if (options?.folder) params.set('folder', options.folder)\n if (options?.search) params.set('search', options.search)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/files?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to list files: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Upload a new image\n */\nexport async function uploadImage(\n config: ImageApiConfig,\n file: File,\n options?: {\n slotId?: string\n pagePath?: string\n folder?: string\n altText?: string\n },\n): Promise<{ file: ImageFile; image?: ManagedImageData }> {\n const formData = new FormData()\n formData.append('file', file)\n if (options?.slotId) formData.append('slot_id', options.slotId)\n if (options?.pagePath) formData.append('page_path', options.pagePath)\n if (options?.folder) formData.append('folder', options.folder)\n if (options?.altText) formData.append('alt_text', options.altText)\n\n // No Content-Type — the browser sets the multipart boundary. Long timeout,\n // no retry: a retried upload would duplicate the file.\n const res = await sonorFetch(`${config.apiUrl}/public/images/upload`, {\n method: 'POST',\n body: formData,\n }, { apiKey: config.apiKey, retries: 0, timeoutMs: 60000 })\n\n if (!res.ok) {\n throw new Error(`Failed to upload image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Assign an existing file to an image slot\n */\nexport async function assignImageToSlot(\n config: ImageApiConfig,\n slotId: string,\n options: {\n fileId?: string\n externalUrl?: string\n pagePath?: string\n altText?: string\n title?: string\n caption?: string\n focalPointX?: number\n focalPointY?: number\n aspectRatio?: string\n },\n): Promise<{ image: ManagedImageData }> {\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n page_path: options.pagePath,\n file_id: options.fileId,\n external_url: options.externalUrl,\n alt_text: options.altText,\n title: options.title,\n caption: options.caption,\n focal_point_x: options.focalPointX,\n focal_point_y: options.focalPointY,\n aspect_ratio: options.aspectRatio,\n }),\n },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to assign image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Clear an image from a slot (keeps the file)\n */\nexport async function clearImageSlot(\n config: ImageApiConfig,\n slotId: string,\n pagePath?: string,\n): Promise<{ success: boolean }> {\n const params = new URLSearchParams()\n if (pagePath) params.set('page_path', pagePath)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { method: 'DELETE' },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to clear slot: ${res.status}`)\n }\n\n return res.json()\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { publishSiteCredential } from './chunk-
|
|
3
|
-
import { FleetHeartbeat } from './chunk-
|
|
2
|
+
import { publishSiteCredential } from './chunk-SFC3OWSE.mjs';
|
|
3
|
+
import { FleetHeartbeat } from './chunk-WINDP776.mjs';
|
|
4
4
|
import { useDeferredActivation } from './chunk-ZVBLXXNJ.mjs';
|
|
5
|
-
import { SignalBridge } from './chunk-
|
|
5
|
+
import { SignalBridge } from './chunk-FD72QL42.mjs';
|
|
6
6
|
import { resolveSiteHost } from './chunk-JLVCWC6A.mjs';
|
|
7
7
|
import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-ZZQAGCSI.mjs';
|
|
8
8
|
import React, { useState, useRef, useCallback, Suspense } from 'react';
|
|
@@ -10,15 +10,15 @@ import dynamic from 'next/dynamic';
|
|
|
10
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
11
11
|
|
|
12
12
|
var LazyAnalyticsProvider = dynamic(
|
|
13
|
-
() => import('./AnalyticsProvider-
|
|
13
|
+
() => import('./AnalyticsProvider-IGOD64MY.mjs').then((m) => ({ default: m.AnalyticsProvider })),
|
|
14
14
|
{ ssr: false }
|
|
15
15
|
);
|
|
16
16
|
var LazyEngageWidget = dynamic(
|
|
17
|
-
() => import('./EngageWidget-
|
|
17
|
+
() => import('./EngageWidget-UJ47PQFG.mjs').then((m) => ({ default: m.EngageWidget })),
|
|
18
18
|
{ ssr: false }
|
|
19
19
|
);
|
|
20
20
|
var LazySitemapSync = dynamic(
|
|
21
|
-
() => import('./SitemapSync-
|
|
21
|
+
() => import('./SitemapSync-WIUEYOBS.mjs').then((m) => ({ default: m.SitemapSync })),
|
|
22
22
|
{ ssr: false }
|
|
23
23
|
);
|
|
24
24
|
function SiteKitClientProviders({
|
|
@@ -148,5 +148,5 @@ function SiteKitClientProviders({
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
export { SiteKitClientProviders };
|
|
151
|
-
//# sourceMappingURL=chunk-
|
|
152
|
-
//# sourceMappingURL=chunk-
|
|
151
|
+
//# sourceMappingURL=chunk-3OO5EDKD.mjs.map
|
|
152
|
+
//# sourceMappingURL=chunk-3OO5EDKD.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/layout/SiteKitClientProviders.tsx"],"names":[],"mappings":"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","file":"chunk-NHX6YJ7G.mjs","sourcesContent":["'use client'\n\n/**\n * SiteKitClientProviders — Client Island\n *\n * This is the 'use client' boundary for SiteKitLayout.\n * It composes the client-only providers (Analytics, Engage, Signal, SitemapSync)\n * that require React context or browser APIs.\n *\n * All modules are lazy-loaded via next/dynamic so their JS is only downloaded\n * when the feature is enabled — keeping the initial bundle lightweight.\n *\n * All modules share a unified identity (visitor ID + session ID) read from\n * the storage-backed singleton (shared/identity), ensuring consistent\n * tracking across Analytics, Signal, and Engage.\n *\n * 4.0 INVARIANT — CHILDREN ARE NEVER WRAPPED. Every module here renders as a\n * childless sibling AFTER {children}; nothing provides context around page\n * content. That makes the prerender-bailout / remount-flash class of bug\n * structurally impossible. Do not reintroduce a wrapper.\n *\n * Props are passed down from the server-side SiteKitLayout component,\n * which reads env vars at render time.\n */\n\nimport React, { Suspense, useCallback, useRef, useState, type ReactNode } from 'react'\nimport dynamic from 'next/dynamic'\nimport {\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\n// Defer non-critical module mounting until the page is quiet: the lazy\n// modules below are dynamic(ssr:false) and never render on the server, but\n// rendering them during hydration still kicks off their chunk downloads +\n// mount effects inside the critical startup window. useDeferredActivation\n// holds them until window.load + idle or first interaction — the same\n// strategy as the hand-rolled per-site deferrals this replaces (upforge\n// `deferred-analytics.tsx`, TPS `DeferredAnalytics.tsx`). The hook is public\n// (`@sonordev/site-kit/client`) so sites can reuse it for their own scripts.\nimport { useDeferredActivation } from '../shared/defer'\n// Single source of truth for seeding the token manager + the __SITE_KIT_*\n// globals — shared with the public `SiteKitCredential` component that\n// non-core layouts (agency-site-kit) use. Do not re-inline it here.\nimport { publishSiteCredential, resolveSiteHost } from '../shared/publishCredential'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\n// Lazy-load feature modules — JS only downloaded when feature is enabled\nconst LazyAnalyticsProvider = dynamic(\n () => import('../analytics/AnalyticsProvider').then(m => ({ default: m.AnalyticsProvider })),\n { ssr: false },\n)\nconst LazyEngageWidget = dynamic(\n () => import('../engage/EngageWidget').then(m => ({ default: m.EngageWidget })),\n { ssr: false },\n)\nconst LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n// SignalBridge is imported STATICALLY, not via dynamic(ssr:false): it is a\n// tiny SSR-safe context shell that renders children immediately and\n// lazy-loads its machinery (SignalCore) as a childless sibling internally.\n// Wrapping children in a dynamic(ssr:false) component was the old SSR-bailout\n// failure mode — do not reintroduce it.\nimport { SignalBridge } from '../signal/SignalBridge'\n// Fleet heartbeat: a deferred, CHILDLESS SIBLING (like Analytics/Engage) that\n// reports this site's kit version + active modules once per session, so the\n// platform can see version drift across the fleet. Tiny and SSR-safe — renders\n// null until the shared idle gate fires; never wraps page content.\nimport { FleetHeartbeat } from '../fleet/FleetHeartbeat'\nimport type { FleetModule } from '../fleet/contract'\n\nexport interface SiteKitClientProvidersProps {\n children: ReactNode\n apiKey: string\n apiUrl: string\n projectId?: string\n analytics?: boolean | AnalyticsConfig\n engage?: boolean | EngageConfig\n signal?: boolean | SignalConfig\n /**\n * Runtime SitemapSync from the visitor's browser. Default FALSE — sitemap\n * registration belongs to build time and to sonor-api's nightly reconciler,\n * not to whoever happens to load the page. See SiteKitLayout for the full\n * reasoning; in short, its guards live in session/localStorage, so every new\n * visitor missed them and re-POSTed the whole sitemap.\n */\n sitemapSync?: boolean\n /**\n * Fleet heartbeat — reports kit version + active modules to Sonor once per\n * session so the platform can track version drift and key state across every\n * site. Default true. Deferred exactly like Analytics; never in the hydration\n * path, carries no visitor data.\n */\n fleet?: boolean\n /**\n * Defer Analytics / Engage / SitemapSync until window load + idle or first\n * interaction (default true). Pass false to restore legacy eager mounting\n * on hydration. SignalBridge is never deferred — it must apply experiment\n * variants as early as possible.\n */\n defer?: boolean\n debug?: boolean\n /** Browser-safe Google Maps key, resolved server-side by SiteKitLayout. */\n mapsBrowserKey?: string\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = false,\n fleet = true,\n defer = true,\n debug = false,\n mapsBrowserKey,\n}: SiteKitClientProvidersProps) {\n // One shared activation gate for all deferred siblings, so they mount in a\n // single commit instead of staggered re-renders.\n const modulesReady = useDeferredActivation(defer)\n // Hoist analytics config so the `site` dimension is resolvable up here.\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n\n // Resolve the sub-site identifier — the dimension that lets one Sonor project\n // host many sites (e.g. truepowersystems.com + ohiopowerstudies.com under one\n // TPS project). Precedence lives in resolveSiteHost (shared contract):\n // explicit `analytics.site` > NEXT_PUBLIC_SITE_URL host > window.location.host.\n // Needed as a local too — SignalBridge and the analytics config read it below.\n const site = resolveSiteHost(analyticsConfig.site)\n\n // Seed the token manager + publish the window globals modules read from.\n // No-op on the server; runs during render so it lands before child effects.\n publishSiteCredential({ apiKey, apiUrl, site, debug, mapsBrowserKey })\n\n // Unified identity — single source of truth for all modules\n const [visitorId] = useState(() => getOrCreateVisitorId())\n const [sessionId] = useState(() => getOrCreateSessionId())\n\n // Page metadata bridge: Analytics writes, Signal reads\n const pageMetadataRef = useRef<Record<string, unknown> | null>(null)\n const onPageMetadata = useCallback((metadata: Record<string, unknown>) => {\n pageMetadataRef.current = metadata\n }, [])\n\n // Children render FIRST and are never re-parented. Siblings accumulate after.\n const siblings: ReactNode[] = []\n\n // SignalBridge — childless sibling (4.0: useSignal reads the module store,\n // so it no longer needs to wrap anything). Not gated on modulesReady:\n // experiment variants must apply as early as possible.\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n siblings.push(\n <SignalBridge\n key=\"sk-signal\"\n enabled\n realtime={signalConfig.realtime !== false}\n experiments={signalConfig.experiments !== false}\n behaviorTracking={signalConfig.behaviorTracking !== false}\n visitorId={visitorId}\n sessionId={sessionId}\n pageMetadataRef={pageMetadataRef}\n />,\n )\n }\n\n // Add Analytics if enabled (renders alongside, doesn't wrap).\n //\n // CRITICAL: LazyAnalyticsProvider is dynamic(..., { ssr: false }). Wrapping\n // {content} inside an ssr:false component makes the entire page tree skip\n // server rendering — the route de-opts to 100% client rendering and the\n // hero / LCP element only paints after hydration (mobile LCP ~4s, Lighthouse\n // ~85). Analytics tracks via effects + a metadata ref, so it never needs to\n // wrap page content — mount it as a childless sibling, exactly like Engage.\n // Each deferred sibling is appended as `{modulesReady && <Module/>}` so the\n // children slot never moves in the tree — flipping ready only mounts the\n // sibling, it never remounts page content.\n if (analytics) {\n siblings.push(\n <React.Fragment key=\"sk-analytics\">\n {modulesReady && (\n <Suspense fallback={null}>\n <LazyAnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n sessionTimeout={analyticsConfig.sessionDuration}\n excludePaths={analyticsConfig.excludePaths}\n // Off by default: a cross-origin embed of this site reports\n // nothing (see analytics/send-gate.ts). Opt in per site.\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n />\n </Suspense>\n )}\n </React.Fragment>,\n )\n }\n\n // Engage widget — childless sibling\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n siblings.push(\n <React.Fragment key=\"sk-engage\">\n {modulesReady && (\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n position={engageConfig.position || 'bottom-right'}\n offsetBottom={engageConfig.offsetBottom}\n zIndex={engageConfig.zIndex}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n )}\n </React.Fragment>,\n )\n }\n\n // SitemapSync — childless sibling\n if (sitemapSync) {\n siblings.push(\n <React.Fragment key=\"sk-sitemap\">\n {modulesReady && (\n <LazySitemapSync\n debug={debug}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n />\n )}\n </React.Fragment>,\n )\n }\n\n // Fleet heartbeat — childless sibling on the same modulesReady idle gate.\n // Reports the modules actually enabled on THIS layout (honest client-observable\n // set) so the platform can answer \"which version / modules is each site\n // running\". defer={false}: the modulesReady gate already handled deferral, so\n // the heartbeat fires on mount (still bounded to once per session internally).\n if (fleet) {\n const activeModules: FleetModule[] = []\n if (analytics) activeModules.push('analytics')\n if (engage) activeModules.push('engage')\n if (signal) activeModules.push('signal')\n if (sitemapSync) activeModules.push('sitemapSync')\n siblings.push(\n <React.Fragment key=\"sk-fleet\">\n {modulesReady && (\n <FleetHeartbeat\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n modules={activeModules}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n defer={false}\n debug={debug}\n />\n )}\n </React.Fragment>,\n )\n }\n\n return (\n <>\n {children}\n {siblings}\n </>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/layout/SiteKitClientProviders.tsx"],"names":[],"mappings":"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","file":"chunk-3OO5EDKD.mjs","sourcesContent":["'use client'\n\n/**\n * SiteKitClientProviders — Client Island\n *\n * This is the 'use client' boundary for SiteKitLayout.\n * It composes the client-only providers (Analytics, Engage, Signal, SitemapSync)\n * that require React context or browser APIs.\n *\n * All modules are lazy-loaded via next/dynamic so their JS is only downloaded\n * when the feature is enabled — keeping the initial bundle lightweight.\n *\n * All modules share a unified identity (visitor ID + session ID) read from\n * the storage-backed singleton (shared/identity), ensuring consistent\n * tracking across Analytics, Signal, and Engage.\n *\n * 4.0 INVARIANT — CHILDREN ARE NEVER WRAPPED. Every module here renders as a\n * childless sibling AFTER {children}; nothing provides context around page\n * content. That makes the prerender-bailout / remount-flash class of bug\n * structurally impossible. Do not reintroduce a wrapper.\n *\n * Props are passed down from the server-side SiteKitLayout component,\n * which reads env vars at render time.\n */\n\nimport React, { Suspense, useCallback, useRef, useState, type ReactNode } from 'react'\nimport dynamic from 'next/dynamic'\nimport {\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\n// Defer non-critical module mounting until the page is quiet: the lazy\n// modules below are dynamic(ssr:false) and never render on the server, but\n// rendering them during hydration still kicks off their chunk downloads +\n// mount effects inside the critical startup window. useDeferredActivation\n// holds them until window.load + idle or first interaction — the same\n// strategy as the hand-rolled per-site deferrals this replaces (upforge\n// `deferred-analytics.tsx`, TPS `DeferredAnalytics.tsx`). The hook is public\n// (`@sonordev/site-kit/client`) so sites can reuse it for their own scripts.\nimport { useDeferredActivation } from '../shared/defer'\n// Single source of truth for seeding the token manager + the __SITE_KIT_*\n// globals — shared with the public `SiteKitCredential` component that\n// non-core layouts (agency-site-kit) use. Do not re-inline it here.\nimport { publishSiteCredential, resolveSiteHost } from '../shared/publishCredential'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\n// Lazy-load feature modules — JS only downloaded when feature is enabled\nconst LazyAnalyticsProvider = dynamic(\n () => import('../analytics/AnalyticsProvider').then(m => ({ default: m.AnalyticsProvider })),\n { ssr: false },\n)\nconst LazyEngageWidget = dynamic(\n () => import('../engage/EngageWidget').then(m => ({ default: m.EngageWidget })),\n { ssr: false },\n)\nconst LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n// SignalBridge is imported STATICALLY, not via dynamic(ssr:false): it is a\n// tiny SSR-safe context shell that renders children immediately and\n// lazy-loads its machinery (SignalCore) as a childless sibling internally.\n// Wrapping children in a dynamic(ssr:false) component was the old SSR-bailout\n// failure mode — do not reintroduce it.\nimport { SignalBridge } from '../signal/SignalBridge'\n// Fleet heartbeat: a deferred, CHILDLESS SIBLING (like Analytics/Engage) that\n// reports this site's kit version + active modules once per session, so the\n// platform can see version drift across the fleet. Tiny and SSR-safe — renders\n// null until the shared idle gate fires; never wraps page content.\nimport { FleetHeartbeat } from '../fleet/FleetHeartbeat'\nimport type { FleetModule } from '../fleet/contract'\n\nexport interface SiteKitClientProvidersProps {\n children: ReactNode\n apiKey: string\n apiUrl: string\n projectId?: string\n analytics?: boolean | AnalyticsConfig\n engage?: boolean | EngageConfig\n signal?: boolean | SignalConfig\n /**\n * Runtime SitemapSync from the visitor's browser. Default FALSE — sitemap\n * registration belongs to build time and to sonor-api's nightly reconciler,\n * not to whoever happens to load the page. See SiteKitLayout for the full\n * reasoning; in short, its guards live in session/localStorage, so every new\n * visitor missed them and re-POSTed the whole sitemap.\n */\n sitemapSync?: boolean\n /**\n * Fleet heartbeat — reports kit version + active modules to Sonor once per\n * session so the platform can track version drift and key state across every\n * site. Default true. Deferred exactly like Analytics; never in the hydration\n * path, carries no visitor data.\n */\n fleet?: boolean\n /**\n * Defer Analytics / Engage / SitemapSync until window load + idle or first\n * interaction (default true). Pass false to restore legacy eager mounting\n * on hydration. SignalBridge is never deferred — it must apply experiment\n * variants as early as possible.\n */\n defer?: boolean\n debug?: boolean\n /** Browser-safe Google Maps key, resolved server-side by SiteKitLayout. */\n mapsBrowserKey?: string\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = false,\n fleet = true,\n defer = true,\n debug = false,\n mapsBrowserKey,\n}: SiteKitClientProvidersProps) {\n // One shared activation gate for all deferred siblings, so they mount in a\n // single commit instead of staggered re-renders.\n const modulesReady = useDeferredActivation(defer)\n // Hoist analytics config so the `site` dimension is resolvable up here.\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n\n // Resolve the sub-site identifier — the dimension that lets one Sonor project\n // host many sites (e.g. truepowersystems.com + ohiopowerstudies.com under one\n // TPS project). Precedence lives in resolveSiteHost (shared contract):\n // explicit `analytics.site` > NEXT_PUBLIC_SITE_URL host > window.location.host.\n // Needed as a local too — SignalBridge and the analytics config read it below.\n const site = resolveSiteHost(analyticsConfig.site)\n\n // Seed the token manager + publish the window globals modules read from.\n // No-op on the server; runs during render so it lands before child effects.\n publishSiteCredential({ apiKey, apiUrl, site, debug, mapsBrowserKey })\n\n // Unified identity — single source of truth for all modules\n const [visitorId] = useState(() => getOrCreateVisitorId())\n const [sessionId] = useState(() => getOrCreateSessionId())\n\n // Page metadata bridge: Analytics writes, Signal reads\n const pageMetadataRef = useRef<Record<string, unknown> | null>(null)\n const onPageMetadata = useCallback((metadata: Record<string, unknown>) => {\n pageMetadataRef.current = metadata\n }, [])\n\n // Children render FIRST and are never re-parented. Siblings accumulate after.\n const siblings: ReactNode[] = []\n\n // SignalBridge — childless sibling (4.0: useSignal reads the module store,\n // so it no longer needs to wrap anything). Not gated on modulesReady:\n // experiment variants must apply as early as possible.\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n siblings.push(\n <SignalBridge\n key=\"sk-signal\"\n enabled\n realtime={signalConfig.realtime !== false}\n experiments={signalConfig.experiments !== false}\n behaviorTracking={signalConfig.behaviorTracking !== false}\n visitorId={visitorId}\n sessionId={sessionId}\n pageMetadataRef={pageMetadataRef}\n />,\n )\n }\n\n // Add Analytics if enabled (renders alongside, doesn't wrap).\n //\n // CRITICAL: LazyAnalyticsProvider is dynamic(..., { ssr: false }). Wrapping\n // {content} inside an ssr:false component makes the entire page tree skip\n // server rendering — the route de-opts to 100% client rendering and the\n // hero / LCP element only paints after hydration (mobile LCP ~4s, Lighthouse\n // ~85). Analytics tracks via effects + a metadata ref, so it never needs to\n // wrap page content — mount it as a childless sibling, exactly like Engage.\n // Each deferred sibling is appended as `{modulesReady && <Module/>}` so the\n // children slot never moves in the tree — flipping ready only mounts the\n // sibling, it never remounts page content.\n if (analytics) {\n siblings.push(\n <React.Fragment key=\"sk-analytics\">\n {modulesReady && (\n <Suspense fallback={null}>\n <LazyAnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n sessionTimeout={analyticsConfig.sessionDuration}\n excludePaths={analyticsConfig.excludePaths}\n // Off by default: a cross-origin embed of this site reports\n // nothing (see analytics/send-gate.ts). Opt in per site.\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n />\n </Suspense>\n )}\n </React.Fragment>,\n )\n }\n\n // Engage widget — childless sibling\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n siblings.push(\n <React.Fragment key=\"sk-engage\">\n {modulesReady && (\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n position={engageConfig.position || 'bottom-right'}\n offsetBottom={engageConfig.offsetBottom}\n zIndex={engageConfig.zIndex}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n )}\n </React.Fragment>,\n )\n }\n\n // SitemapSync — childless sibling\n if (sitemapSync) {\n siblings.push(\n <React.Fragment key=\"sk-sitemap\">\n {modulesReady && (\n <LazySitemapSync\n debug={debug}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n />\n )}\n </React.Fragment>,\n )\n }\n\n // Fleet heartbeat — childless sibling on the same modulesReady idle gate.\n // Reports the modules actually enabled on THIS layout (honest client-observable\n // set) so the platform can answer \"which version / modules is each site\n // running\". defer={false}: the modulesReady gate already handled deferral, so\n // the heartbeat fires on mount (still bounded to once per session internally).\n if (fleet) {\n const activeModules: FleetModule[] = []\n if (analytics) activeModules.push('analytics')\n if (engage) activeModules.push('engage')\n if (signal) activeModules.push('signal')\n if (sitemapSync) activeModules.push('sitemapSync')\n siblings.push(\n <React.Fragment key=\"sk-fleet\">\n {modulesReady && (\n <FleetHeartbeat\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n modules={activeModules}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n defer={false}\n debug={debug}\n />\n )}\n </React.Fragment>,\n )\n }\n\n return (\n <>\n {children}\n {siblings}\n </>\n )\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isTokenMode, getFreshCredential, isSiteToken, refreshSiteToken, currentCredential, credentialBreakerId } from './chunk-
|
|
2
|
-
import { SITE_KIT_VERSION } from './chunk-
|
|
1
|
+
import { isTokenMode, getFreshCredential, isSiteToken, refreshSiteToken, currentCredential, credentialBreakerId } from './chunk-NCDF2RK4.mjs';
|
|
2
|
+
import { SITE_KIT_VERSION } from './chunk-5FETEH3Y.mjs';
|
|
3
3
|
|
|
4
4
|
// src/shared/fetchWithRetry.ts
|
|
5
5
|
function backoffDelay(attempt, response) {
|
|
@@ -127,5 +127,5 @@ function sonorBeacon(url, payload, apiKey) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
export { sonorBeacon, sonorFetch };
|
|
130
|
-
//# sourceMappingURL=chunk-
|
|
131
|
-
//# sourceMappingURL=chunk-
|
|
130
|
+
//# sourceMappingURL=chunk-4C5CZJIN.mjs.map
|
|
131
|
+
//# sourceMappingURL=chunk-4C5CZJIN.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/fetchWithRetry.ts","../src/shared/sonorFetch.ts"],"names":[],"mappings":"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","file":"chunk-3EXBBFXX.mjs","sourcesContent":["/**\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. Shared on window for\n// the same reason as the token state (see siteToken.ts): duplicated module\n// copies must trip and observe ONE breaker, not one each. Never applies on the\n// server, so a per-module Map there is fine.\nconst BREAKER_STATE_KEY = '__SONOR_AUTH_BREAKER__'\nconst pausedKeys: Map<string, number> = (() => {\n if (typeof window === 'undefined') return new Map()\n const w = window as unknown as Record<string, Map<string, number> | undefined>\n return (w[BREAKER_STATE_KEY] ??= new Map())\n})()\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) {\n if (isTokenMode()) {\n // Token mode: `credential` is the freshest token (refreshed just above if\n // the seed was stale). It MUST override any x-api-key a caller hand-set — a\n // stale build-time seed passed as a header would otherwise pin the request\n // and defeat refresh entirely. Also drop a caller-set Authorization:\n // extractApiKey() server-side prefers `Authorization: Bearer` over\n // x-api-key, so a stale Bearer seed would win even once we set a fresh\n // x-api-key. This is the single place the client credential is chosen — do\n // not re-attach it as a header at call sites.\n headers.set('x-api-key', credential)\n headers.delete('authorization')\n } else if (!headers.has('x-api-key')) {\n // Raw-key mode: legacy passthrough — respect a caller-supplied header.\n headers.set('x-api-key', credential)\n }\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 // Same reason as the initial request: a caller-set stale Bearer would win\n // over our fresh x-api-key server-side, so strip it on the retry too.\n retryHeaders.delete('authorization')\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
|
+
{"version":3,"sources":["../src/shared/fetchWithRetry.ts","../src/shared/sonorFetch.ts"],"names":[],"mappings":"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","file":"chunk-4C5CZJIN.mjs","sourcesContent":["/**\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. Shared on window for\n// the same reason as the token state (see siteToken.ts): duplicated module\n// copies must trip and observe ONE breaker, not one each. Never applies on the\n// server, so a per-module Map there is fine.\nconst BREAKER_STATE_KEY = '__SONOR_AUTH_BREAKER__'\nconst pausedKeys: Map<string, number> = (() => {\n if (typeof window === 'undefined') return new Map()\n const w = window as unknown as Record<string, Map<string, number> | undefined>\n return (w[BREAKER_STATE_KEY] ??= new Map())\n})()\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) {\n if (isTokenMode()) {\n // Token mode: `credential` is the freshest token (refreshed just above if\n // the seed was stale). It MUST override any x-api-key a caller hand-set — a\n // stale build-time seed passed as a header would otherwise pin the request\n // and defeat refresh entirely. Also drop a caller-set Authorization:\n // extractApiKey() server-side prefers `Authorization: Bearer` over\n // x-api-key, so a stale Bearer seed would win even once we set a fresh\n // x-api-key. This is the single place the client credential is chosen — do\n // not re-attach it as a header at call sites.\n headers.set('x-api-key', credential)\n headers.delete('authorization')\n } else if (!headers.has('x-api-key')) {\n // Raw-key mode: legacy passthrough — respect a caller-supplied header.\n headers.set('x-api-key', credential)\n }\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 // Same reason as the initial request: a caller-set stale Bearer would win\n // over our fresh x-api-key server-side, so strip it on the retry too.\n retryHeaders.delete('authorization')\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,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { chatLauncherStyles } from './chunk-4U5NCKQY.mjs';
|
|
3
|
-
import { useForm } from './chunk-
|
|
4
|
-
import { sonorFetch } from './chunk-
|
|
3
|
+
import { useForm } from './chunk-UQY5KC64.mjs';
|
|
4
|
+
import { sonorFetch } from './chunk-4C5CZJIN.mjs';
|
|
5
5
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
6
6
|
import ReactMarkdown from 'react-markdown';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -1608,5 +1608,5 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
1608
1608
|
}
|
|
1609
1609
|
|
|
1610
1610
|
export { ChatWidget };
|
|
1611
|
-
//# sourceMappingURL=chunk-
|
|
1612
|
-
//# sourceMappingURL=chunk-
|
|
1611
|
+
//# sourceMappingURL=chunk-4NVMAYMQ.mjs.map
|
|
1612
|
+
//# sourceMappingURL=chunk-4NVMAYMQ.mjs.map
|