@sonordev/site-kit 1.2.7

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.
Files changed (300) hide show
  1. package/README.md +376 -0
  2. package/dist/SetupWizard-Cki06kB0.d.mts +12 -0
  3. package/dist/SetupWizard-Cki06kB0.d.ts +12 -0
  4. package/dist/analytics/index.d.mts +93 -0
  5. package/dist/analytics/index.d.ts +93 -0
  6. package/dist/analytics/index.js +89 -0
  7. package/dist/analytics/index.js.map +1 -0
  8. package/dist/analytics/index.mjs +71 -0
  9. package/dist/analytics/index.mjs.map +1 -0
  10. package/dist/api-CWtoFJCO.d.mts +137 -0
  11. package/dist/api-CWtoFJCO.d.ts +137 -0
  12. package/dist/blog/index.d.mts +305 -0
  13. package/dist/blog/index.d.ts +305 -0
  14. package/dist/blog/index.js +1578 -0
  15. package/dist/blog/index.js.map +1 -0
  16. package/dist/blog/index.mjs +1562 -0
  17. package/dist/blog/index.mjs.map +1 -0
  18. package/dist/blog/server.d.mts +229 -0
  19. package/dist/blog/server.d.ts +229 -0
  20. package/dist/blog/server.js +692 -0
  21. package/dist/blog/server.js.map +1 -0
  22. package/dist/blog/server.mjs +666 -0
  23. package/dist/blog/server.mjs.map +1 -0
  24. package/dist/chunk-24277A3Q.mjs +968 -0
  25. package/dist/chunk-24277A3Q.mjs.map +1 -0
  26. package/dist/chunk-373TK6TZ.js +321 -0
  27. package/dist/chunk-373TK6TZ.js.map +1 -0
  28. package/dist/chunk-3MYZS6PD.js +30 -0
  29. package/dist/chunk-3MYZS6PD.js.map +1 -0
  30. package/dist/chunk-43GBM4SX.js +283 -0
  31. package/dist/chunk-43GBM4SX.js.map +1 -0
  32. package/dist/chunk-4XPGGLVP.mjs +53 -0
  33. package/dist/chunk-4XPGGLVP.mjs.map +1 -0
  34. package/dist/chunk-622GAQP5.js +2008 -0
  35. package/dist/chunk-622GAQP5.js.map +1 -0
  36. package/dist/chunk-6BIPAKL4.mjs +28 -0
  37. package/dist/chunk-6BIPAKL4.mjs.map +1 -0
  38. package/dist/chunk-6ZCISNAB.mjs +343 -0
  39. package/dist/chunk-6ZCISNAB.mjs.map +1 -0
  40. package/dist/chunk-72MQFHYJ.js +1429 -0
  41. package/dist/chunk-72MQFHYJ.js.map +1 -0
  42. package/dist/chunk-7557OTHW.js +62 -0
  43. package/dist/chunk-7557OTHW.js.map +1 -0
  44. package/dist/chunk-7FUV73JZ.js +981 -0
  45. package/dist/chunk-7FUV73JZ.js.map +1 -0
  46. package/dist/chunk-7RF6PVHA.mjs +324 -0
  47. package/dist/chunk-7RF6PVHA.mjs.map +1 -0
  48. package/dist/chunk-7RYCHO6D.mjs +134 -0
  49. package/dist/chunk-7RYCHO6D.mjs.map +1 -0
  50. package/dist/chunk-7UKPRW25.mjs +1999 -0
  51. package/dist/chunk-7UKPRW25.mjs.map +1 -0
  52. package/dist/chunk-7URAOG2M.js +14864 -0
  53. package/dist/chunk-7URAOG2M.js.map +1 -0
  54. package/dist/chunk-AFAO3TGS.mjs +810 -0
  55. package/dist/chunk-AFAO3TGS.mjs.map +1 -0
  56. package/dist/chunk-BYLIU6XG.js +343 -0
  57. package/dist/chunk-BYLIU6XG.js.map +1 -0
  58. package/dist/chunk-D63MUKZ6.mjs +4423 -0
  59. package/dist/chunk-D63MUKZ6.mjs.map +1 -0
  60. package/dist/chunk-DDKW2FNA.js +390 -0
  61. package/dist/chunk-DDKW2FNA.js.map +1 -0
  62. package/dist/chunk-DQYMKR27.mjs +341 -0
  63. package/dist/chunk-DQYMKR27.mjs.map +1 -0
  64. package/dist/chunk-DW5UJKHH.js +221 -0
  65. package/dist/chunk-DW5UJKHH.js.map +1 -0
  66. package/dist/chunk-EEZCR6E6.js +50 -0
  67. package/dist/chunk-EEZCR6E6.js.map +1 -0
  68. package/dist/chunk-GCJXQ4AG.mjs +59 -0
  69. package/dist/chunk-GCJXQ4AG.mjs.map +1 -0
  70. package/dist/chunk-JGNQK2G6.mjs +14845 -0
  71. package/dist/chunk-JGNQK2G6.mjs.map +1 -0
  72. package/dist/chunk-JTLOJLWQ.mjs +563 -0
  73. package/dist/chunk-JTLOJLWQ.mjs.map +1 -0
  74. package/dist/chunk-K23A4G76.mjs +202 -0
  75. package/dist/chunk-K23A4G76.mjs.map +1 -0
  76. package/dist/chunk-KKU3K7RG.js +336 -0
  77. package/dist/chunk-KKU3K7RG.js.map +1 -0
  78. package/dist/chunk-KUGMH4ZF.js +571 -0
  79. package/dist/chunk-KUGMH4ZF.js.map +1 -0
  80. package/dist/chunk-LBVWVP72.js +110 -0
  81. package/dist/chunk-LBVWVP72.js.map +1 -0
  82. package/dist/chunk-LIVWLY2P.js +138 -0
  83. package/dist/chunk-LIVWLY2P.js.map +1 -0
  84. package/dist/chunk-M2T6R7BA.mjs +1003 -0
  85. package/dist/chunk-M2T6R7BA.mjs.map +1 -0
  86. package/dist/chunk-MV3QN7PW.mjs +47 -0
  87. package/dist/chunk-MV3QN7PW.mjs.map +1 -0
  88. package/dist/chunk-OB7E654K.js +72 -0
  89. package/dist/chunk-OB7E654K.js.map +1 -0
  90. package/dist/chunk-OIIKTGRL.mjs +380 -0
  91. package/dist/chunk-OIIKTGRL.mjs.map +1 -0
  92. package/dist/chunk-P3UWIUJS.mjs +1427 -0
  93. package/dist/chunk-P3UWIUJS.mjs.map +1 -0
  94. package/dist/chunk-PKN27UMH.mjs +136 -0
  95. package/dist/chunk-PKN27UMH.mjs.map +1 -0
  96. package/dist/chunk-QXV4667R.mjs +105 -0
  97. package/dist/chunk-QXV4667R.mjs.map +1 -0
  98. package/dist/chunk-S7FRYNSU.mjs +315 -0
  99. package/dist/chunk-S7FRYNSU.mjs.map +1 -0
  100. package/dist/chunk-TFLQX7K7.mjs +68 -0
  101. package/dist/chunk-TFLQX7K7.mjs.map +1 -0
  102. package/dist/chunk-UWE5PCYJ.mjs +279 -0
  103. package/dist/chunk-UWE5PCYJ.mjs.map +1 -0
  104. package/dist/chunk-UYFDNX2F.js +4469 -0
  105. package/dist/chunk-UYFDNX2F.js.map +1 -0
  106. package/dist/chunk-W4PALSGM.js +350 -0
  107. package/dist/chunk-W4PALSGM.js.map +1 -0
  108. package/dist/chunk-WECQ6KOB.js +1008 -0
  109. package/dist/chunk-WECQ6KOB.js.map +1 -0
  110. package/dist/chunk-XQQWI6WB.js +814 -0
  111. package/dist/chunk-XQQWI6WB.js.map +1 -0
  112. package/dist/chunk-XZJOZJB6.js +140 -0
  113. package/dist/chunk-XZJOZJB6.js.map +1 -0
  114. package/dist/chunk-ZSMWDLMK.js +63 -0
  115. package/dist/chunk-ZSMWDLMK.js.map +1 -0
  116. package/dist/cli/index.js +37243 -0
  117. package/dist/cli/index.js.map +1 -0
  118. package/dist/cli/index.mjs +37209 -0
  119. package/dist/cli/index.mjs.map +1 -0
  120. package/dist/commerce/index.d.mts +170 -0
  121. package/dist/commerce/index.d.ts +170 -0
  122. package/dist/commerce/index.js +174 -0
  123. package/dist/commerce/index.js.map +1 -0
  124. package/dist/commerce/index.mjs +5 -0
  125. package/dist/commerce/index.mjs.map +1 -0
  126. package/dist/commerce/server.d.mts +107 -0
  127. package/dist/commerce/server.d.ts +107 -0
  128. package/dist/commerce/server.js +187 -0
  129. package/dist/commerce/server.js.map +1 -0
  130. package/dist/commerce/server.mjs +177 -0
  131. package/dist/commerce/server.mjs.map +1 -0
  132. package/dist/config/index.d.mts +43 -0
  133. package/dist/config/index.d.ts +43 -0
  134. package/dist/config/index.js +66 -0
  135. package/dist/config/index.js.map +1 -0
  136. package/dist/config/index.mjs +64 -0
  137. package/dist/config/index.mjs.map +1 -0
  138. package/dist/engage/index.d.mts +33 -0
  139. package/dist/engage/index.d.ts +33 -0
  140. package/dist/engage/index.js +22 -0
  141. package/dist/engage/index.js.map +1 -0
  142. package/dist/engage/index.mjs +5 -0
  143. package/dist/engage/index.mjs.map +1 -0
  144. package/dist/forms/index.d.mts +437 -0
  145. package/dist/forms/index.d.ts +437 -0
  146. package/dist/forms/index.js +1168 -0
  147. package/dist/forms/index.js.map +1 -0
  148. package/dist/forms/index.mjs +1142 -0
  149. package/dist/forms/index.mjs.map +1 -0
  150. package/dist/generators-2XKQMPKH.mjs +4 -0
  151. package/dist/generators-2XKQMPKH.mjs.map +1 -0
  152. package/dist/generators-DTMO36DV.js +33 -0
  153. package/dist/generators-DTMO36DV.js.map +1 -0
  154. package/dist/images/index.d.mts +4 -0
  155. package/dist/images/index.d.ts +4 -0
  156. package/dist/images/index.js +46 -0
  157. package/dist/images/index.js.map +1 -0
  158. package/dist/images/index.mjs +5 -0
  159. package/dist/images/index.mjs.map +1 -0
  160. package/dist/images/server.d.mts +69 -0
  161. package/dist/images/server.d.ts +69 -0
  162. package/dist/images/server.js +21 -0
  163. package/dist/images/server.js.map +1 -0
  164. package/dist/images/server.mjs +4 -0
  165. package/dist/images/server.mjs.map +1 -0
  166. package/dist/index.d.mts +846 -0
  167. package/dist/index.d.ts +846 -0
  168. package/dist/index.js +2623 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/index.mjs +2416 -0
  171. package/dist/index.mjs.map +1 -0
  172. package/dist/layout/index.d.mts +53 -0
  173. package/dist/layout/index.d.ts +53 -0
  174. package/dist/layout/index.js +187 -0
  175. package/dist/layout/index.js.map +1 -0
  176. package/dist/layout/index.mjs +185 -0
  177. package/dist/layout/index.mjs.map +1 -0
  178. package/dist/llms/index.d.mts +448 -0
  179. package/dist/llms/index.d.ts +448 -0
  180. package/dist/llms/index.js +581 -0
  181. package/dist/llms/index.js.map +1 -0
  182. package/dist/llms/index.mjs +529 -0
  183. package/dist/llms/index.mjs.map +1 -0
  184. package/dist/manifest/index.d.mts +62 -0
  185. package/dist/manifest/index.d.ts +62 -0
  186. package/dist/manifest/index.js +85 -0
  187. package/dist/manifest/index.js.map +1 -0
  188. package/dist/manifest/index.mjs +83 -0
  189. package/dist/manifest/index.mjs.map +1 -0
  190. package/dist/middleware/index.d.mts +63 -0
  191. package/dist/middleware/index.d.ts +63 -0
  192. package/dist/middleware/index.js +54 -0
  193. package/dist/middleware/index.js.map +1 -0
  194. package/dist/middleware/index.mjs +51 -0
  195. package/dist/middleware/index.mjs.map +1 -0
  196. package/dist/migrator-2MQHOFDQ.mjs +4 -0
  197. package/dist/migrator-2MQHOFDQ.mjs.map +1 -0
  198. package/dist/migrator-THJCF6MZ.js +37 -0
  199. package/dist/migrator-THJCF6MZ.js.map +1 -0
  200. package/dist/redirects/index.d.mts +78 -0
  201. package/dist/redirects/index.d.ts +78 -0
  202. package/dist/redirects/index.js +26 -0
  203. package/dist/redirects/index.js.map +1 -0
  204. package/dist/redirects/index.mjs +5 -0
  205. package/dist/redirects/index.mjs.map +1 -0
  206. package/dist/reputation/index.d.mts +57 -0
  207. package/dist/reputation/index.d.ts +57 -0
  208. package/dist/reputation/index.js +21 -0
  209. package/dist/reputation/index.js.map +1 -0
  210. package/dist/reputation/index.mjs +4 -0
  211. package/dist/reputation/index.mjs.map +1 -0
  212. package/dist/robots/index.d.mts +38 -0
  213. package/dist/robots/index.d.ts +38 -0
  214. package/dist/robots/index.js +52 -0
  215. package/dist/robots/index.js.map +1 -0
  216. package/dist/robots/index.mjs +50 -0
  217. package/dist/robots/index.mjs.map +1 -0
  218. package/dist/routing-B5XS-6_W.d.mts +118 -0
  219. package/dist/routing-DZYzyDHw.d.ts +118 -0
  220. package/dist/scanner-GAF5PO5F.js +53 -0
  221. package/dist/scanner-GAF5PO5F.js.map +1 -0
  222. package/dist/scanner-LKJKW7IT.mjs +4 -0
  223. package/dist/scanner-LKJKW7IT.mjs.map +1 -0
  224. package/dist/securityHeaders-nwZ6nP4g.d.mts +24 -0
  225. package/dist/securityHeaders-nwZ6nP4g.d.ts +24 -0
  226. package/dist/seo/index.d.mts +600 -0
  227. package/dist/seo/index.d.ts +600 -0
  228. package/dist/seo/index.js +883 -0
  229. package/dist/seo/index.js.map +1 -0
  230. package/dist/seo/index.mjs +773 -0
  231. package/dist/seo/index.mjs.map +1 -0
  232. package/dist/seo/register-sitemap-cli.js +151 -0
  233. package/dist/seo/register-sitemap-cli.js.map +1 -0
  234. package/dist/seo/register-sitemap-cli.mjs +144 -0
  235. package/dist/seo/register-sitemap-cli.mjs.map +1 -0
  236. package/dist/seo/server.d.mts +107 -0
  237. package/dist/seo/server.d.ts +107 -0
  238. package/dist/seo/server.js +207 -0
  239. package/dist/seo/server.js.map +1 -0
  240. package/dist/seo/server.mjs +186 -0
  241. package/dist/seo/server.mjs.map +1 -0
  242. package/dist/server-api-EWXKOQZA.mjs +4 -0
  243. package/dist/server-api-EWXKOQZA.mjs.map +1 -0
  244. package/dist/server-api-GJPNRYUP.js +81 -0
  245. package/dist/server-api-GJPNRYUP.js.map +1 -0
  246. package/dist/setup/client.d.mts +60 -0
  247. package/dist/setup/client.d.ts +60 -0
  248. package/dist/setup/client.js +31 -0
  249. package/dist/setup/client.js.map +1 -0
  250. package/dist/setup/client.mjs +6 -0
  251. package/dist/setup/client.mjs.map +1 -0
  252. package/dist/setup/index.d.mts +5 -0
  253. package/dist/setup/index.d.ts +5 -0
  254. package/dist/setup/index.js +35 -0
  255. package/dist/setup/index.js.map +1 -0
  256. package/dist/setup/index.mjs +6 -0
  257. package/dist/setup/index.mjs.map +1 -0
  258. package/dist/setup/server.d.mts +14 -0
  259. package/dist/setup/server.d.ts +14 -0
  260. package/dist/setup/server.js +13 -0
  261. package/dist/setup/server.js.map +1 -0
  262. package/dist/setup/server.mjs +4 -0
  263. package/dist/setup/server.mjs.map +1 -0
  264. package/dist/site-config/index.d.mts +24 -0
  265. package/dist/site-config/index.d.ts +24 -0
  266. package/dist/site-config/index.js +17 -0
  267. package/dist/site-config/index.js.map +1 -0
  268. package/dist/site-config/index.mjs +4 -0
  269. package/dist/site-config/index.mjs.map +1 -0
  270. package/dist/sitemap/index.d.mts +96 -0
  271. package/dist/sitemap/index.d.ts +96 -0
  272. package/dist/sitemap/index.js +288 -0
  273. package/dist/sitemap/index.js.map +1 -0
  274. package/dist/sitemap/index.mjs +285 -0
  275. package/dist/sitemap/index.mjs.map +1 -0
  276. package/dist/socket-loader-J26QHHOB.js +16 -0
  277. package/dist/socket-loader-J26QHHOB.js.map +1 -0
  278. package/dist/socket-loader-R7S2YJ2J.mjs +14 -0
  279. package/dist/socket-loader-R7S2YJ2J.mjs.map +1 -0
  280. package/dist/types-0dmq3k20.d.mts +168 -0
  281. package/dist/types-0dmq3k20.d.ts +168 -0
  282. package/dist/types-Blb2QNkV.d.mts +263 -0
  283. package/dist/types-Blb2QNkV.d.ts +263 -0
  284. package/dist/types-BnCwwUX3.d.mts +250 -0
  285. package/dist/types-BnCwwUX3.d.ts +250 -0
  286. package/dist/types-CGlnp43R.d.mts +312 -0
  287. package/dist/types-CGlnp43R.d.ts +312 -0
  288. package/dist/types-D08004rU.d.mts +179 -0
  289. package/dist/types-D08004rU.d.ts +179 -0
  290. package/dist/types-DNSYU7qI.d.mts +127 -0
  291. package/dist/types-DNSYU7qI.d.ts +127 -0
  292. package/dist/types-KZP_VWZp.d.mts +266 -0
  293. package/dist/types-KZP_VWZp.d.ts +266 -0
  294. package/dist/useEventModal-BVTx69XE.d.mts +274 -0
  295. package/dist/useEventModal-Dx1dItTJ.d.ts +274 -0
  296. package/dist/web-vitals-444RLW3B.js +252 -0
  297. package/dist/web-vitals-444RLW3B.js.map +1 -0
  298. package/dist/web-vitals-KPICZIEF.mjs +241 -0
  299. package/dist/web-vitals-KPICZIEF.mjs.map +1 -0
  300. package/package.json +192 -0
package/README.md ADDED
@@ -0,0 +1,376 @@
1
+ # @sonordev/site-kit
2
+
3
+ Complete client-side integration kit for Sonor. One package for SEO, Analytics, Engage widgets, Forms, and Blog - all managed from your Sonor dashboard.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @sonordev/site-kit
9
+ # or
10
+ pnpm add @sonordev/site-kit
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ Wrap your app with `SiteKitProvider` in your root layout:
16
+
17
+ ```tsx
18
+ // app/layout.tsx
19
+ import { SiteKitProvider } from '@sonordev/site-kit'
20
+
21
+ export default function RootLayout({ children }) {
22
+ return (
23
+ <html>
24
+ <body>
25
+ <SiteKitProvider
26
+ projectId={process.env.UPTRADE_PROJECT_ID!}
27
+ supabaseUrl={process.env.NEXT_PUBLIC_SUPABASE_URL!}
28
+ supabaseAnonKey={process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!}
29
+ analytics={{ enabled: true }}
30
+ engage={{ enabled: true }}
31
+ >
32
+ {children}
33
+ </SiteKitProvider>
34
+ </body>
35
+ </html>
36
+ )
37
+ }
38
+ ```
39
+
40
+ ## Modules
41
+
42
+ ### SEO (`@sonordev/site-kit/seo`)
43
+
44
+ Managed SEO components that automatically inject structured data, FAQs, internal links, and more based on your Portal configuration.
45
+
46
+ ```tsx
47
+ import { ManagedSchema, ManagedFAQ, ManagedInternalLinks } from '@sonordev/site-kit/seo'
48
+ import { getManagedMetadata, generateSitemap, generateRobots } from '@sonordev/site-kit/seo/server'
49
+
50
+ // In a page component
51
+ export async function generateMetadata({ params }) {
52
+ return getManagedMetadata('your-project-id', `/blog/${params.slug}`)
53
+ }
54
+
55
+ export default async function BlogPost({ params }) {
56
+ return (
57
+ <article>
58
+ <h1>My Blog Post</h1>
59
+ <p>Content...</p>
60
+
61
+ {/* Managed structured data */}
62
+ <ManagedSchema projectId="..." path="/blog/my-post" />
63
+
64
+ {/* Managed FAQ section */}
65
+ <ManagedFAQ projectId="..." path="/blog/my-post" />
66
+
67
+ {/* Managed internal links */}
68
+ <ManagedInternalLinks projectId="..." path="/blog/my-post" />
69
+ </article>
70
+ )
71
+ }
72
+ ```
73
+
74
+ ### Analytics (`@sonordev/site-kit/analytics`)
75
+
76
+ Automatic page view tracking, custom events, and Core Web Vitals reporting.
77
+
78
+ ```tsx
79
+ import { useAnalytics, WebVitals } from '@sonordev/site-kit/analytics'
80
+
81
+ export default function MyComponent() {
82
+ const { trackEvent, trackConversion } = useAnalytics()
83
+
84
+ const handleClick = () => {
85
+ trackEvent('button_click', { button: 'cta' })
86
+ }
87
+
88
+ const handlePurchase = () => {
89
+ trackConversion('purchase', 99.99)
90
+ }
91
+
92
+ return (
93
+ <>
94
+ <button onClick={handleClick}>CTA Button</button>
95
+ <WebVitals /> {/* Reports LCP, CLS, FID, etc. */}
96
+ </>
97
+ )
98
+ }
99
+ ```
100
+
101
+ ### Engage (`@sonordev/site-kit/engage`)
102
+
103
+ Popups, nudges, banners, and chat widgets configured from Portal.
104
+
105
+ ```tsx
106
+ import { EngageWidget, ChatWidget } from '@sonordev/site-kit/engage'
107
+
108
+ // Automatically included when engage.enabled = true in SiteKitProvider
109
+ // Or add manually:
110
+
111
+ export default function Layout({ children }) {
112
+ return (
113
+ <>
114
+ {children}
115
+ <EngageWidget projectId="..." />
116
+ <ChatWidget projectId="..." />
117
+ </>
118
+ )
119
+ }
120
+ ```
121
+
122
+ ### Forms (`@sonordev/site-kit/forms`)
123
+
124
+ Managed forms with automatic routing to CRM, Support, or other destinations.
125
+
126
+ ```tsx
127
+ import { ManagedForm } from '@sonordev/site-kit/forms'
128
+
129
+ // Basic usage - fetches form config from Portal
130
+ export default function ContactPage() {
131
+ return (
132
+ <ManagedForm
133
+ projectId="..."
134
+ formSlug="contact-form"
135
+ onSuccess={(data) => console.log('Submitted:', data)}
136
+ />
137
+ )
138
+ }
139
+
140
+ // Custom rendering
141
+ export default function CustomContactPage() {
142
+ return (
143
+ <ManagedForm
144
+ projectId="..."
145
+ formSlug="contact-form"
146
+ render={({ fields, step, totalSteps, values, errors, handleSubmit, isSubmitting }) => (
147
+ <form onSubmit={handleSubmit}>
148
+ {fields.map(field => (
149
+ <CustomField key={field.slug} {...field} />
150
+ ))}
151
+ <button disabled={isSubmitting}>Submit</button>
152
+ </form>
153
+ )}
154
+ />
155
+ )
156
+ }
157
+ ```
158
+
159
+ ### Blog (`@sonordev/site-kit/blog`)
160
+
161
+ Complete Portal-managed blog system with beautiful layouts, dynamic routing, categories, and SEO.
162
+
163
+ **Create posts in Portal → Automatically appear on your site.**
164
+
165
+ ```tsx
166
+ // app/blog/page.tsx - Blog Index
167
+ import { BlogList, BlogLayout } from '@sonordev/site-kit/blog'
168
+ import { generateBlogIndexMetadata } from '@sonordev/site-kit/blog/server'
169
+
170
+ export const metadata = generateBlogIndexMetadata({
171
+ title: 'Blog',
172
+ siteName: 'My Company',
173
+ siteUrl: 'https://example.com',
174
+ })
175
+
176
+ export default function BlogPage({ searchParams }) {
177
+ return (
178
+ <BlogLayout
179
+ hero={{ title: 'Blog', subtitle: 'Latest insights and articles' }}
180
+ layout="sidebar-right"
181
+ >
182
+ <BlogList
183
+ category={searchParams.category}
184
+ page={parseInt(searchParams.page || '1')}
185
+ showCategoryFilter
186
+ showPagination
187
+ />
188
+ </BlogLayout>
189
+ )
190
+ }
191
+ ```
192
+
193
+ ```tsx
194
+ // app/blog/[slug]/page.tsx - Individual Post
195
+ import { BlogPost } from '@sonordev/site-kit/blog'
196
+ import {
197
+ generateBlogPostMetadata,
198
+ generateBlogStaticParams,
199
+ getBlogPost,
200
+ generateBlogPostSchema
201
+ } from '@sonordev/site-kit/blog/server'
202
+
203
+ // Pre-generate all post pages at build time
204
+ export const generateStaticParams = generateBlogStaticParams
205
+
206
+ // Dynamic metadata for SEO
207
+ export async function generateMetadata({ params }) {
208
+ return generateBlogPostMetadata(params.slug, {
209
+ siteName: 'My Company',
210
+ siteUrl: 'https://example.com',
211
+ })
212
+ }
213
+
214
+ export default async function PostPage({ params }) {
215
+ const post = await getBlogPost(params.slug)
216
+
217
+ return (
218
+ <>
219
+ {/* JSON-LD Schema */}
220
+ <script
221
+ type="application/ld+json"
222
+ dangerouslySetInnerHTML={{
223
+ __html: JSON.stringify(generateBlogPostSchema(post, {
224
+ siteUrl: 'https://example.com',
225
+ siteName: 'My Company',
226
+ })),
227
+ }}
228
+ />
229
+
230
+ {/* Blog Post with TOC and Related Posts */}
231
+ <BlogPost
232
+ slug={params.slug}
233
+ showToc
234
+ showRelated
235
+ showAuthor
236
+ />
237
+ </>
238
+ )
239
+ }
240
+ ```
241
+
242
+ #### Available Components
243
+
244
+ | Component | Purpose |
245
+ |-----------|---------|
246
+ | `BlogList` | Grid of posts with pagination & category filter |
247
+ | `BlogPost` | Full post with TOC, author, related posts |
248
+ | `BlogLayout` | Complete layout with sidebar |
249
+ | `BlogSidebar` | Categories, recent posts, tags, search |
250
+ | `TableOfContents` | Sticky TOC from headings |
251
+ | `AuthorCard` | Author info with social links |
252
+ | `RelatedPosts` | Related posts by category |
253
+
254
+ #### Server Functions
255
+
256
+ ```tsx
257
+ import {
258
+ getBlogPost, // Fetch single post
259
+ getAllBlogSlugs, // For generateStaticParams
260
+ getBlogCategories, // All categories
261
+ generateBlogPostMetadata, // Post page metadata
262
+ generateBlogIndexMetadata, // Index page metadata
263
+ generateBlogStaticParams, // SSG params
264
+ generateBlogSitemap, // Sitemap entries
265
+ generateBlogPostSchema, // JSON-LD
266
+ } from '@sonordev/site-kit/blog/server'
267
+ ```
268
+
269
+ ## Configuration
270
+
271
+ ### Full Provider Options
272
+
273
+ ```tsx
274
+ <SiteKitProvider
275
+ // Required
276
+ projectId="your-project-id"
277
+ supabaseUrl="https://xxx.supabase.co"
278
+ supabaseAnonKey="your-anon-key"
279
+
280
+ // Analytics options
281
+ analytics={{
282
+ enabled: true,
283
+ trackPageViews: true, // Auto-track route changes
284
+ trackWebVitals: true, // Report Core Web Vitals
285
+ trackScrollDepth: false, // Track scroll milestones
286
+ sessionDuration: 30, // Session timeout in minutes
287
+ excludePaths: ['/admin'] // Don't track these paths
288
+ }}
289
+
290
+ // Engage widget options
291
+ engage={{
292
+ enabled: true,
293
+ position: 'bottom-right', // Widget position
294
+ zIndex: 9999,
295
+ chatEnabled: true // Enable AI/live chat
296
+ }}
297
+
298
+ // Forms options
299
+ forms={{
300
+ enabled: true,
301
+ honeypotField: '_hp' // Spam protection field name
302
+ }}
303
+
304
+ // Debug mode - logs to console
305
+ debug={false}
306
+ >
307
+ ```
308
+
309
+ ## Environment Variables
310
+
311
+ ```bash
312
+ # Required
313
+ UPTRADE_PROJECT_ID=your-project-id
314
+ NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
315
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
316
+ ```
317
+
318
+ ## Server-Side Utilities
319
+
320
+ ```tsx
321
+ // app/sitemap.ts
322
+ import { generateSitemap } from '@sonordev/site-kit/seo/server'
323
+
324
+ export default async function sitemap() {
325
+ return generateSitemap('your-project-id', 'https://yoursite.com')
326
+ }
327
+
328
+ // app/robots.ts
329
+ import { generateRobots } from '@sonordev/site-kit/seo/server'
330
+
331
+ export default async function robots() {
332
+ return generateRobots('your-project-id', 'https://yoursite.com')
333
+ }
334
+
335
+ // Redirect handling in middleware
336
+ import { handleRedirect } from '@sonordev/site-kit/seo/server'
337
+
338
+ export async function middleware(request) {
339
+ const redirect = await handleRedirect('your-project-id', request.nextUrl.pathname)
340
+ if (redirect) {
341
+ return NextResponse.redirect(new URL(redirect.to, request.url), redirect.statusCode)
342
+ }
343
+ }
344
+ ```
345
+
346
+ ## Form Routing
347
+
348
+ Forms automatically route submissions based on their type:
349
+
350
+ | Form Type | Routes To | Use Case |
351
+ |-----------|-----------|----------|
352
+ | `prospect` | CRM Leads | Sales inquiries, quote requests |
353
+ | `support` | Support Tickets | Help requests, bug reports |
354
+ | `feedback` | Feedback Entries | User feedback, suggestions |
355
+ | `newsletter` | Email Subscribers | Newsletter signups |
356
+ | `contact` | Form Submissions | General contact (no routing) |
357
+ | `custom` | Form Submissions | Custom handling |
358
+
359
+ ## TypeScript
360
+
361
+ All modules are fully typed:
362
+
363
+ ```tsx
364
+ import type {
365
+ SiteKitConfig,
366
+ ManagedMetadata,
367
+ AnalyticsEvent,
368
+ EngageElement,
369
+ ManagedFormConfig,
370
+ BlogPostType
371
+ } from '@sonordev/site-kit'
372
+ ```
373
+
374
+ ## License
375
+
376
+ MIT
@@ -0,0 +1,12 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface SetupWizardProps {
4
+ config?: {
5
+ url?: string;
6
+ anonKey?: string;
7
+ portalApiUrl?: string;
8
+ };
9
+ }
10
+ declare function SetupWizard({ config }?: SetupWizardProps): react_jsx_runtime.JSX.Element;
11
+
12
+ export { SetupWizard as S };
@@ -0,0 +1,12 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface SetupWizardProps {
4
+ config?: {
5
+ url?: string;
6
+ anonKey?: string;
7
+ portalApiUrl?: string;
8
+ };
9
+ }
10
+ declare function SetupWizard({ config }?: SetupWizardProps): react_jsx_runtime.JSX.Element;
11
+
12
+ export { SetupWizard as S };
@@ -0,0 +1,93 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React__default from 'react';
3
+ import { A as AnalyticsContextValue, T as TrackEventOptions, a as TrackConversionOptions } from '../types-DNSYU7qI.mjs';
4
+ export { c as AnalyticsConfig, b as AnalyticsEvent, C as Conversion, P as PageView, S as Session, W as WebVitalsData } from '../types-DNSYU7qI.mjs';
5
+
6
+ interface AnalyticsProviderProps {
7
+ children: React__default.ReactNode;
8
+ apiUrl?: string;
9
+ apiKey?: string;
10
+ trackPageViews?: boolean;
11
+ trackWebVitals?: boolean;
12
+ trackScrollDepth?: boolean;
13
+ trackClicks?: boolean;
14
+ trackJourneys?: boolean;
15
+ sessionTimeout?: number;
16
+ excludePaths?: string[];
17
+ validateAgainstSitemap?: boolean;
18
+ debug?: boolean;
19
+ /** External visitor ID from shared identity (used by SiteKitLayout) */
20
+ externalVisitorId?: string;
21
+ /** External session ID from shared identity (used by SiteKitLayout) */
22
+ externalSessionId?: string;
23
+ /** Callback invoked with page metadata after each page view (used by Signal bridge) */
24
+ onPageMetadata?: (metadata: Record<string, unknown>) => void;
25
+ }
26
+ declare function AnalyticsProvider({ children, apiUrl: propApiUrl, apiKey: propApiKey, trackPageViews, trackWebVitals, trackScrollDepth, trackClicks, trackJourneys, // NEW: Enable journey tracking by default
27
+ sessionTimeout, excludePaths, validateAgainstSitemap, debug, externalVisitorId, externalSessionId, onPageMetadata, }: AnalyticsProviderProps): react_jsx_runtime.JSX.Element;
28
+ declare function useAnalytics(): AnalyticsContextValue;
29
+ declare function useTrackEvent(): {
30
+ trackEvent: (options: TrackEventOptions) => void;
31
+ trackConversion: (options: TrackConversionOptions) => void;
32
+ };
33
+
34
+ /**
35
+ * @sonordev/site-kit/analytics - Web Vitals Component
36
+ *
37
+ * Automatically reports Core Web Vitals via Portal API
38
+ */
39
+ interface WebVitalsProps {
40
+ apiUrl?: string;
41
+ apiKey?: string;
42
+ debug?: boolean;
43
+ }
44
+ declare function WebVitals({ apiUrl: propApiUrl, apiKey: propApiKey, debug }: WebVitalsProps): null;
45
+
46
+ /**
47
+ * @sonordev/site-kit/analytics - Contact Tracking Hook
48
+ *
49
+ * Tracks phone calls and email clicks as conversions.
50
+ * Use this hook to automatically track tel: and mailto: links,
51
+ * or manually track contact interactions.
52
+ */
53
+ interface UseContactTrackingOptions {
54
+ /** Automatically track all tel: and mailto: links (default: true) */
55
+ autoTrack?: boolean;
56
+ /** Debug mode - logs events to console */
57
+ debug?: boolean;
58
+ }
59
+ interface ContactTrackingReturn {
60
+ /** Manually track a phone call click */
61
+ trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void;
62
+ /** Manually track an email click */
63
+ trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void;
64
+ }
65
+ /**
66
+ * Hook for tracking phone and email contact interactions as conversions.
67
+ *
68
+ * @example
69
+ * ```tsx
70
+ * // Auto-track all tel: and mailto: links
71
+ * useContactTracking()
72
+ *
73
+ * // Manual tracking
74
+ * const { trackPhoneClick, trackEmailClick } = useContactTracking()
75
+ * trackPhoneClick('513-555-1234')
76
+ * trackEmailClick('hello@example.com')
77
+ * ```
78
+ */
79
+ declare function useContactTracking(options?: UseContactTrackingOptions): ContactTrackingReturn;
80
+ /**
81
+ * Component wrapper for contact tracking
82
+ * Simply include this component to auto-track all tel: and mailto: links
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * <ContactTracking />
87
+ * ```
88
+ */
89
+ declare function ContactTracking({ debug }: {
90
+ debug?: boolean;
91
+ }): null;
92
+
93
+ export { AnalyticsContextValue, AnalyticsProvider, ContactTracking, TrackConversionOptions, TrackEventOptions, WebVitals, useAnalytics, useContactTracking, useTrackEvent };
@@ -0,0 +1,93 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React__default from 'react';
3
+ import { A as AnalyticsContextValue, T as TrackEventOptions, a as TrackConversionOptions } from '../types-DNSYU7qI.js';
4
+ export { c as AnalyticsConfig, b as AnalyticsEvent, C as Conversion, P as PageView, S as Session, W as WebVitalsData } from '../types-DNSYU7qI.js';
5
+
6
+ interface AnalyticsProviderProps {
7
+ children: React__default.ReactNode;
8
+ apiUrl?: string;
9
+ apiKey?: string;
10
+ trackPageViews?: boolean;
11
+ trackWebVitals?: boolean;
12
+ trackScrollDepth?: boolean;
13
+ trackClicks?: boolean;
14
+ trackJourneys?: boolean;
15
+ sessionTimeout?: number;
16
+ excludePaths?: string[];
17
+ validateAgainstSitemap?: boolean;
18
+ debug?: boolean;
19
+ /** External visitor ID from shared identity (used by SiteKitLayout) */
20
+ externalVisitorId?: string;
21
+ /** External session ID from shared identity (used by SiteKitLayout) */
22
+ externalSessionId?: string;
23
+ /** Callback invoked with page metadata after each page view (used by Signal bridge) */
24
+ onPageMetadata?: (metadata: Record<string, unknown>) => void;
25
+ }
26
+ declare function AnalyticsProvider({ children, apiUrl: propApiUrl, apiKey: propApiKey, trackPageViews, trackWebVitals, trackScrollDepth, trackClicks, trackJourneys, // NEW: Enable journey tracking by default
27
+ sessionTimeout, excludePaths, validateAgainstSitemap, debug, externalVisitorId, externalSessionId, onPageMetadata, }: AnalyticsProviderProps): react_jsx_runtime.JSX.Element;
28
+ declare function useAnalytics(): AnalyticsContextValue;
29
+ declare function useTrackEvent(): {
30
+ trackEvent: (options: TrackEventOptions) => void;
31
+ trackConversion: (options: TrackConversionOptions) => void;
32
+ };
33
+
34
+ /**
35
+ * @sonordev/site-kit/analytics - Web Vitals Component
36
+ *
37
+ * Automatically reports Core Web Vitals via Portal API
38
+ */
39
+ interface WebVitalsProps {
40
+ apiUrl?: string;
41
+ apiKey?: string;
42
+ debug?: boolean;
43
+ }
44
+ declare function WebVitals({ apiUrl: propApiUrl, apiKey: propApiKey, debug }: WebVitalsProps): null;
45
+
46
+ /**
47
+ * @sonordev/site-kit/analytics - Contact Tracking Hook
48
+ *
49
+ * Tracks phone calls and email clicks as conversions.
50
+ * Use this hook to automatically track tel: and mailto: links,
51
+ * or manually track contact interactions.
52
+ */
53
+ interface UseContactTrackingOptions {
54
+ /** Automatically track all tel: and mailto: links (default: true) */
55
+ autoTrack?: boolean;
56
+ /** Debug mode - logs events to console */
57
+ debug?: boolean;
58
+ }
59
+ interface ContactTrackingReturn {
60
+ /** Manually track a phone call click */
61
+ trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void;
62
+ /** Manually track an email click */
63
+ trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void;
64
+ }
65
+ /**
66
+ * Hook for tracking phone and email contact interactions as conversions.
67
+ *
68
+ * @example
69
+ * ```tsx
70
+ * // Auto-track all tel: and mailto: links
71
+ * useContactTracking()
72
+ *
73
+ * // Manual tracking
74
+ * const { trackPhoneClick, trackEmailClick } = useContactTracking()
75
+ * trackPhoneClick('513-555-1234')
76
+ * trackEmailClick('hello@example.com')
77
+ * ```
78
+ */
79
+ declare function useContactTracking(options?: UseContactTrackingOptions): ContactTrackingReturn;
80
+ /**
81
+ * Component wrapper for contact tracking
82
+ * Simply include this component to auto-track all tel: and mailto: links
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * <ContactTracking />
87
+ * ```
88
+ */
89
+ declare function ContactTracking({ debug }: {
90
+ debug?: boolean;
91
+ }): null;
92
+
93
+ export { AnalyticsContextValue, AnalyticsProvider, ContactTracking, TrackConversionOptions, TrackEventOptions, WebVitals, useAnalytics, useContactTracking, useTrackEvent };
@@ -0,0 +1,89 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ var chunkWECQ6KOB_js = require('../chunk-WECQ6KOB.js');
5
+ require('../chunk-ZSMWDLMK.js');
6
+ var react = require('react');
7
+
8
+ function useContactTracking(options = {}) {
9
+ const { autoTrack = true, debug = false } = options;
10
+ const { trackConversion } = chunkWECQ6KOB_js.useAnalytics();
11
+ const trackPhoneClick = react.useCallback((phoneNumber, metadata) => {
12
+ if (debug) console.log("[Analytics] Phone click:", phoneNumber);
13
+ trackConversion({
14
+ type: "phone_call",
15
+ metadata: {
16
+ phoneNumber: phoneNumber.replace(/\D/g, ""),
17
+ // Normalize to digits
18
+ rawNumber: phoneNumber,
19
+ ...metadata
20
+ }
21
+ });
22
+ }, [trackConversion, debug]);
23
+ const trackEmailClick = react.useCallback((email, metadata) => {
24
+ if (debug) console.log("[Analytics] Email click:", email);
25
+ trackConversion({
26
+ type: "email_click",
27
+ metadata: {
28
+ email,
29
+ ...metadata
30
+ }
31
+ });
32
+ }, [trackConversion, debug]);
33
+ react.useEffect(() => {
34
+ if (!autoTrack || typeof document === "undefined") return;
35
+ const handleClick = (e) => {
36
+ const target = e.target;
37
+ const anchor = target.closest("a");
38
+ if (!anchor) return;
39
+ const href = anchor.getAttribute("href");
40
+ if (!href) return;
41
+ if (href.startsWith("tel:")) {
42
+ const phone = href.replace("tel:", "").trim();
43
+ trackPhoneClick(phone, {
44
+ linkText: anchor.textContent?.trim(),
45
+ source: "auto"
46
+ });
47
+ } else if (href.startsWith("mailto:")) {
48
+ const email = href.replace("mailto:", "").split("?")[0].trim();
49
+ trackEmailClick(email, {
50
+ linkText: anchor.textContent?.trim(),
51
+ source: "auto"
52
+ });
53
+ }
54
+ };
55
+ document.addEventListener("click", handleClick, { capture: true });
56
+ return () => {
57
+ document.removeEventListener("click", handleClick, { capture: true });
58
+ };
59
+ }, [autoTrack, trackPhoneClick, trackEmailClick]);
60
+ return {
61
+ trackPhoneClick,
62
+ trackEmailClick
63
+ };
64
+ }
65
+ function ContactTracking({ debug = false }) {
66
+ useContactTracking({ autoTrack: true, debug });
67
+ return null;
68
+ }
69
+
70
+ Object.defineProperty(exports, "AnalyticsProvider", {
71
+ enumerable: true,
72
+ get: function () { return chunkWECQ6KOB_js.AnalyticsProvider; }
73
+ });
74
+ Object.defineProperty(exports, "WebVitals", {
75
+ enumerable: true,
76
+ get: function () { return chunkWECQ6KOB_js.WebVitals; }
77
+ });
78
+ Object.defineProperty(exports, "useAnalytics", {
79
+ enumerable: true,
80
+ get: function () { return chunkWECQ6KOB_js.useAnalytics; }
81
+ });
82
+ Object.defineProperty(exports, "useTrackEvent", {
83
+ enumerable: true,
84
+ get: function () { return chunkWECQ6KOB_js.useTrackEvent; }
85
+ });
86
+ exports.ContactTracking = ContactTracking;
87
+ exports.useContactTracking = useContactTracking;
88
+ //# sourceMappingURL=index.js.map
89
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/analytics/useContactTracking.ts"],"names":["useAnalytics","useCallback","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @sonordev/site-kit/analytics - Contact Tracking Hook\n * \n * Tracks phone calls and email clicks as conversions.\n * Use this hook to automatically track tel: and mailto: links,\n * or manually track contact interactions.\n */\n\n'use client'\n\nimport { useCallback, useEffect } from 'react'\nimport { useAnalytics } from './AnalyticsProvider'\n\nexport interface UseContactTrackingOptions {\n /** Automatically track all tel: and mailto: links (default: true) */\n autoTrack?: boolean\n /** Debug mode - logs events to console */\n debug?: boolean\n}\n\nexport interface ContactTrackingReturn {\n /** Manually track a phone call click */\n trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void\n /** Manually track an email click */\n trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void\n}\n\n/**\n * Hook for tracking phone and email contact interactions as conversions.\n * \n * @example\n * ```tsx\n * // Auto-track all tel: and mailto: links\n * useContactTracking()\n * \n * // Manual tracking\n * const { trackPhoneClick, trackEmailClick } = useContactTracking()\n * trackPhoneClick('513-555-1234')\n * trackEmailClick('hello@example.com')\n * ```\n */\nexport function useContactTracking(options: UseContactTrackingOptions = {}): ContactTrackingReturn {\n const { autoTrack = true, debug = false } = options\n const { trackConversion } = useAnalytics()\n \n const trackPhoneClick = useCallback((phoneNumber: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Phone click:', phoneNumber)\n \n trackConversion({\n type: 'phone_call',\n metadata: {\n phoneNumber: phoneNumber.replace(/\\D/g, ''), // Normalize to digits\n rawNumber: phoneNumber,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n const trackEmailClick = useCallback((email: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Email click:', email)\n \n trackConversion({\n type: 'email_click',\n metadata: {\n email,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n // Auto-track tel: and mailto: links\n useEffect(() => {\n if (!autoTrack || typeof document === 'undefined') return\n \n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n const anchor = target.closest('a')\n if (!anchor) return\n \n const href = anchor.getAttribute('href')\n if (!href) return\n \n if (href.startsWith('tel:')) {\n const phone = href.replace('tel:', '').trim()\n trackPhoneClick(phone, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n } else if (href.startsWith('mailto:')) {\n const email = href.replace('mailto:', '').split('?')[0].trim()\n trackEmailClick(email, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n }\n }\n \n document.addEventListener('click', handleClick, { capture: true })\n \n return () => {\n document.removeEventListener('click', handleClick, { capture: true })\n }\n }, [autoTrack, trackPhoneClick, trackEmailClick])\n \n return {\n trackPhoneClick,\n trackEmailClick,\n }\n}\n\n/**\n * Component wrapper for contact tracking\n * Simply include this component to auto-track all tel: and mailto: links\n * \n * @example\n * ```tsx\n * <ContactTracking />\n * ```\n */\nexport function ContactTracking({ debug = false }: { debug?: boolean }) {\n useContactTracking({ autoTrack: true, debug })\n return null\n}\n"]}