@sonordev/site-kit 1.2.8 → 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-QETK4P5G.mjs +142 -0
- package/dist/chunk-QETK4P5G.mjs.map +1 -0
- package/dist/chunk-VTECURKB.js +144 -0
- package/dist/chunk-VTECURKB.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/layout/client.d.mts +18 -0
- package/dist/layout/client.d.ts +18 -0
- package/dist/layout/client.js +18 -0
- package/dist/layout/client.js.map +1 -0
- package/dist/layout/client.mjs +9 -0
- package/dist/layout/client.mjs.map +1 -0
- package/dist/layout/index.d.mts +2 -25
- package/dist/layout/index.d.ts +2 -25
- package/dist/layout/index.js +6 -136
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/index.mjs +5 -135
- package/dist/layout/index.mjs.map +1 -1
- package/dist/types-5RCOK10v.d.mts +25 -0
- package/dist/types-5RCOK10v.d.ts +25 -0
- package/package.json +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { SignalBridge } from './chunk-UPR5FEIO.mjs';
|
|
3
|
+
import { SitemapSync } from './chunk-JIDOXTX2.mjs';
|
|
4
|
+
import { AnalyticsProvider } from './chunk-DOSSLBNW.mjs';
|
|
5
|
+
import { EngageWidget } from './chunk-EISQ7LJG.mjs';
|
|
6
|
+
import { createContext, useState, useRef, useCallback, Suspense, useMemo } from 'react';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
function generateId() {
|
|
10
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
11
|
+
return crypto.randomUUID();
|
|
12
|
+
}
|
|
13
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
14
|
+
const r = Math.random() * 16 | 0;
|
|
15
|
+
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function getOrCreateVisitorId() {
|
|
19
|
+
if (typeof window === "undefined") return "";
|
|
20
|
+
const key = "_uptrade_vid";
|
|
21
|
+
let visitorId = localStorage.getItem(key);
|
|
22
|
+
if (!visitorId) {
|
|
23
|
+
visitorId = generateId();
|
|
24
|
+
localStorage.setItem(key, visitorId);
|
|
25
|
+
}
|
|
26
|
+
return visitorId;
|
|
27
|
+
}
|
|
28
|
+
function getOrCreateSessionId(timeoutMinutes = 30) {
|
|
29
|
+
if (typeof window === "undefined") return "";
|
|
30
|
+
const key = "_uptrade_sid";
|
|
31
|
+
const timeKey = "_uptrade_stime";
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
const timeoutMs = timeoutMinutes * 60 * 1e3;
|
|
34
|
+
const existingSession = sessionStorage.getItem(key);
|
|
35
|
+
const lastActivity = sessionStorage.getItem(timeKey);
|
|
36
|
+
if (existingSession && lastActivity) {
|
|
37
|
+
const elapsed = now - parseInt(lastActivity, 10);
|
|
38
|
+
if (elapsed < timeoutMs) {
|
|
39
|
+
sessionStorage.setItem(timeKey, now.toString());
|
|
40
|
+
return existingSession;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const newSession = generateId();
|
|
44
|
+
sessionStorage.setItem(key, newSession);
|
|
45
|
+
sessionStorage.setItem(timeKey, now.toString());
|
|
46
|
+
return newSession;
|
|
47
|
+
}
|
|
48
|
+
var SiteKitIdentityContext = createContext(null);
|
|
49
|
+
function SiteKitIdentityProvider({
|
|
50
|
+
visitorId,
|
|
51
|
+
sessionId,
|
|
52
|
+
children
|
|
53
|
+
}) {
|
|
54
|
+
const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId]);
|
|
55
|
+
return /* @__PURE__ */ jsx(SiteKitIdentityContext.Provider, { value, children });
|
|
56
|
+
}
|
|
57
|
+
function SiteKitClientProviders({
|
|
58
|
+
children,
|
|
59
|
+
apiKey,
|
|
60
|
+
apiUrl,
|
|
61
|
+
projectId,
|
|
62
|
+
analytics = true,
|
|
63
|
+
engage = true,
|
|
64
|
+
signal = false,
|
|
65
|
+
sitemapSync = true,
|
|
66
|
+
debug = false
|
|
67
|
+
}) {
|
|
68
|
+
if (typeof window !== "undefined") {
|
|
69
|
+
window.__SITE_KIT_API_URL__ = apiUrl;
|
|
70
|
+
window.__SITE_KIT_API_KEY__ = apiKey;
|
|
71
|
+
window.__SITE_KIT_DEBUG__ = debug;
|
|
72
|
+
}
|
|
73
|
+
const [visitorId] = useState(() => getOrCreateVisitorId());
|
|
74
|
+
const [sessionId] = useState(() => getOrCreateSessionId());
|
|
75
|
+
const pageMetadataRef = useRef(null);
|
|
76
|
+
const onPageMetadata = useCallback((metadata) => {
|
|
77
|
+
pageMetadataRef.current = metadata;
|
|
78
|
+
}, []);
|
|
79
|
+
let content = /* @__PURE__ */ jsx(Fragment, { children });
|
|
80
|
+
if (signal) {
|
|
81
|
+
const signalConfig = typeof signal === "object" ? signal : {};
|
|
82
|
+
content = /* @__PURE__ */ jsx(
|
|
83
|
+
SignalBridge,
|
|
84
|
+
{
|
|
85
|
+
enabled: true,
|
|
86
|
+
realtime: signalConfig.realtime !== false,
|
|
87
|
+
experiments: signalConfig.experiments !== false,
|
|
88
|
+
behaviorTracking: signalConfig.behaviorTracking !== false,
|
|
89
|
+
visitorId,
|
|
90
|
+
sessionId,
|
|
91
|
+
pageMetadataRef,
|
|
92
|
+
children: content
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (analytics) {
|
|
97
|
+
const analyticsConfig = typeof analytics === "object" ? analytics : {};
|
|
98
|
+
content = /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
|
|
99
|
+
AnalyticsProvider,
|
|
100
|
+
{
|
|
101
|
+
apiUrl,
|
|
102
|
+
apiKey,
|
|
103
|
+
trackPageViews: analyticsConfig.trackPageViews !== false,
|
|
104
|
+
trackWebVitals: analyticsConfig.trackWebVitals !== false,
|
|
105
|
+
trackScrollDepth: analyticsConfig.trackScrollDepth !== false,
|
|
106
|
+
trackClicks: analyticsConfig.trackClicks !== false,
|
|
107
|
+
debug,
|
|
108
|
+
externalVisitorId: visitorId,
|
|
109
|
+
externalSessionId: sessionId,
|
|
110
|
+
onPageMetadata,
|
|
111
|
+
children: content
|
|
112
|
+
}
|
|
113
|
+
) });
|
|
114
|
+
}
|
|
115
|
+
if (engage) {
|
|
116
|
+
const engageConfig = typeof engage === "object" ? engage : {};
|
|
117
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
118
|
+
content,
|
|
119
|
+
/* @__PURE__ */ jsx(
|
|
120
|
+
EngageWidget,
|
|
121
|
+
{
|
|
122
|
+
apiUrl,
|
|
123
|
+
apiKey,
|
|
124
|
+
projectId,
|
|
125
|
+
position: engageConfig.position || "bottom-right",
|
|
126
|
+
chatEnabled: engageConfig.chatEnabled !== false
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
] });
|
|
130
|
+
}
|
|
131
|
+
if (sitemapSync) {
|
|
132
|
+
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
133
|
+
content,
|
|
134
|
+
/* @__PURE__ */ jsx(SitemapSync, { debug })
|
|
135
|
+
] });
|
|
136
|
+
}
|
|
137
|
+
return /* @__PURE__ */ jsx(SiteKitIdentityProvider, { visitorId, sessionId, children: content });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export { SiteKitClientProviders };
|
|
141
|
+
//# sourceMappingURL=chunk-QETK4P5G.mjs.map
|
|
142
|
+
//# sourceMappingURL=chunk-QETK4P5G.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/identity.tsx","../src/layout/SiteKitClientProviders.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-QETK4P5G.mjs","sourcesContent":["/**\n * @sonordev/site-kit/shared — Unified Identity Management\n *\n * Single source of truth for visitor and session IDs across\n * Analytics, Signal, and Engage modules.\n *\n * Storage keys:\n * localStorage: _uptrade_vid (visitor ID, persists ~forever)\n * sessionStorage: _uptrade_sid (session ID, per-tab)\n * sessionStorage: _uptrade_stime (last activity timestamp for timeout)\n */\n\n'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\n\n// ============================================\n// ID Generation\n// ============================================\n\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)\n })\n}\n\n/**\n * Get or create a persistent visitor ID.\n * Stored in localStorage under `_uptrade_vid`.\n */\nexport function getOrCreateVisitorId(): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_vid'\n let visitorId = localStorage.getItem(key)\n\n if (!visitorId) {\n visitorId = generateId()\n localStorage.setItem(key, visitorId)\n }\n\n return visitorId\n}\n\n/**\n * Get or create a session ID with inactivity timeout.\n * Stored in sessionStorage under `_uptrade_sid`.\n * Session expires after `timeoutMinutes` of inactivity (default 30).\n */\nexport function getOrCreateSessionId(timeoutMinutes = 30): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_sid'\n const timeKey = '_uptrade_stime'\n const now = Date.now()\n const timeoutMs = timeoutMinutes * 60 * 1000\n\n const existingSession = sessionStorage.getItem(key)\n const lastActivity = sessionStorage.getItem(timeKey)\n\n if (existingSession && lastActivity) {\n const elapsed = now - parseInt(lastActivity, 10)\n if (elapsed < timeoutMs) {\n // Session still active — refresh timestamp\n sessionStorage.setItem(timeKey, now.toString())\n return existingSession\n }\n }\n\n // New session (first visit or timeout expired)\n const newSession = generateId()\n sessionStorage.setItem(key, newSession)\n sessionStorage.setItem(timeKey, now.toString())\n return newSession\n}\n\n// ============================================\n// React Context\n// ============================================\n\nexport interface SiteKitIdentity {\n visitorId: string\n sessionId: string\n}\n\nconst SiteKitIdentityContext = createContext<SiteKitIdentity | null>(null)\n\nexport interface SiteKitIdentityProviderProps {\n visitorId: string\n sessionId: string\n children: React.ReactNode\n}\n\nexport function SiteKitIdentityProvider({\n visitorId,\n sessionId,\n children,\n}: SiteKitIdentityProviderProps) {\n const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId])\n\n return (\n <SiteKitIdentityContext.Provider value={value}>\n {children}\n </SiteKitIdentityContext.Provider>\n )\n}\n\n/**\n * Access the shared visitor/session identity.\n * Falls back to generating IDs directly if used outside of SiteKitIdentityProvider.\n */\nexport function useSiteKitIdentity(): SiteKitIdentity {\n const context = useContext(SiteKitIdentityContext)\n if (context) return context\n\n // Fallback for standalone usage outside SiteKitLayout\n return {\n visitorId: getOrCreateVisitorId(),\n sessionId: getOrCreateSessionId(),\n }\n}\n","'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 share a unified identity (visitor ID + session ID) via\n * SiteKitIdentityProvider, ensuring consistent tracking across Analytics,\n * Signal, and Engage.\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 { AnalyticsProvider } from '../analytics/AnalyticsProvider'\nimport { EngageWidget } from '../engage/EngageWidget'\nimport { SignalBridge } from '../signal/SignalBridge'\nimport { SitemapSync } from '../SitemapSync'\nimport {\n SiteKitIdentityProvider,\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\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 sitemapSync?: boolean\n debug?: boolean\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // Set window globals for modules that still read from them\n if (typeof window !== 'undefined') {\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = apiKey\n ;(window as any).__SITE_KIT_DEBUG__ = debug\n }\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 let content = <>{children}</>\n\n // Wrap with SignalBridge if enabled\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <SignalBridge\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 {content}\n </SignalBridge>\n )\n }\n\n // Wrap with Analytics if enabled\n if (analytics) {\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n content = (\n <Suspense fallback={null}>\n <AnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n >\n {content}\n </AnalyticsProvider>\n </Suspense>\n )\n }\n\n // Add Engage widget if enabled (renders alongside, doesn't wrap)\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n content = (\n <>\n {content}\n <EngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n <SitemapSync debug={debug} />\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunkREMHGWXT_js = require('./chunk-REMHGWXT.js');
|
|
5
|
+
var chunkPPRAW576_js = require('./chunk-PPRAW576.js');
|
|
6
|
+
var chunkTG46LJFB_js = require('./chunk-TG46LJFB.js');
|
|
7
|
+
var chunkBBITDUZQ_js = require('./chunk-BBITDUZQ.js');
|
|
8
|
+
var react = require('react');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
|
|
11
|
+
function generateId() {
|
|
12
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
13
|
+
return crypto.randomUUID();
|
|
14
|
+
}
|
|
15
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
16
|
+
const r = Math.random() * 16 | 0;
|
|
17
|
+
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function getOrCreateVisitorId() {
|
|
21
|
+
if (typeof window === "undefined") return "";
|
|
22
|
+
const key = "_uptrade_vid";
|
|
23
|
+
let visitorId = localStorage.getItem(key);
|
|
24
|
+
if (!visitorId) {
|
|
25
|
+
visitorId = generateId();
|
|
26
|
+
localStorage.setItem(key, visitorId);
|
|
27
|
+
}
|
|
28
|
+
return visitorId;
|
|
29
|
+
}
|
|
30
|
+
function getOrCreateSessionId(timeoutMinutes = 30) {
|
|
31
|
+
if (typeof window === "undefined") return "";
|
|
32
|
+
const key = "_uptrade_sid";
|
|
33
|
+
const timeKey = "_uptrade_stime";
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
const timeoutMs = timeoutMinutes * 60 * 1e3;
|
|
36
|
+
const existingSession = sessionStorage.getItem(key);
|
|
37
|
+
const lastActivity = sessionStorage.getItem(timeKey);
|
|
38
|
+
if (existingSession && lastActivity) {
|
|
39
|
+
const elapsed = now - parseInt(lastActivity, 10);
|
|
40
|
+
if (elapsed < timeoutMs) {
|
|
41
|
+
sessionStorage.setItem(timeKey, now.toString());
|
|
42
|
+
return existingSession;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const newSession = generateId();
|
|
46
|
+
sessionStorage.setItem(key, newSession);
|
|
47
|
+
sessionStorage.setItem(timeKey, now.toString());
|
|
48
|
+
return newSession;
|
|
49
|
+
}
|
|
50
|
+
var SiteKitIdentityContext = react.createContext(null);
|
|
51
|
+
function SiteKitIdentityProvider({
|
|
52
|
+
visitorId,
|
|
53
|
+
sessionId,
|
|
54
|
+
children
|
|
55
|
+
}) {
|
|
56
|
+
const value = react.useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId]);
|
|
57
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SiteKitIdentityContext.Provider, { value, children });
|
|
58
|
+
}
|
|
59
|
+
function SiteKitClientProviders({
|
|
60
|
+
children,
|
|
61
|
+
apiKey,
|
|
62
|
+
apiUrl,
|
|
63
|
+
projectId,
|
|
64
|
+
analytics = true,
|
|
65
|
+
engage = true,
|
|
66
|
+
signal = false,
|
|
67
|
+
sitemapSync = true,
|
|
68
|
+
debug = false
|
|
69
|
+
}) {
|
|
70
|
+
if (typeof window !== "undefined") {
|
|
71
|
+
window.__SITE_KIT_API_URL__ = apiUrl;
|
|
72
|
+
window.__SITE_KIT_API_KEY__ = apiKey;
|
|
73
|
+
window.__SITE_KIT_DEBUG__ = debug;
|
|
74
|
+
}
|
|
75
|
+
const [visitorId] = react.useState(() => getOrCreateVisitorId());
|
|
76
|
+
const [sessionId] = react.useState(() => getOrCreateSessionId());
|
|
77
|
+
const pageMetadataRef = react.useRef(null);
|
|
78
|
+
const onPageMetadata = react.useCallback((metadata) => {
|
|
79
|
+
pageMetadataRef.current = metadata;
|
|
80
|
+
}, []);
|
|
81
|
+
let content = /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
82
|
+
if (signal) {
|
|
83
|
+
const signalConfig = typeof signal === "object" ? signal : {};
|
|
84
|
+
content = /* @__PURE__ */ jsxRuntime.jsx(
|
|
85
|
+
chunkREMHGWXT_js.SignalBridge,
|
|
86
|
+
{
|
|
87
|
+
enabled: true,
|
|
88
|
+
realtime: signalConfig.realtime !== false,
|
|
89
|
+
experiments: signalConfig.experiments !== false,
|
|
90
|
+
behaviorTracking: signalConfig.behaviorTracking !== false,
|
|
91
|
+
visitorId,
|
|
92
|
+
sessionId,
|
|
93
|
+
pageMetadataRef,
|
|
94
|
+
children: content
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
if (analytics) {
|
|
99
|
+
const analyticsConfig = typeof analytics === "object" ? analytics : {};
|
|
100
|
+
content = /* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
101
|
+
chunkTG46LJFB_js.AnalyticsProvider,
|
|
102
|
+
{
|
|
103
|
+
apiUrl,
|
|
104
|
+
apiKey,
|
|
105
|
+
trackPageViews: analyticsConfig.trackPageViews !== false,
|
|
106
|
+
trackWebVitals: analyticsConfig.trackWebVitals !== false,
|
|
107
|
+
trackScrollDepth: analyticsConfig.trackScrollDepth !== false,
|
|
108
|
+
trackClicks: analyticsConfig.trackClicks !== false,
|
|
109
|
+
debug,
|
|
110
|
+
externalVisitorId: visitorId,
|
|
111
|
+
externalSessionId: sessionId,
|
|
112
|
+
onPageMetadata,
|
|
113
|
+
children: content
|
|
114
|
+
}
|
|
115
|
+
) });
|
|
116
|
+
}
|
|
117
|
+
if (engage) {
|
|
118
|
+
const engageConfig = typeof engage === "object" ? engage : {};
|
|
119
|
+
content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
120
|
+
content,
|
|
121
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
122
|
+
chunkBBITDUZQ_js.EngageWidget,
|
|
123
|
+
{
|
|
124
|
+
apiUrl,
|
|
125
|
+
apiKey,
|
|
126
|
+
projectId,
|
|
127
|
+
position: engageConfig.position || "bottom-right",
|
|
128
|
+
chatEnabled: engageConfig.chatEnabled !== false
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
] });
|
|
132
|
+
}
|
|
133
|
+
if (sitemapSync) {
|
|
134
|
+
content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
135
|
+
content,
|
|
136
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkPPRAW576_js.SitemapSync, { debug })
|
|
137
|
+
] });
|
|
138
|
+
}
|
|
139
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SiteKitIdentityProvider, { visitorId, sessionId, children: content });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
exports.SiteKitClientProviders = SiteKitClientProviders;
|
|
143
|
+
//# sourceMappingURL=chunk-VTECURKB.js.map
|
|
144
|
+
//# sourceMappingURL=chunk-VTECURKB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/identity.tsx","../src/layout/SiteKitClientProviders.tsx"],"names":["createContext","useMemo","jsx","useState","useRef","useCallback","Fragment","SignalBridge","Suspense","AnalyticsProvider","jsxs","EngageWidget","SitemapSync"],"mappings":"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","file":"chunk-VTECURKB.js","sourcesContent":["/**\n * @sonordev/site-kit/shared — Unified Identity Management\n *\n * Single source of truth for visitor and session IDs across\n * Analytics, Signal, and Engage modules.\n *\n * Storage keys:\n * localStorage: _uptrade_vid (visitor ID, persists ~forever)\n * sessionStorage: _uptrade_sid (session ID, per-tab)\n * sessionStorage: _uptrade_stime (last activity timestamp for timeout)\n */\n\n'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\n\n// ============================================\n// ID Generation\n// ============================================\n\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)\n })\n}\n\n/**\n * Get or create a persistent visitor ID.\n * Stored in localStorage under `_uptrade_vid`.\n */\nexport function getOrCreateVisitorId(): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_vid'\n let visitorId = localStorage.getItem(key)\n\n if (!visitorId) {\n visitorId = generateId()\n localStorage.setItem(key, visitorId)\n }\n\n return visitorId\n}\n\n/**\n * Get or create a session ID with inactivity timeout.\n * Stored in sessionStorage under `_uptrade_sid`.\n * Session expires after `timeoutMinutes` of inactivity (default 30).\n */\nexport function getOrCreateSessionId(timeoutMinutes = 30): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_sid'\n const timeKey = '_uptrade_stime'\n const now = Date.now()\n const timeoutMs = timeoutMinutes * 60 * 1000\n\n const existingSession = sessionStorage.getItem(key)\n const lastActivity = sessionStorage.getItem(timeKey)\n\n if (existingSession && lastActivity) {\n const elapsed = now - parseInt(lastActivity, 10)\n if (elapsed < timeoutMs) {\n // Session still active — refresh timestamp\n sessionStorage.setItem(timeKey, now.toString())\n return existingSession\n }\n }\n\n // New session (first visit or timeout expired)\n const newSession = generateId()\n sessionStorage.setItem(key, newSession)\n sessionStorage.setItem(timeKey, now.toString())\n return newSession\n}\n\n// ============================================\n// React Context\n// ============================================\n\nexport interface SiteKitIdentity {\n visitorId: string\n sessionId: string\n}\n\nconst SiteKitIdentityContext = createContext<SiteKitIdentity | null>(null)\n\nexport interface SiteKitIdentityProviderProps {\n visitorId: string\n sessionId: string\n children: React.ReactNode\n}\n\nexport function SiteKitIdentityProvider({\n visitorId,\n sessionId,\n children,\n}: SiteKitIdentityProviderProps) {\n const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId])\n\n return (\n <SiteKitIdentityContext.Provider value={value}>\n {children}\n </SiteKitIdentityContext.Provider>\n )\n}\n\n/**\n * Access the shared visitor/session identity.\n * Falls back to generating IDs directly if used outside of SiteKitIdentityProvider.\n */\nexport function useSiteKitIdentity(): SiteKitIdentity {\n const context = useContext(SiteKitIdentityContext)\n if (context) return context\n\n // Fallback for standalone usage outside SiteKitLayout\n return {\n visitorId: getOrCreateVisitorId(),\n sessionId: getOrCreateSessionId(),\n }\n}\n","'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 share a unified identity (visitor ID + session ID) via\n * SiteKitIdentityProvider, ensuring consistent tracking across Analytics,\n * Signal, and Engage.\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 { AnalyticsProvider } from '../analytics/AnalyticsProvider'\nimport { EngageWidget } from '../engage/EngageWidget'\nimport { SignalBridge } from '../signal/SignalBridge'\nimport { SitemapSync } from '../SitemapSync'\nimport {\n SiteKitIdentityProvider,\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\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 sitemapSync?: boolean\n debug?: boolean\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // Set window globals for modules that still read from them\n if (typeof window !== 'undefined') {\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = apiKey\n ;(window as any).__SITE_KIT_DEBUG__ = debug\n }\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 let content = <>{children}</>\n\n // Wrap with SignalBridge if enabled\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <SignalBridge\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 {content}\n </SignalBridge>\n )\n }\n\n // Wrap with Analytics if enabled\n if (analytics) {\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n content = (\n <Suspense fallback={null}>\n <AnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n >\n {content}\n </AnalyticsProvider>\n </Suspense>\n )\n }\n\n // Add Engage widget if enabled (renders alongside, doesn't wrap)\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n content = (\n <>\n {content}\n <EngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n <SitemapSync debug={debug} />\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var chunkG6VGUAK2_js = require('./chunk-G6VGUAK2.js');
|
|
4
4
|
var chunkTKQLH33E_js = require('./chunk-TKQLH33E.js');
|
|
5
|
-
var chunkREMHGWXT_js = require('./chunk-REMHGWXT.js');
|
|
6
5
|
require('./chunk-DY4K6X3A.js');
|
|
6
|
+
var chunkREMHGWXT_js = require('./chunk-REMHGWXT.js');
|
|
7
7
|
var chunkTLHRV3LZ_js = require('./chunk-TLHRV3LZ.js');
|
|
8
8
|
var chunkIFAW7JFO_js = require('./chunk-IFAW7JFO.js');
|
|
9
9
|
var chunkX4J33XQD_js = require('./chunk-X4J33XQD.js');
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { ManagedImage, assignImageToSlot, clearImageSlot, fetchManagedImage, fetchManagedImages, listImageFiles, uploadImage } from './chunk-36Y7OWES.mjs';
|
|
2
2
|
export { TestimonialSection, fetchReviewStats, fetchReviews } from './chunk-APZMXRI3.mjs';
|
|
3
|
+
import './chunk-N24BPFF6.mjs';
|
|
3
4
|
import { SignalBridge, useSignalExperiment, useSignalEvent } from './chunk-UPR5FEIO.mjs';
|
|
4
5
|
export { SignalBridge, useSignal, useSignalConfig, useSignalEvent, useSignalExperiment, useSignalOutcome } from './chunk-UPR5FEIO.mjs';
|
|
5
|
-
import './chunk-N24BPFF6.mjs';
|
|
6
6
|
export { CalendarView, CheckoutForm, EventCalendar, EventEmbed, EventModal, EventTile, OfferingCard, OfferingList, ProductEmbed, RegistrationForm, UpcomingEvents, createCheckoutSession, fetchNextEvent, fetchOffering, fetchOfferings, fetchProducts, fetchServices, fetchUpcomingEvents, formatDate, formatDateTime, formatPrice, getOfferingUrl, registerForEvent, useEventModal } from './chunk-6YXRLC6W.mjs';
|
|
7
7
|
export { SetupWizard } from './chunk-IKIJEKU3.mjs';
|
|
8
8
|
export { clearRedirectCache, fetchRedirectRules, generateNextRedirects, handleManagedRedirects } from './chunk-XFOL6JDF.mjs';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { A as AnalyticsConfig, E as EngageConfig, S as SignalConfig } from '../types-5RCOK10v.mjs';
|
|
4
|
+
|
|
5
|
+
interface SiteKitClientProvidersProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
apiKey: string;
|
|
8
|
+
apiUrl: string;
|
|
9
|
+
projectId?: string;
|
|
10
|
+
analytics?: boolean | AnalyticsConfig;
|
|
11
|
+
engage?: boolean | EngageConfig;
|
|
12
|
+
signal?: boolean | SignalConfig;
|
|
13
|
+
sitemapSync?: boolean;
|
|
14
|
+
debug?: boolean;
|
|
15
|
+
}
|
|
16
|
+
declare function SiteKitClientProviders({ children, apiKey, apiUrl, projectId, analytics, engage, signal, sitemapSync, debug, }: SiteKitClientProvidersProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { SiteKitClientProviders, type SiteKitClientProvidersProps };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { A as AnalyticsConfig, E as EngageConfig, S as SignalConfig } from '../types-5RCOK10v.js';
|
|
4
|
+
|
|
5
|
+
interface SiteKitClientProvidersProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
apiKey: string;
|
|
8
|
+
apiUrl: string;
|
|
9
|
+
projectId?: string;
|
|
10
|
+
analytics?: boolean | AnalyticsConfig;
|
|
11
|
+
engage?: boolean | EngageConfig;
|
|
12
|
+
signal?: boolean | SignalConfig;
|
|
13
|
+
sitemapSync?: boolean;
|
|
14
|
+
debug?: boolean;
|
|
15
|
+
}
|
|
16
|
+
declare function SiteKitClientProviders({ children, apiKey, apiUrl, projectId, analytics, engage, signal, sitemapSync, debug, }: SiteKitClientProvidersProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { SiteKitClientProviders, type SiteKitClientProvidersProps };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunkVTECURKB_js = require('../chunk-VTECURKB.js');
|
|
5
|
+
require('../chunk-REMHGWXT.js');
|
|
6
|
+
require('../chunk-PPRAW576.js');
|
|
7
|
+
require('../chunk-TG46LJFB.js');
|
|
8
|
+
require('../chunk-BBITDUZQ.js');
|
|
9
|
+
require('../chunk-ZSMWDLMK.js');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, "SiteKitClientProviders", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return chunkVTECURKB_js.SiteKitClientProviders; }
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=client.js.map
|
|
18
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"client.js"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
export { SiteKitClientProviders } from '../chunk-QETK4P5G.mjs';
|
|
3
|
+
import '../chunk-UPR5FEIO.mjs';
|
|
4
|
+
import '../chunk-JIDOXTX2.mjs';
|
|
5
|
+
import '../chunk-DOSSLBNW.mjs';
|
|
6
|
+
import '../chunk-EISQ7LJG.mjs';
|
|
7
|
+
import '../chunk-4XPGGLVP.mjs';
|
|
8
|
+
//# sourceMappingURL=client.mjs.map
|
|
9
|
+
//# sourceMappingURL=client.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"client.mjs"}
|
package/dist/layout/index.d.mts
CHANGED
|
@@ -1,29 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Configuration types for SiteKitLayout modules.
|
|
6
|
-
* Kept in a shared file so both server (SiteKitLayout) and client
|
|
7
|
-
* (SiteKitClientProviders) components can reference them.
|
|
8
|
-
*/
|
|
9
|
-
interface AnalyticsConfig {
|
|
10
|
-
trackPageViews?: boolean;
|
|
11
|
-
trackWebVitals?: boolean;
|
|
12
|
-
trackScrollDepth?: boolean;
|
|
13
|
-
trackClicks?: boolean;
|
|
14
|
-
sessionDuration?: number;
|
|
15
|
-
excludePaths?: string[];
|
|
16
|
-
}
|
|
17
|
-
interface EngageConfig {
|
|
18
|
-
position?: 'bottom-right' | 'bottom-left';
|
|
19
|
-
zIndex?: number;
|
|
20
|
-
chatEnabled?: boolean;
|
|
21
|
-
}
|
|
22
|
-
interface SignalConfig {
|
|
23
|
-
realtime?: boolean;
|
|
24
|
-
experiments?: boolean;
|
|
25
|
-
behaviorTracking?: boolean;
|
|
26
|
-
}
|
|
3
|
+
import { A as AnalyticsConfig, E as EngageConfig, S as SignalConfig } from '../types-5RCOK10v.mjs';
|
|
27
4
|
|
|
28
5
|
interface SiteKitLayoutProps {
|
|
29
6
|
children: React.ReactNode;
|
|
@@ -50,4 +27,4 @@ interface SiteKitLayoutProps {
|
|
|
50
27
|
}
|
|
51
28
|
declare function SiteKitLayout({ children, apiKey, apiUrl, projectId, analytics, engage, signal, sitemapSync, favicon, managedScripts, debug, }: SiteKitLayoutProps): Promise<react_jsx_runtime.JSX.Element>;
|
|
52
29
|
|
|
53
|
-
export {
|
|
30
|
+
export { AnalyticsConfig, EngageConfig, SignalConfig, SiteKitLayout, type SiteKitLayoutProps };
|
package/dist/layout/index.d.ts
CHANGED
|
@@ -1,29 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Configuration types for SiteKitLayout modules.
|
|
6
|
-
* Kept in a shared file so both server (SiteKitLayout) and client
|
|
7
|
-
* (SiteKitClientProviders) components can reference them.
|
|
8
|
-
*/
|
|
9
|
-
interface AnalyticsConfig {
|
|
10
|
-
trackPageViews?: boolean;
|
|
11
|
-
trackWebVitals?: boolean;
|
|
12
|
-
trackScrollDepth?: boolean;
|
|
13
|
-
trackClicks?: boolean;
|
|
14
|
-
sessionDuration?: number;
|
|
15
|
-
excludePaths?: string[];
|
|
16
|
-
}
|
|
17
|
-
interface EngageConfig {
|
|
18
|
-
position?: 'bottom-right' | 'bottom-left';
|
|
19
|
-
zIndex?: number;
|
|
20
|
-
chatEnabled?: boolean;
|
|
21
|
-
}
|
|
22
|
-
interface SignalConfig {
|
|
23
|
-
realtime?: boolean;
|
|
24
|
-
experiments?: boolean;
|
|
25
|
-
behaviorTracking?: boolean;
|
|
26
|
-
}
|
|
3
|
+
import { A as AnalyticsConfig, E as EngageConfig, S as SignalConfig } from '../types-5RCOK10v.js';
|
|
27
4
|
|
|
28
5
|
interface SiteKitLayoutProps {
|
|
29
6
|
children: React.ReactNode;
|
|
@@ -50,4 +27,4 @@ interface SiteKitLayoutProps {
|
|
|
50
27
|
}
|
|
51
28
|
declare function SiteKitLayout({ children, apiKey, apiUrl, projectId, analytics, engage, signal, sitemapSync, favicon, managedScripts, debug, }: SiteKitLayoutProps): Promise<react_jsx_runtime.JSX.Element>;
|
|
52
29
|
|
|
53
|
-
export {
|
|
30
|
+
export { AnalyticsConfig, EngageConfig, SignalConfig, SiteKitLayout, type SiteKitLayoutProps };
|
package/dist/layout/index.js
CHANGED
|
@@ -1,146 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkVTECURKB_js = require('../chunk-VTECURKB.js');
|
|
4
4
|
var chunkDY4K6X3A_js = require('../chunk-DY4K6X3A.js');
|
|
5
|
+
require('../chunk-REMHGWXT.js');
|
|
5
6
|
var chunk2XOW276O_js = require('../chunk-2XOW276O.js');
|
|
6
|
-
|
|
7
|
+
require('../chunk-PPRAW576.js');
|
|
7
8
|
require('../chunk-RMOL4TZ6.js');
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
require('../chunk-TG46LJFB.js');
|
|
10
|
+
require('../chunk-BBITDUZQ.js');
|
|
10
11
|
require('../chunk-ZSMWDLMK.js');
|
|
11
|
-
var react = require('react');
|
|
12
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
13
13
|
|
|
14
|
-
function generateId() {
|
|
15
|
-
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
16
|
-
return crypto.randomUUID();
|
|
17
|
-
}
|
|
18
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
19
|
-
const r = Math.random() * 16 | 0;
|
|
20
|
-
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
function getOrCreateVisitorId() {
|
|
24
|
-
if (typeof window === "undefined") return "";
|
|
25
|
-
const key = "_uptrade_vid";
|
|
26
|
-
let visitorId = localStorage.getItem(key);
|
|
27
|
-
if (!visitorId) {
|
|
28
|
-
visitorId = generateId();
|
|
29
|
-
localStorage.setItem(key, visitorId);
|
|
30
|
-
}
|
|
31
|
-
return visitorId;
|
|
32
|
-
}
|
|
33
|
-
function getOrCreateSessionId(timeoutMinutes = 30) {
|
|
34
|
-
if (typeof window === "undefined") return "";
|
|
35
|
-
const key = "_uptrade_sid";
|
|
36
|
-
const timeKey = "_uptrade_stime";
|
|
37
|
-
const now = Date.now();
|
|
38
|
-
const timeoutMs = timeoutMinutes * 60 * 1e3;
|
|
39
|
-
const existingSession = sessionStorage.getItem(key);
|
|
40
|
-
const lastActivity = sessionStorage.getItem(timeKey);
|
|
41
|
-
if (existingSession && lastActivity) {
|
|
42
|
-
const elapsed = now - parseInt(lastActivity, 10);
|
|
43
|
-
if (elapsed < timeoutMs) {
|
|
44
|
-
sessionStorage.setItem(timeKey, now.toString());
|
|
45
|
-
return existingSession;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const newSession = generateId();
|
|
49
|
-
sessionStorage.setItem(key, newSession);
|
|
50
|
-
sessionStorage.setItem(timeKey, now.toString());
|
|
51
|
-
return newSession;
|
|
52
|
-
}
|
|
53
|
-
var SiteKitIdentityContext = react.createContext(null);
|
|
54
|
-
function SiteKitIdentityProvider({
|
|
55
|
-
visitorId,
|
|
56
|
-
sessionId,
|
|
57
|
-
children
|
|
58
|
-
}) {
|
|
59
|
-
const value = react.useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId]);
|
|
60
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SiteKitIdentityContext.Provider, { value, children });
|
|
61
|
-
}
|
|
62
|
-
function SiteKitClientProviders({
|
|
63
|
-
children,
|
|
64
|
-
apiKey,
|
|
65
|
-
apiUrl,
|
|
66
|
-
projectId,
|
|
67
|
-
analytics = true,
|
|
68
|
-
engage = true,
|
|
69
|
-
signal = false,
|
|
70
|
-
sitemapSync = true,
|
|
71
|
-
debug = false
|
|
72
|
-
}) {
|
|
73
|
-
if (typeof window !== "undefined") {
|
|
74
|
-
window.__SITE_KIT_API_URL__ = apiUrl;
|
|
75
|
-
window.__SITE_KIT_API_KEY__ = apiKey;
|
|
76
|
-
window.__SITE_KIT_DEBUG__ = debug;
|
|
77
|
-
}
|
|
78
|
-
const [visitorId] = react.useState(() => getOrCreateVisitorId());
|
|
79
|
-
const [sessionId] = react.useState(() => getOrCreateSessionId());
|
|
80
|
-
const pageMetadataRef = react.useRef(null);
|
|
81
|
-
const onPageMetadata = react.useCallback((metadata) => {
|
|
82
|
-
pageMetadataRef.current = metadata;
|
|
83
|
-
}, []);
|
|
84
|
-
let content = /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
85
|
-
if (signal) {
|
|
86
|
-
const signalConfig = typeof signal === "object" ? signal : {};
|
|
87
|
-
content = /* @__PURE__ */ jsxRuntime.jsx(
|
|
88
|
-
chunkREMHGWXT_js.SignalBridge,
|
|
89
|
-
{
|
|
90
|
-
enabled: true,
|
|
91
|
-
realtime: signalConfig.realtime !== false,
|
|
92
|
-
experiments: signalConfig.experiments !== false,
|
|
93
|
-
behaviorTracking: signalConfig.behaviorTracking !== false,
|
|
94
|
-
visitorId,
|
|
95
|
-
sessionId,
|
|
96
|
-
pageMetadataRef,
|
|
97
|
-
children: content
|
|
98
|
-
}
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
if (analytics) {
|
|
102
|
-
const analyticsConfig = typeof analytics === "object" ? analytics : {};
|
|
103
|
-
content = /* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
104
|
-
chunkTG46LJFB_js.AnalyticsProvider,
|
|
105
|
-
{
|
|
106
|
-
apiUrl,
|
|
107
|
-
apiKey,
|
|
108
|
-
trackPageViews: analyticsConfig.trackPageViews !== false,
|
|
109
|
-
trackWebVitals: analyticsConfig.trackWebVitals !== false,
|
|
110
|
-
trackScrollDepth: analyticsConfig.trackScrollDepth !== false,
|
|
111
|
-
trackClicks: analyticsConfig.trackClicks !== false,
|
|
112
|
-
debug,
|
|
113
|
-
externalVisitorId: visitorId,
|
|
114
|
-
externalSessionId: sessionId,
|
|
115
|
-
onPageMetadata,
|
|
116
|
-
children: content
|
|
117
|
-
}
|
|
118
|
-
) });
|
|
119
|
-
}
|
|
120
|
-
if (engage) {
|
|
121
|
-
const engageConfig = typeof engage === "object" ? engage : {};
|
|
122
|
-
content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
123
|
-
content,
|
|
124
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
125
|
-
chunkBBITDUZQ_js.EngageWidget,
|
|
126
|
-
{
|
|
127
|
-
apiUrl,
|
|
128
|
-
apiKey,
|
|
129
|
-
projectId,
|
|
130
|
-
position: engageConfig.position || "bottom-right",
|
|
131
|
-
chatEnabled: engageConfig.chatEnabled !== false
|
|
132
|
-
}
|
|
133
|
-
)
|
|
134
|
-
] });
|
|
135
|
-
}
|
|
136
|
-
if (sitemapSync) {
|
|
137
|
-
content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
138
|
-
content,
|
|
139
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkPPRAW576_js.SitemapSync, { debug })
|
|
140
|
-
] });
|
|
141
|
-
}
|
|
142
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SiteKitIdentityProvider, { visitorId, sessionId, children: content });
|
|
143
|
-
}
|
|
144
14
|
async function SiteKitLayout({
|
|
145
15
|
children,
|
|
146
16
|
apiKey,
|
|
@@ -165,7 +35,7 @@ async function SiteKitLayout({
|
|
|
165
35
|
favicon && /* @__PURE__ */ jsxRuntime.jsx(chunkDY4K6X3A_js.ManagedFavicon, { apiKey: resolvedApiKey, apiUrl: resolvedApiUrl }),
|
|
166
36
|
managedScripts && /* @__PURE__ */ jsxRuntime.jsx(chunk2XOW276O_js.ManagedScripts, { position: "head" }),
|
|
167
37
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
168
|
-
SiteKitClientProviders,
|
|
38
|
+
chunkVTECURKB_js.SiteKitClientProviders,
|
|
169
39
|
{
|
|
170
40
|
apiKey: resolvedApiKey,
|
|
171
41
|
apiUrl: resolvedApiUrl,
|
package/dist/layout/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/identity.tsx","../../src/layout/SiteKitClientProviders.tsx","../../src/layout/SiteKitLayout.tsx"],"names":["createContext","useMemo","jsx","useState","useRef","useCallback","Fragment","SignalBridge","Suspense","AnalyticsProvider","jsxs","EngageWidget","SitemapSync","ManagedFavicon","ManagedScripts"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @sonordev/site-kit/shared — Unified Identity Management\n *\n * Single source of truth for visitor and session IDs across\n * Analytics, Signal, and Engage modules.\n *\n * Storage keys:\n * localStorage: _uptrade_vid (visitor ID, persists ~forever)\n * sessionStorage: _uptrade_sid (session ID, per-tab)\n * sessionStorage: _uptrade_stime (last activity timestamp for timeout)\n */\n\n'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\n\n// ============================================\n// ID Generation\n// ============================================\n\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)\n })\n}\n\n/**\n * Get or create a persistent visitor ID.\n * Stored in localStorage under `_uptrade_vid`.\n */\nexport function getOrCreateVisitorId(): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_vid'\n let visitorId = localStorage.getItem(key)\n\n if (!visitorId) {\n visitorId = generateId()\n localStorage.setItem(key, visitorId)\n }\n\n return visitorId\n}\n\n/**\n * Get or create a session ID with inactivity timeout.\n * Stored in sessionStorage under `_uptrade_sid`.\n * Session expires after `timeoutMinutes` of inactivity (default 30).\n */\nexport function getOrCreateSessionId(timeoutMinutes = 30): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_sid'\n const timeKey = '_uptrade_stime'\n const now = Date.now()\n const timeoutMs = timeoutMinutes * 60 * 1000\n\n const existingSession = sessionStorage.getItem(key)\n const lastActivity = sessionStorage.getItem(timeKey)\n\n if (existingSession && lastActivity) {\n const elapsed = now - parseInt(lastActivity, 10)\n if (elapsed < timeoutMs) {\n // Session still active — refresh timestamp\n sessionStorage.setItem(timeKey, now.toString())\n return existingSession\n }\n }\n\n // New session (first visit or timeout expired)\n const newSession = generateId()\n sessionStorage.setItem(key, newSession)\n sessionStorage.setItem(timeKey, now.toString())\n return newSession\n}\n\n// ============================================\n// React Context\n// ============================================\n\nexport interface SiteKitIdentity {\n visitorId: string\n sessionId: string\n}\n\nconst SiteKitIdentityContext = createContext<SiteKitIdentity | null>(null)\n\nexport interface SiteKitIdentityProviderProps {\n visitorId: string\n sessionId: string\n children: React.ReactNode\n}\n\nexport function SiteKitIdentityProvider({\n visitorId,\n sessionId,\n children,\n}: SiteKitIdentityProviderProps) {\n const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId])\n\n return (\n <SiteKitIdentityContext.Provider value={value}>\n {children}\n </SiteKitIdentityContext.Provider>\n )\n}\n\n/**\n * Access the shared visitor/session identity.\n * Falls back to generating IDs directly if used outside of SiteKitIdentityProvider.\n */\nexport function useSiteKitIdentity(): SiteKitIdentity {\n const context = useContext(SiteKitIdentityContext)\n if (context) return context\n\n // Fallback for standalone usage outside SiteKitLayout\n return {\n visitorId: getOrCreateVisitorId(),\n sessionId: getOrCreateSessionId(),\n }\n}\n","'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 share a unified identity (visitor ID + session ID) via\n * SiteKitIdentityProvider, ensuring consistent tracking across Analytics,\n * Signal, and Engage.\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 { AnalyticsProvider } from '../analytics/AnalyticsProvider'\nimport { EngageWidget } from '../engage/EngageWidget'\nimport { SignalBridge } from '../signal/SignalBridge'\nimport { SitemapSync } from '../SitemapSync'\nimport {\n SiteKitIdentityProvider,\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\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 sitemapSync?: boolean\n debug?: boolean\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // Set window globals for modules that still read from them\n if (typeof window !== 'undefined') {\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = apiKey\n ;(window as any).__SITE_KIT_DEBUG__ = debug\n }\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 let content = <>{children}</>\n\n // Wrap with SignalBridge if enabled\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <SignalBridge\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 {content}\n </SignalBridge>\n )\n }\n\n // Wrap with Analytics if enabled\n if (analytics) {\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n content = (\n <Suspense fallback={null}>\n <AnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n >\n {content}\n </AnalyticsProvider>\n </Suspense>\n )\n }\n\n // Add Engage widget if enabled (renders alongside, doesn't wrap)\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n content = (\n <>\n {content}\n <EngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n <SitemapSync debug={debug} />\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n","/**\n * @sonordev/site-kit/layout — SiteKitLayout\n *\n * The master layout component. A single RSC that auto-composes every\n * site-kit feature your layout needs:\n *\n * Server-side (RSC):\n * - ManagedFavicon (link tags from Portal logo)\n * - ManagedScripts position=\"head\" (tracking pixels, analytics tags)\n * - ManagedScripts position=\"body-end\"\n *\n * Client-side (island):\n * - AnalyticsProvider (page views, scroll depth, heatmap, web vitals)\n * - EngageWidget (popups, nudges, chat)\n * - SignalBridge (A/B experiments, behavior tracking)\n * - SitemapSync (keeps Portal seo_pages in sync)\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { SiteKitLayout } from '@sonordev/site-kit/layout'\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html lang=\"en\">\n * <body>\n * <SiteKitLayout>\n * <Header />\n * <main>{children}</main>\n * <Footer />\n * </SiteKitLayout>\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example Opt out of specific features:\n * ```tsx\n * <SiteKitLayout engage={false} signal={false}>\n * {children}\n * </SiteKitLayout>\n * ```\n */\n\nimport * as React from 'react'\nimport { ManagedFavicon } from '../images/ManagedFavicon'\nimport { ManagedScripts } from '../seo/ManagedScripts'\nimport { SiteKitClientProviders } from './SiteKitClientProviders'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\nexport interface SiteKitLayoutProps {\n children: React.ReactNode\n\n /** Portal API key. Defaults to SONOR_API_KEY env var. */\n apiKey?: string\n /** Portal API URL. Defaults to env or https://api.sonor.io */\n apiUrl?: string\n /** Project ID (for Engage chat room routing). Auto-resolved if not provided. */\n projectId?: string\n\n /** Analytics tracking. true (default) | false | config object */\n analytics?: boolean | AnalyticsConfig\n /** Engage widgets (popups, chat). true (default) | false | config object */\n engage?: boolean | EngageConfig\n /** Signal AI (experiments, behavior). false (default) | true | config object */\n signal?: boolean | SignalConfig\n /** SitemapSync client component. Default: true */\n sitemapSync?: boolean\n /** ManagedFavicon in <head>. Default: true */\n favicon?: boolean\n /** ManagedScripts (head + body-end). Default: true */\n managedScripts?: boolean\n\n /** Debug mode — logs to console. Default: false */\n debug?: boolean\n}\n\nexport async function SiteKitLayout({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n favicon = true,\n managedScripts = true,\n debug = false,\n}: SiteKitLayoutProps) {\n // Resolve API config from env (server-side, safe)\n const resolvedApiKey =\n apiKey ??\n process.env.SONOR_API_KEY ??\n process.env.UPTRADE_API_KEY ??\n process.env.NEXT_PUBLIC_UPTRADE_API_KEY ??\n ''\n const resolvedApiUrl =\n apiUrl ??\n process.env.SONOR_API_URL ??\n process.env.UPTRADE_API_URL ??\n process.env.NEXT_PUBLIC_UPTRADE_API_URL ??\n 'https://api.sonor.io'\n\n if (!resolvedApiKey && debug) {\n console.warn(\n '[SiteKitLayout] No API key found. Set SONOR_API_KEY (or UPTRADE_API_KEY).',\n )\n }\n\n return (\n <>\n {/* Server-rendered head components */}\n {favicon && <ManagedFavicon apiKey={resolvedApiKey} apiUrl={resolvedApiUrl} />}\n {managedScripts && <ManagedScripts position=\"head\" />}\n\n {/* Client-side providers island */}\n <SiteKitClientProviders\n apiKey={resolvedApiKey}\n apiUrl={resolvedApiUrl}\n projectId={projectId}\n analytics={analytics}\n engage={engage}\n signal={signal}\n sitemapSync={sitemapSync}\n debug={debug}\n >\n {children}\n </SiteKitClientProviders>\n\n {/* Server-rendered body-end scripts */}\n {managedScripts && <ManagedScripts position=\"body-end\" />}\n </>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/layout/SiteKitLayout.tsx"],"names":["jsxs","Fragment","jsx","ManagedFavicon","ManagedScripts","SiteKitClientProviders"],"mappings":";;;;;;;;;;;;;AA8EA,eAAsB,aAAA,CAAc;AAAA,EAClC,QAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA,GAAY,IAAA;AAAA,EACZ,MAAA,GAAS,IAAA;AAAA,EACT,MAAA,GAAS,KAAA;AAAA,EACT,WAAA,GAAc,IAAA;AAAA,EACd,OAAA,GAAU,IAAA;AAAA,EACV,cAAA,GAAiB,IAAA;AAAA,EACjB,KAAA,GAAQ;AACV,CAAA,EAAuB;AAErB,EAAA,MAAM,cAAA,GACJ,MAAA,IACA,OAAA,CAAQ,GAAA,CAAI,aAAA,IACZ,QAAQ,GAAA,CAAI,eAAA,IACZ,OAAA,CAAQ,GAAA,CAAI,2BAAA,IACZ,EAAA;AACF,EAAA,MAAM,cAAA,GACJ,MAAA,IACA,OAAA,CAAQ,GAAA,CAAI,aAAA,IACZ,QAAQ,GAAA,CAAI,eAAA,IACZ,OAAA,CAAQ,GAAA,CAAI,2BAAA,IACZ,sBAAA;AAEF,EAAA,IAAI,CAAC,kBAAkB,KAAA,EAAO;AAC5B,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN;AAAA,KACF;AAAA,EACF;AAEA,EAAA,uBACEA,eAAA,CAAAC,mBAAA,EAAA,EAEG,QAAA,EAAA;AAAA,IAAA,OAAA,oBAAWC,cAAA,CAACC,+BAAA,EAAA,EAAe,MAAA,EAAQ,cAAA,EAAgB,QAAQ,cAAA,EAAgB,CAAA;AAAA,IAC3E,cAAA,oBAAkBD,cAAA,CAACE,+BAAA,EAAA,EAAe,QAAA,EAAS,MAAA,EAAO,CAAA;AAAA,oBAGnDF,cAAA;AAAA,MAACG,uCAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAQ,cAAA;AAAA,QACR,MAAA,EAAQ,cAAA;AAAA,QACR,SAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA,WAAA;AAAA,QACA,KAAA;AAAA,QAEC;AAAA;AAAA,KACH;AAAA,IAGC,cAAA,oBAAkBH,cAAA,CAACE,+BAAA,EAAA,EAAe,QAAA,EAAS,UAAA,EAAW;AAAA,GAAA,EACzD,CAAA;AAEJ","file":"index.js","sourcesContent":["/**\n * @sonordev/site-kit/layout — SiteKitLayout\n *\n * The master layout component. A single RSC that auto-composes every\n * site-kit feature your layout needs:\n *\n * Server-side (RSC):\n * - ManagedFavicon (link tags from Portal logo)\n * - ManagedScripts position=\"head\" (tracking pixels, analytics tags)\n * - ManagedScripts position=\"body-end\"\n *\n * Client-side (island):\n * - AnalyticsProvider (page views, scroll depth, heatmap, web vitals)\n * - EngageWidget (popups, nudges, chat)\n * - SignalBridge (A/B experiments, behavior tracking)\n * - SitemapSync (keeps Portal seo_pages in sync)\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { SiteKitLayout } from '@sonordev/site-kit/layout'\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html lang=\"en\">\n * <body>\n * <SiteKitLayout>\n * <Header />\n * <main>{children}</main>\n * <Footer />\n * </SiteKitLayout>\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example Opt out of specific features:\n * ```tsx\n * <SiteKitLayout engage={false} signal={false}>\n * {children}\n * </SiteKitLayout>\n * ```\n */\n\nimport * as React from 'react'\nimport { ManagedFavicon } from '../images/ManagedFavicon'\nimport { ManagedScripts } from '../seo/ManagedScripts'\nimport { SiteKitClientProviders } from './SiteKitClientProviders'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\nexport interface SiteKitLayoutProps {\n children: React.ReactNode\n\n /** Portal API key. Defaults to SONOR_API_KEY env var. */\n apiKey?: string\n /** Portal API URL. Defaults to env or https://api.sonor.io */\n apiUrl?: string\n /** Project ID (for Engage chat room routing). Auto-resolved if not provided. */\n projectId?: string\n\n /** Analytics tracking. true (default) | false | config object */\n analytics?: boolean | AnalyticsConfig\n /** Engage widgets (popups, chat). true (default) | false | config object */\n engage?: boolean | EngageConfig\n /** Signal AI (experiments, behavior). false (default) | true | config object */\n signal?: boolean | SignalConfig\n /** SitemapSync client component. Default: true */\n sitemapSync?: boolean\n /** ManagedFavicon in <head>. Default: true */\n favicon?: boolean\n /** ManagedScripts (head + body-end). Default: true */\n managedScripts?: boolean\n\n /** Debug mode — logs to console. Default: false */\n debug?: boolean\n}\n\nexport async function SiteKitLayout({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n favicon = true,\n managedScripts = true,\n debug = false,\n}: SiteKitLayoutProps) {\n // Resolve API config from env (server-side, safe)\n const resolvedApiKey =\n apiKey ??\n process.env.SONOR_API_KEY ??\n process.env.UPTRADE_API_KEY ??\n process.env.NEXT_PUBLIC_UPTRADE_API_KEY ??\n ''\n const resolvedApiUrl =\n apiUrl ??\n process.env.SONOR_API_URL ??\n process.env.UPTRADE_API_URL ??\n process.env.NEXT_PUBLIC_UPTRADE_API_URL ??\n 'https://api.sonor.io'\n\n if (!resolvedApiKey && debug) {\n console.warn(\n '[SiteKitLayout] No API key found. Set SONOR_API_KEY (or UPTRADE_API_KEY).',\n )\n }\n\n return (\n <>\n {/* Server-rendered head components */}\n {favicon && <ManagedFavicon apiKey={resolvedApiKey} apiUrl={resolvedApiUrl} />}\n {managedScripts && <ManagedScripts position=\"head\" />}\n\n {/* Client-side providers island */}\n <SiteKitClientProviders\n apiKey={resolvedApiKey}\n apiUrl={resolvedApiUrl}\n projectId={projectId}\n analytics={analytics}\n engage={engage}\n signal={signal}\n sitemapSync={sitemapSync}\n debug={debug}\n >\n {children}\n </SiteKitClientProviders>\n\n {/* Server-rendered body-end scripts */}\n {managedScripts && <ManagedScripts position=\"body-end\" />}\n </>\n )\n}\n"]}
|
package/dist/layout/index.mjs
CHANGED
|
@@ -1,144 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SiteKitClientProviders } from '../chunk-QETK4P5G.mjs';
|
|
2
2
|
import { ManagedFavicon } from '../chunk-N24BPFF6.mjs';
|
|
3
|
+
import '../chunk-UPR5FEIO.mjs';
|
|
3
4
|
import { ManagedScripts } from '../chunk-5F7FFUPJ.mjs';
|
|
4
|
-
import
|
|
5
|
+
import '../chunk-JIDOXTX2.mjs';
|
|
5
6
|
import '../chunk-SQSBAPWA.mjs';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
7
|
+
import '../chunk-DOSSLBNW.mjs';
|
|
8
|
+
import '../chunk-EISQ7LJG.mjs';
|
|
8
9
|
import '../chunk-4XPGGLVP.mjs';
|
|
9
|
-
import { createContext, useState, useRef, useCallback, Suspense, useMemo } from 'react';
|
|
10
10
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
11
11
|
|
|
12
|
-
function generateId() {
|
|
13
|
-
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
14
|
-
return crypto.randomUUID();
|
|
15
|
-
}
|
|
16
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
17
|
-
const r = Math.random() * 16 | 0;
|
|
18
|
-
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
function getOrCreateVisitorId() {
|
|
22
|
-
if (typeof window === "undefined") return "";
|
|
23
|
-
const key = "_uptrade_vid";
|
|
24
|
-
let visitorId = localStorage.getItem(key);
|
|
25
|
-
if (!visitorId) {
|
|
26
|
-
visitorId = generateId();
|
|
27
|
-
localStorage.setItem(key, visitorId);
|
|
28
|
-
}
|
|
29
|
-
return visitorId;
|
|
30
|
-
}
|
|
31
|
-
function getOrCreateSessionId(timeoutMinutes = 30) {
|
|
32
|
-
if (typeof window === "undefined") return "";
|
|
33
|
-
const key = "_uptrade_sid";
|
|
34
|
-
const timeKey = "_uptrade_stime";
|
|
35
|
-
const now = Date.now();
|
|
36
|
-
const timeoutMs = timeoutMinutes * 60 * 1e3;
|
|
37
|
-
const existingSession = sessionStorage.getItem(key);
|
|
38
|
-
const lastActivity = sessionStorage.getItem(timeKey);
|
|
39
|
-
if (existingSession && lastActivity) {
|
|
40
|
-
const elapsed = now - parseInt(lastActivity, 10);
|
|
41
|
-
if (elapsed < timeoutMs) {
|
|
42
|
-
sessionStorage.setItem(timeKey, now.toString());
|
|
43
|
-
return existingSession;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const newSession = generateId();
|
|
47
|
-
sessionStorage.setItem(key, newSession);
|
|
48
|
-
sessionStorage.setItem(timeKey, now.toString());
|
|
49
|
-
return newSession;
|
|
50
|
-
}
|
|
51
|
-
var SiteKitIdentityContext = createContext(null);
|
|
52
|
-
function SiteKitIdentityProvider({
|
|
53
|
-
visitorId,
|
|
54
|
-
sessionId,
|
|
55
|
-
children
|
|
56
|
-
}) {
|
|
57
|
-
const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId]);
|
|
58
|
-
return /* @__PURE__ */ jsx(SiteKitIdentityContext.Provider, { value, children });
|
|
59
|
-
}
|
|
60
|
-
function SiteKitClientProviders({
|
|
61
|
-
children,
|
|
62
|
-
apiKey,
|
|
63
|
-
apiUrl,
|
|
64
|
-
projectId,
|
|
65
|
-
analytics = true,
|
|
66
|
-
engage = true,
|
|
67
|
-
signal = false,
|
|
68
|
-
sitemapSync = true,
|
|
69
|
-
debug = false
|
|
70
|
-
}) {
|
|
71
|
-
if (typeof window !== "undefined") {
|
|
72
|
-
window.__SITE_KIT_API_URL__ = apiUrl;
|
|
73
|
-
window.__SITE_KIT_API_KEY__ = apiKey;
|
|
74
|
-
window.__SITE_KIT_DEBUG__ = debug;
|
|
75
|
-
}
|
|
76
|
-
const [visitorId] = useState(() => getOrCreateVisitorId());
|
|
77
|
-
const [sessionId] = useState(() => getOrCreateSessionId());
|
|
78
|
-
const pageMetadataRef = useRef(null);
|
|
79
|
-
const onPageMetadata = useCallback((metadata) => {
|
|
80
|
-
pageMetadataRef.current = metadata;
|
|
81
|
-
}, []);
|
|
82
|
-
let content = /* @__PURE__ */ jsx(Fragment, { children });
|
|
83
|
-
if (signal) {
|
|
84
|
-
const signalConfig = typeof signal === "object" ? signal : {};
|
|
85
|
-
content = /* @__PURE__ */ jsx(
|
|
86
|
-
SignalBridge,
|
|
87
|
-
{
|
|
88
|
-
enabled: true,
|
|
89
|
-
realtime: signalConfig.realtime !== false,
|
|
90
|
-
experiments: signalConfig.experiments !== false,
|
|
91
|
-
behaviorTracking: signalConfig.behaviorTracking !== false,
|
|
92
|
-
visitorId,
|
|
93
|
-
sessionId,
|
|
94
|
-
pageMetadataRef,
|
|
95
|
-
children: content
|
|
96
|
-
}
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
if (analytics) {
|
|
100
|
-
const analyticsConfig = typeof analytics === "object" ? analytics : {};
|
|
101
|
-
content = /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
|
|
102
|
-
AnalyticsProvider,
|
|
103
|
-
{
|
|
104
|
-
apiUrl,
|
|
105
|
-
apiKey,
|
|
106
|
-
trackPageViews: analyticsConfig.trackPageViews !== false,
|
|
107
|
-
trackWebVitals: analyticsConfig.trackWebVitals !== false,
|
|
108
|
-
trackScrollDepth: analyticsConfig.trackScrollDepth !== false,
|
|
109
|
-
trackClicks: analyticsConfig.trackClicks !== false,
|
|
110
|
-
debug,
|
|
111
|
-
externalVisitorId: visitorId,
|
|
112
|
-
externalSessionId: sessionId,
|
|
113
|
-
onPageMetadata,
|
|
114
|
-
children: content
|
|
115
|
-
}
|
|
116
|
-
) });
|
|
117
|
-
}
|
|
118
|
-
if (engage) {
|
|
119
|
-
const engageConfig = typeof engage === "object" ? engage : {};
|
|
120
|
-
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
121
|
-
content,
|
|
122
|
-
/* @__PURE__ */ jsx(
|
|
123
|
-
EngageWidget,
|
|
124
|
-
{
|
|
125
|
-
apiUrl,
|
|
126
|
-
apiKey,
|
|
127
|
-
projectId,
|
|
128
|
-
position: engageConfig.position || "bottom-right",
|
|
129
|
-
chatEnabled: engageConfig.chatEnabled !== false
|
|
130
|
-
}
|
|
131
|
-
)
|
|
132
|
-
] });
|
|
133
|
-
}
|
|
134
|
-
if (sitemapSync) {
|
|
135
|
-
content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
136
|
-
content,
|
|
137
|
-
/* @__PURE__ */ jsx(SitemapSync, { debug })
|
|
138
|
-
] });
|
|
139
|
-
}
|
|
140
|
-
return /* @__PURE__ */ jsx(SiteKitIdentityProvider, { visitorId, sessionId, children: content });
|
|
141
|
-
}
|
|
142
12
|
async function SiteKitLayout({
|
|
143
13
|
children,
|
|
144
14
|
apiKey,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/identity.tsx","../../src/layout/SiteKitClientProviders.tsx","../../src/layout/SiteKitLayout.tsx"],"names":["jsx","jsxs","Fragment"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @sonordev/site-kit/shared — Unified Identity Management\n *\n * Single source of truth for visitor and session IDs across\n * Analytics, Signal, and Engage modules.\n *\n * Storage keys:\n * localStorage: _uptrade_vid (visitor ID, persists ~forever)\n * sessionStorage: _uptrade_sid (session ID, per-tab)\n * sessionStorage: _uptrade_stime (last activity timestamp for timeout)\n */\n\n'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\n\n// ============================================\n// ID Generation\n// ============================================\n\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)\n })\n}\n\n/**\n * Get or create a persistent visitor ID.\n * Stored in localStorage under `_uptrade_vid`.\n */\nexport function getOrCreateVisitorId(): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_vid'\n let visitorId = localStorage.getItem(key)\n\n if (!visitorId) {\n visitorId = generateId()\n localStorage.setItem(key, visitorId)\n }\n\n return visitorId\n}\n\n/**\n * Get or create a session ID with inactivity timeout.\n * Stored in sessionStorage under `_uptrade_sid`.\n * Session expires after `timeoutMinutes` of inactivity (default 30).\n */\nexport function getOrCreateSessionId(timeoutMinutes = 30): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_sid'\n const timeKey = '_uptrade_stime'\n const now = Date.now()\n const timeoutMs = timeoutMinutes * 60 * 1000\n\n const existingSession = sessionStorage.getItem(key)\n const lastActivity = sessionStorage.getItem(timeKey)\n\n if (existingSession && lastActivity) {\n const elapsed = now - parseInt(lastActivity, 10)\n if (elapsed < timeoutMs) {\n // Session still active — refresh timestamp\n sessionStorage.setItem(timeKey, now.toString())\n return existingSession\n }\n }\n\n // New session (first visit or timeout expired)\n const newSession = generateId()\n sessionStorage.setItem(key, newSession)\n sessionStorage.setItem(timeKey, now.toString())\n return newSession\n}\n\n// ============================================\n// React Context\n// ============================================\n\nexport interface SiteKitIdentity {\n visitorId: string\n sessionId: string\n}\n\nconst SiteKitIdentityContext = createContext<SiteKitIdentity | null>(null)\n\nexport interface SiteKitIdentityProviderProps {\n visitorId: string\n sessionId: string\n children: React.ReactNode\n}\n\nexport function SiteKitIdentityProvider({\n visitorId,\n sessionId,\n children,\n}: SiteKitIdentityProviderProps) {\n const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId])\n\n return (\n <SiteKitIdentityContext.Provider value={value}>\n {children}\n </SiteKitIdentityContext.Provider>\n )\n}\n\n/**\n * Access the shared visitor/session identity.\n * Falls back to generating IDs directly if used outside of SiteKitIdentityProvider.\n */\nexport function useSiteKitIdentity(): SiteKitIdentity {\n const context = useContext(SiteKitIdentityContext)\n if (context) return context\n\n // Fallback for standalone usage outside SiteKitLayout\n return {\n visitorId: getOrCreateVisitorId(),\n sessionId: getOrCreateSessionId(),\n }\n}\n","'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 share a unified identity (visitor ID + session ID) via\n * SiteKitIdentityProvider, ensuring consistent tracking across Analytics,\n * Signal, and Engage.\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 { AnalyticsProvider } from '../analytics/AnalyticsProvider'\nimport { EngageWidget } from '../engage/EngageWidget'\nimport { SignalBridge } from '../signal/SignalBridge'\nimport { SitemapSync } from '../SitemapSync'\nimport {\n SiteKitIdentityProvider,\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\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 sitemapSync?: boolean\n debug?: boolean\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // Set window globals for modules that still read from them\n if (typeof window !== 'undefined') {\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = apiKey\n ;(window as any).__SITE_KIT_DEBUG__ = debug\n }\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 let content = <>{children}</>\n\n // Wrap with SignalBridge if enabled\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <SignalBridge\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 {content}\n </SignalBridge>\n )\n }\n\n // Wrap with Analytics if enabled\n if (analytics) {\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n content = (\n <Suspense fallback={null}>\n <AnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n >\n {content}\n </AnalyticsProvider>\n </Suspense>\n )\n }\n\n // Add Engage widget if enabled (renders alongside, doesn't wrap)\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n content = (\n <>\n {content}\n <EngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n <SitemapSync debug={debug} />\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n","/**\n * @sonordev/site-kit/layout — SiteKitLayout\n *\n * The master layout component. A single RSC that auto-composes every\n * site-kit feature your layout needs:\n *\n * Server-side (RSC):\n * - ManagedFavicon (link tags from Portal logo)\n * - ManagedScripts position=\"head\" (tracking pixels, analytics tags)\n * - ManagedScripts position=\"body-end\"\n *\n * Client-side (island):\n * - AnalyticsProvider (page views, scroll depth, heatmap, web vitals)\n * - EngageWidget (popups, nudges, chat)\n * - SignalBridge (A/B experiments, behavior tracking)\n * - SitemapSync (keeps Portal seo_pages in sync)\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { SiteKitLayout } from '@sonordev/site-kit/layout'\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html lang=\"en\">\n * <body>\n * <SiteKitLayout>\n * <Header />\n * <main>{children}</main>\n * <Footer />\n * </SiteKitLayout>\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example Opt out of specific features:\n * ```tsx\n * <SiteKitLayout engage={false} signal={false}>\n * {children}\n * </SiteKitLayout>\n * ```\n */\n\nimport * as React from 'react'\nimport { ManagedFavicon } from '../images/ManagedFavicon'\nimport { ManagedScripts } from '../seo/ManagedScripts'\nimport { SiteKitClientProviders } from './SiteKitClientProviders'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\nexport interface SiteKitLayoutProps {\n children: React.ReactNode\n\n /** Portal API key. Defaults to SONOR_API_KEY env var. */\n apiKey?: string\n /** Portal API URL. Defaults to env or https://api.sonor.io */\n apiUrl?: string\n /** Project ID (for Engage chat room routing). Auto-resolved if not provided. */\n projectId?: string\n\n /** Analytics tracking. true (default) | false | config object */\n analytics?: boolean | AnalyticsConfig\n /** Engage widgets (popups, chat). true (default) | false | config object */\n engage?: boolean | EngageConfig\n /** Signal AI (experiments, behavior). false (default) | true | config object */\n signal?: boolean | SignalConfig\n /** SitemapSync client component. Default: true */\n sitemapSync?: boolean\n /** ManagedFavicon in <head>. Default: true */\n favicon?: boolean\n /** ManagedScripts (head + body-end). Default: true */\n managedScripts?: boolean\n\n /** Debug mode — logs to console. Default: false */\n debug?: boolean\n}\n\nexport async function SiteKitLayout({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n favicon = true,\n managedScripts = true,\n debug = false,\n}: SiteKitLayoutProps) {\n // Resolve API config from env (server-side, safe)\n const resolvedApiKey =\n apiKey ??\n process.env.SONOR_API_KEY ??\n process.env.UPTRADE_API_KEY ??\n process.env.NEXT_PUBLIC_UPTRADE_API_KEY ??\n ''\n const resolvedApiUrl =\n apiUrl ??\n process.env.SONOR_API_URL ??\n process.env.UPTRADE_API_URL ??\n process.env.NEXT_PUBLIC_UPTRADE_API_URL ??\n 'https://api.sonor.io'\n\n if (!resolvedApiKey && debug) {\n console.warn(\n '[SiteKitLayout] No API key found. Set SONOR_API_KEY (or UPTRADE_API_KEY).',\n )\n }\n\n return (\n <>\n {/* Server-rendered head components */}\n {favicon && <ManagedFavicon apiKey={resolvedApiKey} apiUrl={resolvedApiUrl} />}\n {managedScripts && <ManagedScripts position=\"head\" />}\n\n {/* Client-side providers island */}\n <SiteKitClientProviders\n apiKey={resolvedApiKey}\n apiUrl={resolvedApiUrl}\n projectId={projectId}\n analytics={analytics}\n engage={engage}\n signal={signal}\n sitemapSync={sitemapSync}\n debug={debug}\n >\n {children}\n </SiteKitClientProviders>\n\n {/* Server-rendered body-end scripts */}\n {managedScripts && <ManagedScripts position=\"body-end\" />}\n </>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/layout/SiteKitLayout.tsx"],"names":[],"mappings":";;;;;;;;;;;AA8EA,eAAsB,aAAA,CAAc;AAAA,EAClC,QAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA,GAAY,IAAA;AAAA,EACZ,MAAA,GAAS,IAAA;AAAA,EACT,MAAA,GAAS,KAAA;AAAA,EACT,WAAA,GAAc,IAAA;AAAA,EACd,OAAA,GAAU,IAAA;AAAA,EACV,cAAA,GAAiB,IAAA;AAAA,EACjB,KAAA,GAAQ;AACV,CAAA,EAAuB;AAErB,EAAA,MAAM,cAAA,GACJ,MAAA,IACA,OAAA,CAAQ,GAAA,CAAI,aAAA,IACZ,QAAQ,GAAA,CAAI,eAAA,IACZ,OAAA,CAAQ,GAAA,CAAI,2BAAA,IACZ,EAAA;AACF,EAAA,MAAM,cAAA,GACJ,MAAA,IACA,OAAA,CAAQ,GAAA,CAAI,aAAA,IACZ,QAAQ,GAAA,CAAI,eAAA,IACZ,OAAA,CAAQ,GAAA,CAAI,2BAAA,IACZ,sBAAA;AAEF,EAAA,IAAI,CAAC,kBAAkB,KAAA,EAAO;AAC5B,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN;AAAA,KACF;AAAA,EACF;AAEA,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EAEG,QAAA,EAAA;AAAA,IAAA,OAAA,oBAAW,GAAA,CAAC,cAAA,EAAA,EAAe,MAAA,EAAQ,cAAA,EAAgB,QAAQ,cAAA,EAAgB,CAAA;AAAA,IAC3E,cAAA,oBAAkB,GAAA,CAAC,cAAA,EAAA,EAAe,QAAA,EAAS,MAAA,EAAO,CAAA;AAAA,oBAGnD,GAAA;AAAA,MAAC,sBAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAQ,cAAA;AAAA,QACR,MAAA,EAAQ,cAAA;AAAA,QACR,SAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA,WAAA;AAAA,QACA,KAAA;AAAA,QAEC;AAAA;AAAA,KACH;AAAA,IAGC,cAAA,oBAAkB,GAAA,CAAC,cAAA,EAAA,EAAe,QAAA,EAAS,UAAA,EAAW;AAAA,GAAA,EACzD,CAAA;AAEJ","file":"index.mjs","sourcesContent":["/**\n * @sonordev/site-kit/layout — SiteKitLayout\n *\n * The master layout component. A single RSC that auto-composes every\n * site-kit feature your layout needs:\n *\n * Server-side (RSC):\n * - ManagedFavicon (link tags from Portal logo)\n * - ManagedScripts position=\"head\" (tracking pixels, analytics tags)\n * - ManagedScripts position=\"body-end\"\n *\n * Client-side (island):\n * - AnalyticsProvider (page views, scroll depth, heatmap, web vitals)\n * - EngageWidget (popups, nudges, chat)\n * - SignalBridge (A/B experiments, behavior tracking)\n * - SitemapSync (keeps Portal seo_pages in sync)\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { SiteKitLayout } from '@sonordev/site-kit/layout'\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html lang=\"en\">\n * <body>\n * <SiteKitLayout>\n * <Header />\n * <main>{children}</main>\n * <Footer />\n * </SiteKitLayout>\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example Opt out of specific features:\n * ```tsx\n * <SiteKitLayout engage={false} signal={false}>\n * {children}\n * </SiteKitLayout>\n * ```\n */\n\nimport * as React from 'react'\nimport { ManagedFavicon } from '../images/ManagedFavicon'\nimport { ManagedScripts } from '../seo/ManagedScripts'\nimport { SiteKitClientProviders } from './SiteKitClientProviders'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\nexport interface SiteKitLayoutProps {\n children: React.ReactNode\n\n /** Portal API key. Defaults to SONOR_API_KEY env var. */\n apiKey?: string\n /** Portal API URL. Defaults to env or https://api.sonor.io */\n apiUrl?: string\n /** Project ID (for Engage chat room routing). Auto-resolved if not provided. */\n projectId?: string\n\n /** Analytics tracking. true (default) | false | config object */\n analytics?: boolean | AnalyticsConfig\n /** Engage widgets (popups, chat). true (default) | false | config object */\n engage?: boolean | EngageConfig\n /** Signal AI (experiments, behavior). false (default) | true | config object */\n signal?: boolean | SignalConfig\n /** SitemapSync client component. Default: true */\n sitemapSync?: boolean\n /** ManagedFavicon in <head>. Default: true */\n favicon?: boolean\n /** ManagedScripts (head + body-end). Default: true */\n managedScripts?: boolean\n\n /** Debug mode — logs to console. Default: false */\n debug?: boolean\n}\n\nexport async function SiteKitLayout({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n favicon = true,\n managedScripts = true,\n debug = false,\n}: SiteKitLayoutProps) {\n // Resolve API config from env (server-side, safe)\n const resolvedApiKey =\n apiKey ??\n process.env.SONOR_API_KEY ??\n process.env.UPTRADE_API_KEY ??\n process.env.NEXT_PUBLIC_UPTRADE_API_KEY ??\n ''\n const resolvedApiUrl =\n apiUrl ??\n process.env.SONOR_API_URL ??\n process.env.UPTRADE_API_URL ??\n process.env.NEXT_PUBLIC_UPTRADE_API_URL ??\n 'https://api.sonor.io'\n\n if (!resolvedApiKey && debug) {\n console.warn(\n '[SiteKitLayout] No API key found. Set SONOR_API_KEY (or UPTRADE_API_KEY).',\n )\n }\n\n return (\n <>\n {/* Server-rendered head components */}\n {favicon && <ManagedFavicon apiKey={resolvedApiKey} apiUrl={resolvedApiUrl} />}\n {managedScripts && <ManagedScripts position=\"head\" />}\n\n {/* Client-side providers island */}\n <SiteKitClientProviders\n apiKey={resolvedApiKey}\n apiUrl={resolvedApiUrl}\n projectId={projectId}\n analytics={analytics}\n engage={engage}\n signal={signal}\n sitemapSync={sitemapSync}\n debug={debug}\n >\n {children}\n </SiteKitClientProviders>\n\n {/* Server-rendered body-end scripts */}\n {managedScripts && <ManagedScripts position=\"body-end\" />}\n </>\n )\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration types for SiteKitLayout modules.
|
|
3
|
+
* Kept in a shared file so both server (SiteKitLayout) and client
|
|
4
|
+
* (SiteKitClientProviders) components can reference them.
|
|
5
|
+
*/
|
|
6
|
+
interface AnalyticsConfig {
|
|
7
|
+
trackPageViews?: boolean;
|
|
8
|
+
trackWebVitals?: boolean;
|
|
9
|
+
trackScrollDepth?: boolean;
|
|
10
|
+
trackClicks?: boolean;
|
|
11
|
+
sessionDuration?: number;
|
|
12
|
+
excludePaths?: string[];
|
|
13
|
+
}
|
|
14
|
+
interface EngageConfig {
|
|
15
|
+
position?: 'bottom-right' | 'bottom-left';
|
|
16
|
+
zIndex?: number;
|
|
17
|
+
chatEnabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface SignalConfig {
|
|
20
|
+
realtime?: boolean;
|
|
21
|
+
experiments?: boolean;
|
|
22
|
+
behaviorTracking?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type { AnalyticsConfig as A, EngageConfig as E, SignalConfig as S };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration types for SiteKitLayout modules.
|
|
3
|
+
* Kept in a shared file so both server (SiteKitLayout) and client
|
|
4
|
+
* (SiteKitClientProviders) components can reference them.
|
|
5
|
+
*/
|
|
6
|
+
interface AnalyticsConfig {
|
|
7
|
+
trackPageViews?: boolean;
|
|
8
|
+
trackWebVitals?: boolean;
|
|
9
|
+
trackScrollDepth?: boolean;
|
|
10
|
+
trackClicks?: boolean;
|
|
11
|
+
sessionDuration?: number;
|
|
12
|
+
excludePaths?: string[];
|
|
13
|
+
}
|
|
14
|
+
interface EngageConfig {
|
|
15
|
+
position?: 'bottom-right' | 'bottom-left';
|
|
16
|
+
zIndex?: number;
|
|
17
|
+
chatEnabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface SignalConfig {
|
|
20
|
+
realtime?: boolean;
|
|
21
|
+
experiments?: boolean;
|
|
22
|
+
behaviorTracking?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type { AnalyticsConfig as A, EngageConfig as E, SignalConfig as S };
|