@sonordev/site-kit 1.5.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AnalyticsProvider-J7UMCBCJ.mjs +4 -0
- package/dist/{AnalyticsProvider-BBLU4U2T.mjs.map → AnalyticsProvider-J7UMCBCJ.mjs.map} +1 -1
- package/dist/AnalyticsProvider-PPDJIGWY.js +25 -0
- package/dist/{AnalyticsProvider-EMDIAAWR.js.map → AnalyticsProvider-PPDJIGWY.js.map} +1 -1
- package/dist/EngageWidget-IDBEBGQR.js +13 -0
- package/dist/{EngageWidget-T2S5WUMJ.js.map → EngageWidget-IDBEBGQR.js.map} +1 -1
- package/dist/EngageWidget-SRRI4W7U.mjs +4 -0
- package/dist/{EngageWidget-RWBCI4RM.mjs.map → EngageWidget-SRRI4W7U.mjs.map} +1 -1
- package/dist/SignalBridge-D6W6OLVG.mjs +4 -0
- package/dist/{SignalBridge-WGHMEILW.mjs.map → SignalBridge-D6W6OLVG.mjs.map} +1 -1
- package/dist/SignalBridge-THATXU2R.js +33 -0
- package/dist/{SignalBridge-6UYUZ2CN.js.map → SignalBridge-THATXU2R.js.map} +1 -1
- package/dist/analytics/index.js +9 -9
- package/dist/analytics/index.mjs +2 -2
- package/dist/blog/index.js +75 -75
- package/dist/blog/index.js.map +1 -1
- package/dist/blog/index.mjs +75 -75
- package/dist/blog/index.mjs.map +1 -1
- package/dist/blog/server.js +2 -2
- package/dist/blog/server.js.map +1 -1
- package/dist/blog/server.mjs +2 -2
- package/dist/blog/server.mjs.map +1 -1
- package/dist/brand.css +87 -0
- package/dist/{chunk-ZU6YPEAF.mjs → chunk-2OJCYWSQ.mjs} +85 -73
- package/dist/chunk-2OJCYWSQ.mjs.map +1 -0
- package/dist/{chunk-PM2KQ6YK.mjs → chunk-3CXAWGUP.mjs} +3 -3
- package/dist/{chunk-PM2KQ6YK.mjs.map → chunk-3CXAWGUP.mjs.map} +1 -1
- package/dist/{chunk-36Y7OWES.mjs → chunk-3YQCPLGP.mjs} +4 -4
- package/dist/chunk-3YQCPLGP.mjs.map +1 -0
- package/dist/{chunk-DK2WNYQA.js → chunk-6ZGM7S5O.js} +108 -86
- package/dist/chunk-6ZGM7S5O.js.map +1 -0
- package/dist/{chunk-XFOL6JDF.mjs → chunk-7LAOWIWE.mjs} +4 -4
- package/dist/chunk-7LAOWIWE.mjs.map +1 -0
- package/dist/{chunk-YBTYDBWY.js → chunk-7M3FNAS5.js} +6 -8
- package/dist/chunk-7M3FNAS5.js.map +1 -0
- package/dist/{chunk-4QHHFCAA.mjs → chunk-AOIG5PVY.mjs} +6 -8
- package/dist/chunk-AOIG5PVY.mjs.map +1 -0
- package/dist/{chunk-VZMDH3R4.mjs → chunk-B22WSN4L.mjs} +4 -4
- package/dist/chunk-B22WSN4L.mjs.map +1 -0
- package/dist/{chunk-ELDJDBQL.js → chunk-BVUOATPG.js} +7 -7
- package/dist/chunk-BVUOATPG.js.map +1 -0
- package/dist/{chunk-N24BPFF6.mjs → chunk-CU6OGBKK.mjs} +6 -6
- package/dist/chunk-CU6OGBKK.mjs.map +1 -0
- package/dist/{chunk-NRNK7LXK.mjs → chunk-DWI5ZKPM.mjs} +4 -4
- package/dist/chunk-DWI5ZKPM.mjs.map +1 -0
- package/dist/{chunk-KRPFLF62.mjs → chunk-F5NXD7VQ.mjs} +10 -12
- package/dist/{chunk-KRPFLF62.mjs.map → chunk-F5NXD7VQ.mjs.map} +1 -1
- package/dist/{chunk-PTTDKFL7.js → chunk-FCXQECM7.js} +6 -6
- package/dist/chunk-FCXQECM7.js.map +1 -0
- package/dist/{chunk-DY4K6X3A.js → chunk-GCPPXUAI.js} +6 -6
- package/dist/chunk-GCPPXUAI.js.map +1 -0
- package/dist/{chunk-KJN2C6YE.js → chunk-I34XL5VJ.js} +5 -5
- package/dist/chunk-I34XL5VJ.js.map +1 -0
- package/dist/{chunk-G6VGUAK2.js → chunk-IFVMZFNT.js} +4 -4
- package/dist/chunk-IFVMZFNT.js.map +1 -0
- package/dist/{chunk-FMB2RZDH.mjs → chunk-J4U3IEXL.mjs} +6 -6
- package/dist/chunk-J4U3IEXL.mjs.map +1 -0
- package/dist/{chunk-EUNL6GAL.js → chunk-JP5WGL75.js} +4 -4
- package/dist/chunk-JP5WGL75.js.map +1 -0
- package/dist/{chunk-MG23BS36.js → chunk-L3UB4B74.js} +5 -5
- package/dist/chunk-L3UB4B74.js.map +1 -0
- package/dist/{chunk-VZMRZQ2D.mjs → chunk-MSRLAD7F.mjs} +107 -86
- package/dist/chunk-MSRLAD7F.mjs.map +1 -0
- package/dist/{chunk-M5FLRLHI.mjs → chunk-OM6R7CDP.mjs} +3 -3
- package/dist/chunk-OM6R7CDP.mjs.map +1 -0
- package/dist/{chunk-4X5TFGKD.mjs → chunk-P3POHQWW.mjs} +422 -426
- package/dist/chunk-P3POHQWW.mjs.map +1 -0
- package/dist/{chunk-GJD4CFHN.js → chunk-RLNG67S5.js} +7 -7
- package/dist/chunk-RLNG67S5.js.map +1 -0
- package/dist/{chunk-FTSXKDP3.js → chunk-RO6DHV6S.js} +10 -12
- package/dist/{chunk-FTSXKDP3.js.map → chunk-RO6DHV6S.js.map} +1 -1
- package/dist/{chunk-WW7UM7XY.js → chunk-TZAD7CZD.js} +424 -428
- package/dist/chunk-TZAD7CZD.js.map +1 -0
- package/dist/{chunk-OE5DEMCV.js → chunk-UD5447TC.js} +13 -15
- package/dist/chunk-UD5447TC.js.map +1 -0
- package/dist/{chunk-TC6TOW2T.js → chunk-UJ757WGI.js} +4 -4
- package/dist/{chunk-TC6TOW2T.js.map → chunk-UJ757WGI.js.map} +1 -1
- package/dist/{chunk-C3A5HXHX.mjs → chunk-V6V6OXS2.mjs} +5 -5
- package/dist/chunk-V6V6OXS2.mjs.map +1 -0
- package/dist/{chunk-X4J33XQD.js → chunk-W6K7MQCC.js} +6 -6
- package/dist/chunk-W6K7MQCC.js.map +1 -0
- package/dist/{chunk-FI2ME55T.mjs → chunk-W7RZ3OTA.mjs} +7 -7
- package/dist/chunk-W7RZ3OTA.mjs.map +1 -0
- package/dist/{chunk-IJ2LWZID.js → chunk-WETCVFIK.js} +85 -73
- package/dist/chunk-WETCVFIK.js.map +1 -0
- package/dist/{chunk-35MALWVX.mjs → chunk-WN2PUL6B.mjs} +13 -15
- package/dist/chunk-WN2PUL6B.mjs.map +1 -0
- package/dist/cli/index.js +19339 -3461
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +19331 -3452
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cms/index.d.mts +1 -1
- package/dist/cms/index.d.ts +1 -1
- package/dist/cms/index.js +3 -3
- package/dist/cms/index.js.map +1 -1
- package/dist/cms/index.mjs +2 -2
- package/dist/cms/index.mjs.map +1 -1
- package/dist/cms/server.js +4 -4
- package/dist/cms/server.mjs +1 -1
- package/dist/commerce/index.js +47 -47
- package/dist/commerce/index.mjs +3 -3
- package/dist/engage/index.d.mts +3 -2
- package/dist/engage/index.d.ts +3 -2
- package/dist/engage/index.js +6 -6
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +3 -3
- package/dist/engage/index.mjs.map +1 -1
- package/dist/forms/index.js +379 -84
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +375 -65
- package/dist/forms/index.mjs.map +1 -1
- package/dist/forms/styles.css +312 -0
- package/dist/images/index.js +11 -11
- package/dist/images/index.mjs +2 -2
- package/dist/images/server.js +4 -4
- package/dist/images/server.mjs +1 -1
- package/dist/index.d.mts +4 -131
- package/dist/index.d.ts +4 -131
- package/dist/index.js +85 -1373
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -1294
- package/dist/index.mjs.map +1 -1
- package/dist/layout/client.js +2 -2
- package/dist/layout/client.mjs +1 -1
- package/dist/layout/index.js +21 -11
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/index.mjs +17 -7
- package/dist/layout/index.mjs.map +1 -1
- package/dist/llms/index.d.mts +3 -3
- package/dist/llms/index.d.ts +3 -3
- package/dist/llms/index.js +12 -12
- package/dist/llms/index.js.map +1 -1
- package/dist/llms/index.mjs +2 -2
- package/dist/llms/index.mjs.map +1 -1
- package/dist/manifest/index.js +4 -4
- package/dist/manifest/index.js.map +1 -1
- package/dist/manifest/index.mjs +3 -3
- package/dist/manifest/index.mjs.map +1 -1
- package/dist/middleware/index.js +3 -3
- package/dist/middleware/index.mjs +2 -2
- package/dist/redirects/index.js +6 -6
- package/dist/redirects/index.mjs +2 -2
- package/dist/robots/index.js +3 -3
- package/dist/robots/index.js.map +1 -1
- package/dist/robots/index.mjs +2 -2
- package/dist/robots/index.mjs.map +1 -1
- package/dist/{routing-DZYzyDHw.d.ts → routing-DQ_Et-OP.d.mts} +4 -4
- package/dist/{routing-B5XS-6_W.d.mts → routing-IYiJNIIX.d.ts} +4 -4
- package/dist/seo/index.d.mts +3 -5
- package/dist/seo/index.d.ts +3 -5
- package/dist/seo/index.js +77 -76
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +41 -40
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo/register-sitemap-cli.js +3 -3
- package/dist/seo/register-sitemap-cli.js.map +1 -1
- package/dist/seo/register-sitemap-cli.mjs +3 -3
- package/dist/seo/register-sitemap-cli.mjs.map +1 -1
- package/dist/seo/server.d.mts +3 -3
- package/dist/seo/server.d.ts +3 -3
- package/dist/seo/server.js +7 -7
- package/dist/seo/server.js.map +1 -1
- package/dist/seo/server.mjs +5 -5
- package/dist/seo/server.mjs.map +1 -1
- package/dist/{server-api-XGKRGUMG.js → server-api-36R24YWN.js} +21 -21
- package/dist/{server-api-XGKRGUMG.js.map → server-api-36R24YWN.js.map} +1 -1
- package/dist/{server-api-COVFLFZ2.mjs → server-api-UIZU4JM3.mjs} +3 -3
- package/dist/{server-api-COVFLFZ2.mjs.map → server-api-UIZU4JM3.mjs.map} +1 -1
- package/dist/setup/index.d.mts +2 -5
- package/dist/setup/index.d.ts +2 -5
- package/dist/setup/index.js +0 -31
- package/dist/setup/index.mjs +1 -4
- package/dist/site-config/index.js +3 -3
- package/dist/site-config/index.mjs +1 -1
- package/dist/sitemap/index.js +10 -9
- package/dist/sitemap/index.js.map +1 -1
- package/dist/sitemap/index.mjs +8 -7
- package/dist/sitemap/index.mjs.map +1 -1
- package/dist/sync/index.js +13 -13
- package/dist/sync/index.mjs +1 -1
- package/dist/{types-KZP_VWZp.d.ts → types-CGkyylOa.d.mts} +2 -2
- package/dist/{types-KZP_VWZp.d.mts → types-CGkyylOa.d.ts} +2 -2
- package/package.json +6 -13
- package/dist/AnalyticsProvider-BBLU4U2T.mjs +0 -4
- package/dist/AnalyticsProvider-EMDIAAWR.js +0 -25
- package/dist/EngageWidget-RWBCI4RM.mjs +0 -4
- package/dist/EngageWidget-T2S5WUMJ.js +0 -13
- package/dist/SetupWizard-Cki06kB0.d.mts +0 -12
- package/dist/SetupWizard-Cki06kB0.d.ts +0 -12
- package/dist/SignalBridge-6UYUZ2CN.js +0 -33
- package/dist/SignalBridge-WGHMEILW.mjs +0 -4
- package/dist/chunk-35MALWVX.mjs.map +0 -1
- package/dist/chunk-36Y7OWES.mjs.map +0 -1
- package/dist/chunk-373TK6TZ.js +0 -321
- package/dist/chunk-373TK6TZ.js.map +0 -1
- package/dist/chunk-4MOJJSNA.js +0 -14867
- package/dist/chunk-4MOJJSNA.js.map +0 -1
- package/dist/chunk-4QHHFCAA.mjs.map +0 -1
- package/dist/chunk-4X5TFGKD.mjs.map +0 -1
- package/dist/chunk-5YDPPOUU.mjs +0 -810
- package/dist/chunk-5YDPPOUU.mjs.map +0 -1
- package/dist/chunk-7FKPJQVS.mjs +0 -289
- package/dist/chunk-7FKPJQVS.mjs.map +0 -1
- package/dist/chunk-C3A5HXHX.mjs.map +0 -1
- package/dist/chunk-DK2WNYQA.js.map +0 -1
- package/dist/chunk-DY4K6X3A.js.map +0 -1
- package/dist/chunk-ELDJDBQL.js.map +0 -1
- package/dist/chunk-EUNL6GAL.js.map +0 -1
- package/dist/chunk-FI2ME55T.mjs.map +0 -1
- package/dist/chunk-FMB2RZDH.mjs.map +0 -1
- package/dist/chunk-G6VGUAK2.js.map +0 -1
- package/dist/chunk-GJD4CFHN.js.map +0 -1
- package/dist/chunk-GVXZWXQ7.js +0 -814
- package/dist/chunk-GVXZWXQ7.js.map +0 -1
- package/dist/chunk-HF2FWDBJ.mjs +0 -968
- package/dist/chunk-HF2FWDBJ.mjs.map +0 -1
- package/dist/chunk-IFAW7JFO.js +0 -1429
- package/dist/chunk-IFAW7JFO.js.map +0 -1
- package/dist/chunk-IJ2LWZID.js.map +0 -1
- package/dist/chunk-IKIJEKU3.mjs +0 -1427
- package/dist/chunk-IKIJEKU3.mjs.map +0 -1
- package/dist/chunk-JFTGG6HK.mjs +0 -14848
- package/dist/chunk-JFTGG6HK.mjs.map +0 -1
- package/dist/chunk-JM3ZR6LB.js +0 -981
- package/dist/chunk-JM3ZR6LB.js.map +0 -1
- package/dist/chunk-KJN2C6YE.js.map +0 -1
- package/dist/chunk-M5FLRLHI.mjs.map +0 -1
- package/dist/chunk-MCGLYYAR.mjs +0 -341
- package/dist/chunk-MCGLYYAR.mjs.map +0 -1
- package/dist/chunk-MG23BS36.js.map +0 -1
- package/dist/chunk-N24BPFF6.mjs.map +0 -1
- package/dist/chunk-NRNK7LXK.mjs.map +0 -1
- package/dist/chunk-OE5DEMCV.js.map +0 -1
- package/dist/chunk-PTTDKFL7.js.map +0 -1
- package/dist/chunk-S7FRYNSU.mjs +0 -315
- package/dist/chunk-S7FRYNSU.mjs.map +0 -1
- package/dist/chunk-SLB5V4RT.js +0 -302
- package/dist/chunk-SLB5V4RT.js.map +0 -1
- package/dist/chunk-VZMDH3R4.mjs.map +0 -1
- package/dist/chunk-VZMRZQ2D.mjs.map +0 -1
- package/dist/chunk-WW7UM7XY.js.map +0 -1
- package/dist/chunk-X4J33XQD.js.map +0 -1
- package/dist/chunk-XFOL6JDF.mjs.map +0 -1
- package/dist/chunk-YBTYDBWY.js.map +0 -1
- package/dist/chunk-ZQO6FZZB.js +0 -343
- package/dist/chunk-ZQO6FZZB.js.map +0 -1
- package/dist/chunk-ZU6YPEAF.mjs.map +0 -1
- package/dist/generators-DOFWGRXS.js +0 -37
- package/dist/generators-DOFWGRXS.js.map +0 -1
- package/dist/generators-R62APO62.mjs +0 -4
- package/dist/generators-R62APO62.mjs.map +0 -1
- package/dist/migrator-3WQB3KQ2.mjs +0 -4
- package/dist/migrator-3WQB3KQ2.mjs.map +0 -1
- package/dist/migrator-HFVQYK5R.js +0 -37
- package/dist/migrator-HFVQYK5R.js.map +0 -1
- package/dist/scanner-AF7YUCFG.mjs +0 -4
- package/dist/scanner-AF7YUCFG.mjs.map +0 -1
- package/dist/scanner-DBD5K6F7.js +0 -53
- package/dist/scanner-DBD5K6F7.js.map +0 -1
- package/dist/setup/client.d.mts +0 -60
- package/dist/setup/client.d.ts +0 -60
- package/dist/setup/client.js +0 -31
- package/dist/setup/client.js.map +0 -1
- package/dist/setup/client.mjs +0 -6
- package/dist/setup/client.mjs.map +0 -1
- package/dist/setup/server.d.mts +0 -14
- package/dist/setup/server.d.ts +0 -14
- package/dist/setup/server.js +0 -13
- package/dist/setup/server.js.map +0 -1
- package/dist/setup/server.mjs +0 -4
- package/dist/setup/server.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cms/server-api.ts"],"names":["__require"],"mappings":"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","file":"chunk-MG23BS36.js","sourcesContent":["/**\n * @sonordev/site-kit/cms - Server-Only API Functions\n *\n * Fetches CMS page/section data from Portal API.\n * Uses the same secure API pattern as seo/server-api.ts.\n */\n\n// React.cache is available in React 19+ / Next.js RSC\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { cache } = require('react') as { cache: <T extends (...args: any[]) => any>(fn: T) => T }\nimport 'server-only'\nimport type { CmsPageData, CmsSectionData, CmsPageSeo } from './types'\n\n// ============================================\n// Server-Only API Config\n// ============================================\n\nfunction getSecureApiConfig() {\n const 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 const apiKey =\n process.env.SONOR_API_KEY ||\n process.env.UPTRADE_API_KEY ||\n process.env.NEXT_PUBLIC_UPTRADE_API_KEY ||\n ''\n\n if (!apiKey) {\n throw new Error(\n '@sonordev/site-kit/cms: SONOR_API_KEY (or UPTRADE_API_KEY) environment variable is required',\n )\n }\n\n return { apiUrl, apiKey }\n}\n\nasync function secureApiPost<T>(\n endpoint: string,\n body: Record<string, unknown> = {},\n): Promise<T | null> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n\n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(body),\n next: { revalidate: 60 },\n } as RequestInit)\n\n if (!response.ok) {\n let detail = response.statusText\n try {\n const err = await response.json().catch(() => ({}))\n if (err?.message) detail = err.message\n } catch {\n /* ignore */\n }\n console.error(\n `@sonordev/cms: API error ${response.status} ${endpoint}: ${detail}`,\n )\n return null\n }\n\n return await response.json()\n } catch (error) {\n console.error('@sonordev/cms: Network error:', error)\n return null\n }\n}\n\n// ============================================\n// Cached Data Fetchers\n// ============================================\n\n/**\n * Fetch a published CMS page by path — cached per request.\n * Returns the full page with all sections and their Portable Text content.\n * @server-only\n */\nexport const getCmsPage = cache(\n async (path: string): Promise<CmsPageData | null> => {\n const result = await secureApiPost<{\n found: boolean\n page: CmsPageData | null\n }>('/api/public/cms/page', { path })\n\n if (!result?.found || !result.page) return null\n return result.page\n },\n)\n\n/**\n * Fetch a single published CMS section by ID — cached per request.\n * @server-only\n */\nexport const getCmsSection = cache(\n async (sectionId: string): Promise<CmsSectionData | null> => {\n const result = await secureApiPost<{\n found: boolean\n section: CmsSectionData | null\n }>('/api/public/cms/section', { sectionId })\n\n if (!result?.found || !result.section) return null\n return result.section\n },\n)\n\n/**\n * Fetch CMS page and return Next.js Metadata object.\n * Use in generateMetadata() for CMS-managed pages.\n *\n * @example\n * ```ts\n * import { getCmsPageMetadata } from '@sonordev/site-kit/cms/server'\n *\n * export async function generateMetadata({ params }) {\n * return getCmsPageMetadata(`/${params.slug}`)\n * }\n * ```\n * @server-only\n */\nexport const getCmsPageMetadata = cache(\n async (\n path: string,\n ): Promise<{\n title?: string\n description?: string\n robots?: { index: boolean }\n openGraph?: { title?: string; description?: string }\n } | null> => {\n const page = await getCmsPage(path)\n if (!page) return null\n\n const seo: CmsPageSeo = page.seo || {}\n\n return {\n title: seo.title || page.title,\n description: seo.description,\n robots: seo.noindex ? { index: false } : undefined,\n openGraph: {\n title: seo.title || page.title,\n description: seo.description,\n },\n }\n },\n)\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/images/ManagedFavicon.tsx"],"names":[],"mappings":"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","file":"chunk-N24BPFF6.mjs","sourcesContent":["/**\n * ManagedFavicon Component\n * \n * Server component that renders favicon link tags using the project's logo.\n * When a logo is uploaded in Project Settings, it's automatically synced\n * to the 'favicon' slot in site_managed_images.\n * \n * Usage:\n * ```tsx\n * import { ManagedFavicon } from '@sonordev/site-kit/images'\n * \n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <head>\n * <ManagedFavicon />\n * </head>\n * <body>{children}</body>\n * </html>\n * )\n * }\n * ```\n * \n * Supports:\n * - SVG favicons (best for modern browsers, scales perfectly)\n * - PNG favicons with multiple sizes\n * - Apple touch icons\n * - Theme color for mobile browsers\n */\n\nimport React from 'react'\n\nexport interface ManagedFaviconProps {\n /**\n * API key for Portal API authentication\n * Defaults to SONOR_API_KEY env var\n */\n apiKey?: string\n \n /**\n * API URL (defaults to https://api.sonor.io)\n */\n apiUrl?: string\n \n /**\n * Fallback favicon URL if no managed favicon is set\n */\n fallback?: string\n \n /**\n * Theme color for mobile browser chrome\n * Defaults to #4bbf39 (Sonor brand primary)\n */\n themeColor?: string\n}\n\ninterface FaviconData {\n public_url?: string\n mime_type?: string\n is_placeholder?: boolean\n}\n\n/** If url is relative (e.g. /uploads/... from API), resolve against base so production can load it. */\nfunction toAbsoluteFaviconUrl(url: string | undefined, apiBase: string): string | undefined {\n if (!url) return undefined\n if (url.startsWith('http://') || url.startsWith('https://')) return url\n const base = apiBase.replace(/\\/$/, '')\n return url.startsWith('/') ? `${base}${url}` : `${base}/${url}`\n}\n\n/**\n * Server-side fetch of favicon data.\n * Exported for use in generateMetadata (single source for favicon URL).\n */\nexport async function fetchFaviconData(apiUrl: string, apiKey: string): Promise<FaviconData | null> {\n try {\n const res = await fetch(`${apiUrl}/public/images/slot/favicon`, {\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 3600 }, // Cache 1hr – favicon rarely changes, allows static generation\n })\n\n if (!res.ok) {\n console.warn('[ManagedFavicon] Failed to fetch:', res.status)\n return null\n }\n\n const data = await res.json()\n if (data.image && !data.is_placeholder) {\n const raw = data.image.public_url || data.image.external_url\n const public_url = toAbsoluteFaviconUrl(raw, apiUrl)\n return {\n public_url: public_url || undefined,\n mime_type: data.image.file?.mime_type,\n is_placeholder: false,\n }\n }\n return null\n } catch (err) {\n console.error('[ManagedFavicon] Error fetching favicon:', err)\n return null\n }\n}\n\n/**\n * Return the managed favicon URL for the project (from API key).\n * Use in generateMetadata to set metadata.icons so favicon is consistent across all sites.\n */\nexport async function getManagedFaviconUrl(\n apiKey?: string,\n apiUrl: string = process.env.SONOR_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || 'https://api.sonor.io'\n): Promise<string | null> {\n const key = apiKey ?? process.env.SONOR_API_KEY ?? process.env.UPTRADE_API_KEY ?? process.env.NEXT_PUBLIC_UPTRADE_API_KEY\n if (!key) return null\n const data = await fetchFaviconData(apiUrl, key)\n return data?.public_url ?? null\n}\n\nexport async function ManagedFavicon({\n apiKey = process.env.SONOR_API_KEY || process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY,\n apiUrl = process.env.SONOR_API_URL || process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || 'https://api.sonor.io',\n fallback = '/favicon.ico',\n themeColor = '#4bbf39',\n}: ManagedFaviconProps) {\n // Fetch favicon data during SSR\n const faviconData = apiKey && apiUrl ? await fetchFaviconData(apiUrl, apiKey) : null\n \n const faviconUrl = faviconData?.public_url || fallback\n const mimeType = faviconData?.mime_type || 'image/x-icon'\n const isSvg = mimeType === 'image/svg+xml' || faviconUrl.endsWith('.svg')\n\n return (\n <>\n {/* Primary favicon */}\n {isSvg ? (\n <link rel=\"icon\" type=\"image/svg+xml\" href={faviconUrl} />\n ) : (\n <>\n <link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href={faviconUrl} />\n <link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href={faviconUrl} />\n </>\n )}\n \n {/* Apple touch icon (for iOS home screen) */}\n <link rel=\"apple-touch-icon\" sizes=\"180x180\" href={faviconUrl} />\n \n {/* Theme color for mobile browsers */}\n <meta name=\"theme-color\" content={themeColor} />\n </>\n )\n}"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/seo/routing.ts"],"names":[],"mappings":"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","file":"chunk-NRNK7LXK.mjs","sourcesContent":["import { getRedirectData, getRobotsData, getSitemapEntries } from './server-api'\nimport type { \n GetRedirectOptions, \n RedirectResult, \n GetRobotsOptions, \n RobotsDirective,\n GetSitemapEntriesOptions,\n SitemapEntry \n} from './types'\n\n/**\n * Get redirect for a path if one exists\n * \n * Use in Next.js middleware to handle managed redirects\n * \n * @example\n * ```tsx\n * // middleware.ts\n * import { getRedirect } from '@sonordev/seo'\n * \n * export async function middleware(request) {\n * const redirect = await getRedirect({\n * projectId: process.env.UPTRADE_PROJECT_ID!,\n * path: request.nextUrl.pathname\n * })\n * \n * if (redirect) {\n * return NextResponse.redirect(redirect.destination, redirect.statusCode)\n * }\n * }\n * ```\n */\nexport async function getRedirect(\n options: GetRedirectOptions\n): Promise<RedirectResult | null> {\n const { path } = options\n\n const redirect = await getRedirectData(path)\n\n if (!redirect) {\n return null\n }\n\n // Check if expired\n if (redirect.expires_at && new Date(redirect.expires_at) < new Date()) {\n return null\n }\n\n // Determine destination\n const destination = redirect.destination_url || redirect.destination_path\n const isExternal = destination.startsWith('http://') || destination.startsWith('https://')\n\n return {\n destination,\n statusCode: redirect.status_code,\n isExternal,\n }\n}\n\n/**\n * Parse robots directive string into structured object\n */\nfunction parseRobotsString(robots: string): RobotsDirective {\n const directive: RobotsDirective = {\n index: true,\n follow: true,\n }\n\n const parts = robots.toLowerCase().split(',').map(p => p.trim())\n\n for (const part of parts) {\n if (part === 'noindex') directive.index = false\n if (part === 'nofollow') directive.follow = false\n if (part === 'noarchive') directive.noarchive = true\n if (part === 'nosnippet') directive.nosnippet = true\n if (part === 'noimageindex') directive.noimageindex = true\n if (part.startsWith('max-snippet:')) {\n directive.max_snippet = parseInt(part.split(':')[1], 10)\n }\n if (part.startsWith('max-image-preview:')) {\n const value = part.split(':')[1] as 'none' | 'standard' | 'large'\n directive.max_image_preview = value\n }\n if (part.startsWith('max-video-preview:')) {\n directive.max_video_preview = parseInt(part.split(':')[1], 10)\n }\n }\n\n return directive\n}\n\n/**\n * Get robots directive for a page\n * \n * @example\n * ```tsx\n * const robots = await getRobotsDirective({\n * projectId: process.env.UPTRADE_PROJECT_ID!,\n * path: '/private-page'\n * })\n * \n * if (!robots.index) {\n * // Page should not be indexed\n * }\n * ```\n */\nexport async function getRobotsDirective(\n options: GetRobotsOptions\n): Promise<RobotsDirective> {\n const { path } = options\n\n const robotsString = await getRobotsData(path)\n\n if (!robotsString) {\n // Default: index and follow\n return { index: true, follow: true }\n }\n\n return parseRobotsString(robotsString)\n}\n\n/**\n * Get sitemap entries for a project\n * \n * Use in sitemap.ts to generate dynamic sitemap\n * \n * @example\n * ```tsx\n * // app/sitemap.ts\n * import { generateSitemap } from '@sonordev/seo'\n * \n * export default async function sitemap() {\n * return generateSitemap({\n * projectId: process.env.UPTRADE_PROJECT_ID!,\n * baseUrl: 'https://example.com',\n * publishedOnly: true\n * })\n * }\n * ```\n */\nexport async function generateSitemap(\n options: GetSitemapEntriesOptions\n): Promise<SitemapEntry[]> {\n const { baseUrl, publishedOnly = true } = options\n\n const pages = await getSitemapEntries({ publishedOnly })\n\n const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n\n return pages.map((page: { path: string; lastmod?: string; changefreq?: string; priority?: number }) => ({\n path: page.path,\n url: `${normalizedBase}${page.path}`,\n lastmod: page.lastmod,\n changefreq: (page.changefreq || 'weekly') as SitemapEntry['changefreq'],\n priority: page.priority ?? 0.5,\n }))\n}\n\n/**\n * Register local sitemap entries with Sonor\n * \n * Call this at build time to sync your local routes to seo_pages.\n * This ensures analytics only tracks real pages.\n * \n * After registration, Signal AI will generate optimized meta titles\n * and descriptions for pages that don't have managed meta yet.\n * \n * @example\n * ```ts\n * // scripts/register-sitemap.ts\n * import { registerLocalSitemap } from '@sonordev/seo'\n * \n * // Option 1: Provide entries directly\n * await registerLocalSitemap({\n * entries: [\n * { path: '/', title: 'Home', priority: 1.0 },\n * { path: '/about', title: 'About Us', priority: 0.8 },\n * ]\n * })\n * \n * // Option 2: Auto-discover from Next.js app directory\n * await registerLocalSitemap({ autoDiscover: true })\n * \n * // Option 3: Skip Signal AI meta optimization\n * await registerLocalSitemap({ autoDiscover: true, optimize_meta: false })\n * ```\n */\nexport async function registerLocalSitemap(options: {\n entries?: Array<{\n path: string\n title?: string\n priority?: number\n changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'\n }>\n autoDiscover?: boolean\n /** Trigger Signal AI to generate optimized meta titles/descriptions (default: true) */\n optimize_meta?: boolean\n}): Promise<{ \n success: boolean\n created: number\n updated: number\n removed?: number\n meta_optimization?: {\n triggered: boolean\n pages_queued: number\n } | null\n}> {\n const { registerSitemap } = await import('./server-api')\n \n let entries = options.entries || []\n \n // Auto-discover from Next.js app directory if requested\n if (options.autoDiscover && entries.length === 0) {\n try {\n const fs = await import('fs')\n const path = await import('path')\n \n const appDir = path.join(process.cwd(), 'app')\n if (fs.existsSync(appDir)) {\n entries = discoverNextJsRoutes(appDir, fs, path)\n console.log(`[Sonor] Auto-discovered ${entries.length} routes from app directory`)\n }\n } catch (error) {\n console.error('[Sonor] Auto-discovery failed:', error)\n }\n }\n \n if (entries.length === 0) {\n console.warn('[Sonor] No sitemap entries to register')\n return { success: true, created: 0, updated: 0 }\n }\n \n console.log(`[Sonor] Registering ${entries.length} sitemap entries...`)\n const result = await registerSitemap(entries)\n \n if (result.success) {\n console.log(`[Sonor] Sitemap registered: ${result.created} new, ${result.updated} updated`)\n }\n \n return result\n}\n\n/**\n * Discover routes from Next.js app directory\n */\nfunction discoverNextJsRoutes(\n appDir: string,\n fs: typeof import('fs'),\n path: typeof import('path'),\n basePath: string = ''\n): Array<{ path: string; priority: number }> {\n const entries: Array<{ path: string; priority: number }> = []\n \n const items = fs.readdirSync(appDir, { withFileTypes: true })\n \n for (const item of items) {\n // Skip private folders, api routes, and special files\n if (item.name.startsWith('_') || item.name.startsWith('.')) continue\n if (item.name === 'api') continue\n if (item.name === 'node_modules') continue\n \n const itemPath = path.join(appDir, item.name)\n \n if (item.isDirectory()) {\n // Check for page.tsx/page.js in this directory\n const hasPage = fs.existsSync(path.join(itemPath, 'page.tsx')) ||\n fs.existsSync(path.join(itemPath, 'page.js')) ||\n fs.existsSync(path.join(itemPath, 'page.jsx'))\n \n // Handle route groups (parentheses)\n const isRouteGroup = item.name.startsWith('(') && item.name.endsWith(')')\n \n // Handle dynamic segments [slug]\n const isDynamic = item.name.startsWith('[') && item.name.endsWith(']')\n \n let routePath = basePath\n if (!isRouteGroup && !isDynamic) {\n routePath = `${basePath}/${item.name}`\n }\n \n if (hasPage && !isDynamic) {\n const priority = routePath === '' ? 1.0 : 0.8\n entries.push({ path: routePath || '/', priority })\n }\n \n // Recurse into subdirectories (but not dynamic ones)\n if (!isDynamic) {\n const subEntries = discoverNextJsRoutes(itemPath, fs, path, isRouteGroup ? basePath : routePath)\n entries.push(...subEntries)\n }\n }\n }\n \n // Add root if app/page.tsx exists and we're at root\n if (basePath === '') {\n const hasRootPage = fs.existsSync(path.join(appDir, 'page.tsx')) ||\n fs.existsSync(path.join(appDir, 'page.js')) ||\n fs.existsSync(path.join(appDir, 'page.jsx'))\n if (hasRootPage) {\n entries.unshift({ path: '/', priority: 1.0 })\n }\n }\n \n return entries\n}\n\n/**\n * Check if a path should be indexed\n * \n * Quick helper to check indexability without full directive parsing\n */\nexport async function isIndexable(\n projectId: string,\n path: string\n): Promise<boolean> {\n const directive = await getRobotsDirective({ projectId, path })\n return directive.index\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/identity.tsx","../src/layout/SiteKitClientProviders.tsx"],"names":["createContext","useMemo","jsx","dynamic","useState","useRef","useCallback","Fragment","Suspense","jsxs"],"mappings":";;;;;;;;;;;AAoBA,SAAS,UAAA,GAAqB;AAC5B,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,UAAA,EAAY;AACtD,IAAA,OAAO,OAAO,UAAA,EAAW;AAAA,EAC3B;AAEA,EAAA,OAAO,sCAAA,CAAuC,OAAA,CAAQ,OAAA,EAAS,CAAC,CAAA,KAAM;AACpE,IAAA,MAAM,CAAA,GAAK,IAAA,CAAK,MAAA,EAAO,GAAI,EAAA,GAAM,CAAA;AACjC,IAAA,OAAA,CAAQ,MAAM,GAAA,GAAM,CAAA,GAAK,IAAI,CAAA,GAAO,CAAA,EAAK,SAAS,EAAE,CAAA;AAAA,EACtD,CAAC,CAAA;AACH;AAMO,SAAS,oBAAA,GAA+B;AAC7C,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,EAAA;AAE1C,EAAA,MAAM,GAAA,GAAM,cAAA;AACZ,EAAA,IAAI,SAAA,GAAY,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAExC,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,SAAA,GAAY,UAAA,EAAW;AACvB,IAAA,YAAA,CAAa,OAAA,CAAQ,KAAK,SAAS,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO,SAAA;AACT;AAOO,SAAS,oBAAA,CAAqB,iBAAiB,EAAA,EAAY;AAChE,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,EAAA;AAE1C,EAAA,MAAM,GAAA,GAAM,cAAA;AACZ,EAAA,MAAM,OAAA,GAAU,gBAAA;AAChB,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,MAAM,SAAA,GAAY,iBAAiB,EAAA,GAAK,GAAA;AAExC,EAAA,MAAM,eAAA,GAAkB,cAAA,CAAe,OAAA,CAAQ,GAAG,CAAA;AAClD,EAAA,MAAM,YAAA,GAAe,cAAA,CAAe,OAAA,CAAQ,OAAO,CAAA;AAEnD,EAAA,IAAI,mBAAmB,YAAA,EAAc;AACnC,IAAA,MAAM,OAAA,GAAU,GAAA,GAAM,QAAA,CAAS,YAAA,EAAc,EAAE,CAAA;AAC/C,IAAA,IAAI,UAAU,SAAA,EAAW;AAEvB,MAAA,cAAA,CAAe,OAAA,CAAQ,OAAA,EAAS,GAAA,CAAI,QAAA,EAAU,CAAA;AAC9C,MAAA,OAAO,eAAA;AAAA,IACT;AAAA,EACF;AAGA,EAAA,MAAM,aAAa,UAAA,EAAW;AAC9B,EAAA,cAAA,CAAe,OAAA,CAAQ,KAAK,UAAU,CAAA;AACtC,EAAA,cAAA,CAAe,OAAA,CAAQ,OAAA,EAAS,GAAA,CAAI,QAAA,EAAU,CAAA;AAC9C,EAAA,OAAO,UAAA;AACT;AAWA,IAAM,sBAAA,GAAyBA,oBAAsC,IAAI,CAAA;AAQlE,SAAS,uBAAA,CAAwB;AAAA,EACtC,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAiC;AAC/B,EAAA,MAAM,KAAA,GAAQC,aAAA,CAAQ,OAAO,EAAE,SAAA,EAAW,WAAU,CAAA,EAAI,CAAC,SAAA,EAAW,SAAS,CAAC,CAAA;AAE9E,EAAA,uBACEC,cAAA,CAAC,sBAAA,CAAuB,QAAA,EAAvB,EAAgC,OAC9B,QAAA,EACH,CAAA;AAEJ;AChFA,IAAM,qBAAA,GAAwBC,wBAAA;AAAA,EAC5B,MAAM,OAAO,iCAAgC,CAAA,CAAE,IAAA,CAAK,QAAM,EAAE,OAAA,EAAS,CAAA,CAAE,iBAAA,EAAkB,CAAE,CAAA;AAAA,EAC3F,EAAE,KAAK,KAAA;AACT,CAAA;AACA,IAAM,gBAAA,GAAmBA,wBAAA;AAAA,EACvB,MAAM,OAAO,4BAAwB,CAAA,CAAE,IAAA,CAAK,QAAM,EAAE,OAAA,EAAS,CAAA,CAAE,YAAA,EAAa,CAAE,CAAA;AAAA,EAC9E,EAAE,KAAK,KAAA;AACT,CAAA;AACA,IAAM,gBAAA,GAAmBA,wBAAA;AAAA,EACvB,MAAM,OAAO,4BAAwB,CAAA,CAAE,IAAA,CAAK,QAAM,EAAE,OAAA,EAAS,CAAA,CAAE,YAAA,EAAa,CAAE,CAAA;AAAA,EAC9E,EAAE,KAAK,KAAA;AACT,CAAA;AACA,IAAM,eAAA,GAAkBA,wBAAA;AAAA,EACtB,MAAM,OAAO,2BAAgB,CAAA,CAAE,IAAA,CAAK,QAAM,EAAE,OAAA,EAAS,CAAA,CAAE,WAAA,EAAY,CAAE,CAAA;AAAA,EACrE,EAAE,KAAK,KAAA;AACT,CAAA;AAcO,SAAS,sBAAA,CAAuB;AAAA,EACrC,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,KAAA,GAAQ;AACV,CAAA,EAAgC;AAE9B,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAChC,IAAC,OAAe,oBAAA,GAAuB,MAAA;AACvC,IAAC,OAAe,oBAAA,GAAuB,MAAA;AACvC,IAAC,OAAe,kBAAA,GAAqB,KAAA;AAAA,EACxC;AAGA,EAAA,MAAM,CAAC,SAAS,CAAA,GAAIC,cAAA,CAAS,MAAM,sBAAsB,CAAA;AACzD,EAAA,MAAM,CAAC,SAAS,CAAA,GAAIA,cAAA,CAAS,MAAM,sBAAsB,CAAA;AAGzD,EAAA,MAAM,eAAA,GAAkBC,aAAuC,IAAI,CAAA;AACnE,EAAA,MAAM,cAAA,GAAiBC,iBAAA,CAAY,CAAC,QAAA,KAAsC;AACxE,IAAA,eAAA,CAAgB,OAAA,GAAU,QAAA;AAAA,EAC5B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,IAAI,OAAA,mBAAUJ,cAAAA,CAAAK,mBAAA,EAAA,EAAG,QAAA,EAAS,CAAA;AAG1B,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,YAAA,GACJ,OAAO,MAAA,KAAW,QAAA,GAAW,SAAS,EAAC;AACzC,IAAA,OAAA,mBACEL,cAAAA;AAAA,MAAC,gBAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAO,IAAA;AAAA,QACP,QAAA,EAAU,aAAa,QAAA,KAAa,KAAA;AAAA,QACpC,WAAA,EAAa,aAAa,WAAA,KAAgB,KAAA;AAAA,QAC1C,gBAAA,EAAkB,aAAa,gBAAA,KAAqB,KAAA;AAAA,QACpD,SAAA;AAAA,QACA,SAAA;AAAA,QACA,eAAA;AAAA,QAEC,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AAGA,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,MAAM,eAAA,GACJ,OAAO,SAAA,KAAc,QAAA,GAAW,YAAY,EAAC;AAC/C,IAAA,OAAA,mBACEA,cAAAA,CAACM,cAAA,EAAA,EAAS,QAAA,EAAU,MAClB,QAAA,kBAAAN,cAAAA;AAAA,MAAC,qBAAA;AAAA,MAAA;AAAA,QACC,MAAA;AAAA,QACA,MAAA;AAAA,QACA,cAAA,EAAgB,gBAAgB,cAAA,KAAmB,KAAA;AAAA,QACnD,cAAA,EAAgB,gBAAgB,cAAA,KAAmB,KAAA;AAAA,QACnD,gBAAA,EAAkB,gBAAgB,gBAAA,KAAqB,KAAA;AAAA,QACvD,WAAA,EAAa,gBAAgB,WAAA,KAAgB,KAAA;AAAA,QAC7C,KAAA;AAAA,QACA,iBAAA,EAAmB,SAAA;AAAA,QACnB,iBAAA,EAAmB,SAAA;AAAA,QACnB,cAAA;AAAA,QAEC,QAAA,EAAA;AAAA;AAAA,KACH,EACF,CAAA;AAAA,EAEJ;AAGA,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,YAAA,GACJ,OAAO,MAAA,KAAW,QAAA,GAAW,SAAS,EAAC;AACzC,IAAA,OAAA,mBACEO,eAAA,CAAAF,mBAAA,EAAA,EACG,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,sBACDL,cAAAA;AAAA,QAAC,gBAAA;AAAA,QAAA;AAAA,UACC,MAAA;AAAA,UACA,MAAA;AAAA,UACA,SAAA;AAAA,UACA,QAAA,EAAU,aAAa,QAAA,IAAY,cAAA;AAAA,UACnC,WAAA,EAAa,aAAa,WAAA,KAAgB;AAAA;AAAA;AAC5C,KAAA,EACF,CAAA;AAAA,EAEJ;AAGA,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,OAAA,mBACEO,eAAA,CAAAF,mBAAA,EAAA,EACG,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,sBACDL,cAAAA,CAAC,eAAA,EAAA,EAAgB,KAAA,EAAc;AAAA,KAAA,EACjC,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACEA,cAAAA,CAAC,uBAAA,EAAA,EAAwB,SAAA,EAAsB,WAC5C,QAAA,EAAA,OAAA,EACH,CAAA;AAEJ","file":"chunk-OE5DEMCV.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 are lazy-loaded via next/dynamic so their JS is only downloaded\n * when the feature is enabled — keeping the initial bundle lightweight.\n *\n * All modules share a unified identity (visitor ID + session ID) 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 dynamic from 'next/dynamic'\nimport {\n SiteKitIdentityProvider,\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\n// Lazy-load feature modules — JS only downloaded when feature is enabled\nconst LazyAnalyticsProvider = dynamic(\n () => import('../analytics/AnalyticsProvider').then(m => ({ default: m.AnalyticsProvider })),\n { ssr: false },\n)\nconst LazyEngageWidget = dynamic(\n () => import('../engage/EngageWidget').then(m => ({ default: m.EngageWidget })),\n { ssr: false },\n)\nconst LazySignalBridge = dynamic(\n () => import('../signal/SignalBridge').then(m => ({ default: m.SignalBridge })),\n { ssr: false },\n)\nconst LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\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 <LazySignalBridge\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 </LazySignalBridge>\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 <LazyAnalyticsProvider\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 </LazyAnalyticsProvider>\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 <LazyEngageWidget\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 <LazySitemapSync debug={debug} />\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/seo/server-api.ts"],"names":["cache"],"mappings":"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","file":"chunk-PTTDKFL7.js","sourcesContent":["/**\n * @sonordev/site-kit/seo - Server-Only API Functions\n * \n * SECURITY: These functions use private environment variables\n * and should ONLY be imported in server-side code (RSC, API routes, server actions).\n * \n * DO NOT import this file in client components or it will expose API keys.\n */\n\nimport { cache } from 'react'\nimport 'server-only' // This ensures the module can only be imported server-side\n\n// ============================================\n// Server-Only API Config\n// ============================================\n\n/**\n * Config for portal API calls. Project is resolved by the portal from the API key;\n * sites never send or read project ID.\n */\nfunction getSecureApiConfig() {\n const apiUrl = process.env.SONOR_API_URL || process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || 'https://api.sonor.io'\n const apiKey = process.env.SONOR_API_KEY || process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY || ''\n\n if (!apiKey) {\n throw new Error('@sonordev/seo: SONOR_API_KEY (or UPTRADE_API_KEY) environment variable is required for server-side SEO functions')\n }\n\n return { apiUrl, apiKey }\n}\n\n/** Derive project ID from API key for Signal API only (format: sonor_{uuid}_{secret} or uptrade_{uuid}_{secret}). Not used for portal. */\nfunction getProjectIdFromKey(apiKey: string): string | null {\n const match = apiKey.match(/^(?:sonor|uptrade)_([0-9a-f-]{36})_/)\n return match ? match[1] : null\n}\n\nfunction sleep(ms: number) {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\n/** Transient failures during Next SSG (parallel workers, one egress IP) */\nconst RETRYABLE_HTTP = new Set([429, 502, 503])\nconst SEO_POST_MAX_ATTEMPTS = 6\n\nasync function secureApiPost<T>(endpoint: string, body: Record<string, any> = {}, revalidate = 86400): Promise<T | null> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n const url = `${apiUrl}${endpoint}`\n\n for (let attempt = 1; attempt <= SEO_POST_MAX_ATTEMPTS; attempt++) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(body),\n next: { revalidate }, // 24h default — SEO data rarely changes; Portal can on-demand revalidate\n })\n\n if (RETRYABLE_HTTP.has(response.status) && attempt < SEO_POST_MAX_ATTEMPTS) {\n await response.text().catch(() => {})\n const retryAfter = response.headers.get('retry-after')\n let delayMs = 250 * attempt * attempt + Math.random() * 200\n if (retryAfter) {\n const sec = parseInt(retryAfter, 10)\n if (!Number.isNaN(sec) && sec > 0) delayMs = Math.max(delayMs, sec * 1000)\n }\n await sleep(Math.min(delayMs, 10_000))\n continue\n }\n\n if (!response.ok) {\n let detail = response.statusText\n try {\n const err = await response.json().catch(() => ({}))\n if (err?.message) detail = err.message\n } catch {\n /* ignore */\n }\n console.error(`@sonordev/seo: API error ${response.status} ${endpoint}: ${detail}`)\n return null\n }\n\n return await response.json()\n } catch (error) {\n if (attempt < SEO_POST_MAX_ATTEMPTS) {\n await sleep(200 * attempt * attempt + Math.random() * 150)\n continue\n }\n console.error('@sonordev/seo: Network error:', error)\n return null\n }\n }\n\n return null\n}\n\nasync function secureApiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 86400 },\n })\n\n if (!response.ok) {\n console.error(`@sonordev/seo: API error ${response.status}: ${response.statusText}`)\n return null\n }\n \n return await response.json()\n } catch (error) {\n console.error('@sonordev/seo: Network error:', error)\n return null\n }\n}\n\n// ============================================\n// Secure Cached Data Fetchers\n// ============================================\n\n/** Response shape for POST /api/public/seo/page-context */\nexport type PageSeoContext = {\n page: any | null\n schemas: any[]\n project: {\n id: string\n title?: string | null\n domain?: string | null\n logo_url?: string | null\n site_url?: string | null\n } | null\n}\n\n/**\n * One Portal round-trip per path (page row + schemas + project).\n * React cache() dedupes when getSEOPageData + getSchemaMarkups run in the same render (e.g. metadata + ManagedSchema).\n * @server-only\n */\nconst loadPageSeoContext = cache(async (path: string): Promise<PageSeoContext | null> => {\n const result = await secureApiPost<PageSeoContext>('/api/public/seo/page-context', { path })\n if (!result) return null\n return {\n page: result.page ?? null,\n schemas: Array.isArray(result.schemas) ? result.schemas : [],\n project: result.project ?? null,\n }\n})\n\n/**\n * Fetch SEO page data - cached per request\n * @server-only\n */\nexport const getSEOPageData = cache(async (path: string) => {\n const ctx = await loadPageSeoContext(path)\n return {\n page: ctx?.page ?? null,\n project: ctx?.project ?? null,\n }\n})\n\n/**\n * Fetch schema markups for a page - cached per request (shares loadPageSeoContext with getSEOPageData)\n * @server-only\n */\nexport const getSchemaMarkups = cache(async (\n path: string,\n options?: { includeTypes?: string[]; excludeTypes?: string[] }\n) => {\n const ctx = await loadPageSeoContext(path)\n let schemas = ctx?.schemas ?? []\n if (options?.includeTypes?.length) {\n const allow = new Set(options.includeTypes)\n schemas = schemas.filter((s: { schema_type?: string }) => s?.schema_type && allow.has(s.schema_type))\n }\n if (options?.excludeTypes?.length) {\n const deny = new Set(options.excludeTypes)\n schemas = schemas.filter((s: { schema_type?: string }) => !s?.schema_type || !deny.has(s.schema_type))\n }\n return schemas\n})\n\n/**\n * Fetch FAQ data for a page - cached per request\n * @server-only\n */\nexport const getFAQData = cache(async (path: string) => {\n const result = await secureApiPost<{ faq: any }>('/api/public/seo/faq', { path })\n return result?.faq || null\n})\n\n/**\n * Fetch internal links for a page - cached per request\n * @server-only\n */\nexport const getInternalLinks = cache(async (\n sourcePath: string,\n options?: { position?: string; limit?: number }\n) => {\n const result = await secureApiPost<{ links: any[] }>('/api/public/seo/internal-links', {\n sourcePath,\n position: options?.position,\n limit: options?.limit,\n })\n return result?.links || []\n})\n\n/**\n * Fetch content block - cached per request\n * @server-only\n */\nexport const getContentBlock = cache(async (path: string, section: string) => {\n const result = await secureApiPost<{ content: any }>('/api/public/seo/content', { path, section })\n return result?.content || null\n})\n\n/**\n * Fetch A/B test and determine variant - cached per request\n * @server-only\n */\nexport const getABTest = cache(async (path: string, field: string) => {\n const result = await secureApiPost<{ test: any }>('/api/public/seo/ab-test', { path, field })\n return result?.test || null\n})\n\n/**\n * Record A/B test impression\n * @server-only\n */\nexport async function recordABImpression(\n testId: string,\n variant: 'a' | 'b',\n sessionId?: string\n): Promise<void> {\n await secureApiPost('/api/public/seo/ab-impression', { testId, variant, sessionId })\n}\n\n/**\n * Fetch redirect for a path - cached per request\n * @server-only\n */\nexport const getRedirectData = cache(async (path: string) => {\n const result = await secureApiPost<{ redirect: any }>('/api/public/seo/redirect', { path })\n return result?.redirect || null\n})\n\n/**\n * Fetch managed scripts - cached per request\n * @server-only\n */\nexport const getManagedScripts = cache(async (position: string, currentPath?: string) => {\n const result = await secureApiPost<{ scripts: any[] }>('/api/public/seo/scripts', {\n position,\n currentPath,\n })\n return result?.scripts || []\n})\n\n/**\n * Fetch robots directive for a page - cached per request\n * @server-only\n */\nexport const getRobotsData = cache(async (path: string) => {\n const { page } = await getSEOPageData(path)\n return page?.managed_robots || null\n})\n\n/**\n * Fetch sitemap entries - cached per request\n * @server-only\n */\nexport const getSitemapEntries = cache(async (options?: { publishedOnly?: boolean }) => {\n const result = await secureApiPost<{ entries: any[] }>('/api/public/seo/sitemap', {\n publishedOnly: options?.publishedOnly,\n })\n return result?.entries || []\n})\n\n/**\n * Register/sync sitemap entries from the client site\n * Call this at build time to populate seo_pages from your sitemap.xml\n * @server-only\n * \n * @example\n * ```ts\n * // scripts/register-sitemap.ts (run at build time)\n * import { registerSitemap } from '@sonordev/seo/server'\n * \n * await registerSitemap([\n * { path: '/', priority: 1.0, changefreq: 'daily' },\n * { path: '/about', priority: 0.8, changefreq: 'weekly' },\n * ])\n * ```\n */\nexport async function registerSitemap(\n entries: Array<{\n path: string\n title?: string\n priority?: number\n changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'\n }>,\n options?: {\n /**\n * Sync mode:\n * - 'full-replace': replaces the entire page set (default for build-time sync)\n * - 'additive': adds/updates pages but never deletes existing ones\n */\n mode?: 'additive' | 'full-replace'\n }\n): Promise<{ success: boolean; created: number; updated: number }> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n const mode = options?.mode ?? 'full-replace'\n\n try {\n const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify({ entries, mode }),\n })\n \n if (!response.ok) {\n console.error(`@sonordev/seo: Sitemap registration failed: ${response.statusText}`)\n return { success: false, created: 0, updated: 0 }\n }\n \n return await response.json()\n } catch (error) {\n console.error('@sonordev/seo: Sitemap registration error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\n// ============================================\n// Signal-Powered Metadata Fallback\n// ============================================\n\n/**\n * Ensure metadata exists for a page by triggering Signal AI optimization.\n * If the page has no managed_title or managed_meta_description, Signal will\n * generate them and save to the database via Portal proxy.\n *\n * Idempotent — returns existing metadata if already populated.\n * @server-only\n */\nexport const ensureMetadata = cache(async (path: string): Promise<{\n managed_title?: string\n managed_meta_description?: string\n managed_keywords?: string[]\n managed_schema?: Record<string, unknown>\n} | null> => {\n return secureApiPost('/api/public/seo/ensure-metadata', { path })\n})\n\n// ============================================\n// AI Visibility & Entity Graph API (Signal)\n// ============================================\n\nfunction getSignalApiConfig() {\n const apiUrl = process.env.SONOR_SIGNAL_URL || process.env.SIGNAL_API_URL || process.env.NEXT_PUBLIC_SIGNAL_API_URL || 'https://signal.sonor.io'\n const apiKey = process.env.SONOR_API_KEY || process.env.UPTRADE_API_KEY || ''\n return { apiUrl, apiKey }\n}\n\nasync function signalApiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getSignalApiConfig()\n \n if (!apiKey) {\n return null\n }\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 300 }, // Cache for 5 minutes\n })\n \n if (!response.ok) {\n return null\n }\n \n const result = await response.json()\n return result?.data || result\n } catch (error) {\n console.error('@sonordev/seo: Signal API error:', error)\n return null\n }\n}\n\n/**\n * Entity types for the knowledge graph\n */\nexport type EntityType = \n | 'organization'\n | 'person'\n | 'service'\n | 'product'\n | 'location'\n | 'concept'\n | 'credential'\n\n/**\n * Entity from the knowledge graph\n */\nexport interface SEOEntity {\n id: string\n project_id: string\n entity_type: EntityType\n name: string\n slug: string\n properties: Record<string, unknown>\n knows_about: string[]\n same_as: string[]\n schema_type?: string\n is_primary: boolean\n}\n\n/**\n * Fetch entities for a project - cached per request\n * Returns the entity graph for enhanced schema markup\n * @server-only\n */\nexport const getEntities = cache(async (\n options?: { type?: EntityType }\n): Promise<SEOEntity[]> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return []\n let endpoint = `/skills/seo/entities/${projectId}`\n if (options?.type) {\n endpoint += `?type=${options.type}`\n }\n const result = await signalApiGet<SEOEntity[]>(endpoint)\n return result || []\n})\n\n/**\n * Fetch primary entity (the business) - cached per request\n * @server-only\n */\nexport const getPrimaryEntity = cache(async (): Promise<SEOEntity | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n return signalApiGet<SEOEntity>(`/skills/seo/entities/${projectId}/primary`)\n})\n\n/**\n * Fetch entity-enhanced schema for a page\n * Returns Organization schema with knowsAbout, areaServed, employee, etc.\n * @server-only\n */\nexport const getEntityEnhancedSchema = cache(async (pagePath: string): Promise<object[]> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return []\n const result = await signalApiGet<{ schemas: object[] }>(\n `/skills/seo/schema/${projectId}/entity-enhanced?pagePath=${encodeURIComponent(pagePath)}`\n )\n return result?.schemas || []\n})\n\n/**\n * Get AI visibility score for a page\n * @server-only\n */\nexport const getVisibilityScore = cache(async (\n pagePath: string\n): Promise<{\n overall_score: number\n entity_coverage: number\n answer_density: number\n chunk_readability: number\n authority_signals: number\n schema_completeness: number\n} | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n const result = await signalApiGet<any[]>(`/skills/seo/visibility/${projectId}`)\n if (!result) return null\n return result.find(s => s.page_path === pagePath) || null\n})\n\n/**\n * Get AI visibility summary for project\n * @server-only\n */\nexport const getVisibilitySummary = cache(async (): Promise<{\n overall_score: number\n total_entities: number\n pages_analyzed: number\n top_recommendations: Array<{ priority: string; type: string; message: string }>\n} | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n return signalApiGet(`/skills/seo/visibility/${projectId}/summary`)\n})\n"]}
|
package/dist/chunk-S7FRYNSU.mjs
DELETED
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
// src/forms/formsApi.ts
|
|
2
|
-
var config = null;
|
|
3
|
-
function configureFormsApi(options) {
|
|
4
|
-
config = options;
|
|
5
|
-
}
|
|
6
|
-
function getConfig() {
|
|
7
|
-
if (config) return config;
|
|
8
|
-
if (typeof window !== "undefined") {
|
|
9
|
-
const apiUrl = window.__SITE_KIT_API_URL__;
|
|
10
|
-
const apiKey = window.__SITE_KIT_API_KEY__;
|
|
11
|
-
if (apiUrl && apiKey) {
|
|
12
|
-
return { baseUrl: apiUrl, apiKey };
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
throw new Error(
|
|
16
|
-
"Forms API not configured. Either wrap your app in SiteKitProvider or call configureFormsApi() first."
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
async function apiRequest(method, path, body) {
|
|
20
|
-
const { baseUrl, apiKey, getAuthToken } = getConfig();
|
|
21
|
-
const headers = {
|
|
22
|
-
"Content-Type": "application/json"
|
|
23
|
-
};
|
|
24
|
-
if (apiKey) {
|
|
25
|
-
headers["x-api-key"] = apiKey;
|
|
26
|
-
} else if (getAuthToken) {
|
|
27
|
-
const token = await getAuthToken();
|
|
28
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
29
|
-
}
|
|
30
|
-
const response = await fetch(`${baseUrl}${path}`, {
|
|
31
|
-
method,
|
|
32
|
-
headers,
|
|
33
|
-
body: body ? JSON.stringify(body) : void 0
|
|
34
|
-
});
|
|
35
|
-
if (!response.ok) {
|
|
36
|
-
const error = await response.json().catch(() => ({ message: response.statusText }));
|
|
37
|
-
throw new Error(error.message || `API error: ${response.status}`);
|
|
38
|
-
}
|
|
39
|
-
if (response.status === 204) {
|
|
40
|
-
return void 0;
|
|
41
|
-
}
|
|
42
|
-
return response.json();
|
|
43
|
-
}
|
|
44
|
-
var formsApi = {
|
|
45
|
-
/**
|
|
46
|
-
* List all forms for a project
|
|
47
|
-
*/
|
|
48
|
-
async list(options = {}) {
|
|
49
|
-
const params = new URLSearchParams();
|
|
50
|
-
if (options.projectId) params.set("projectId", options.projectId);
|
|
51
|
-
if (options.formType) params.set("formType", options.formType);
|
|
52
|
-
if (options.isActive !== void 0) params.set("isActive", String(options.isActive));
|
|
53
|
-
if (options.search) params.set("search", options.search);
|
|
54
|
-
const query = params.toString();
|
|
55
|
-
const result = await apiRequest("GET", `/forms${query ? `?${query}` : ""}`);
|
|
56
|
-
return result.data;
|
|
57
|
-
},
|
|
58
|
-
/**
|
|
59
|
-
* Get a single form by ID or slug
|
|
60
|
-
*/
|
|
61
|
-
async get(idOrSlug) {
|
|
62
|
-
return apiRequest("GET", `/forms/${idOrSlug}`);
|
|
63
|
-
},
|
|
64
|
-
/**
|
|
65
|
-
* Create a new form
|
|
66
|
-
*/
|
|
67
|
-
async create(input) {
|
|
68
|
-
return apiRequest("POST", "/forms", input);
|
|
69
|
-
},
|
|
70
|
-
/**
|
|
71
|
-
* Update an existing form
|
|
72
|
-
*/
|
|
73
|
-
async update(id, input) {
|
|
74
|
-
return apiRequest("PUT", `/forms/${id}`, input);
|
|
75
|
-
},
|
|
76
|
-
/**
|
|
77
|
-
* Delete a form
|
|
78
|
-
*/
|
|
79
|
-
async delete(id) {
|
|
80
|
-
return apiRequest("DELETE", `/forms/${id}`);
|
|
81
|
-
},
|
|
82
|
-
/**
|
|
83
|
-
* Add a field to an existing form
|
|
84
|
-
*/
|
|
85
|
-
async addField(formId, field2) {
|
|
86
|
-
const form = await formsApi.get(formId);
|
|
87
|
-
const maxSortOrder = Math.max(0, ...(form.fields || []).map((f) => f.sortOrder || 0));
|
|
88
|
-
return formsApi.update(formId, {
|
|
89
|
-
fields: [
|
|
90
|
-
...form.fields || [],
|
|
91
|
-
{ ...field2, sortOrder: field2.sortOrder ?? maxSortOrder + 1 }
|
|
92
|
-
]
|
|
93
|
-
});
|
|
94
|
-
},
|
|
95
|
-
/**
|
|
96
|
-
* Update a field in an existing form
|
|
97
|
-
*/
|
|
98
|
-
async updateField(formId, fieldSlug, updates) {
|
|
99
|
-
const form = await formsApi.get(formId);
|
|
100
|
-
return formsApi.update(formId, {
|
|
101
|
-
fields: (form.fields || []).map(
|
|
102
|
-
(f) => f.slug === fieldSlug ? { ...f, ...updates } : f
|
|
103
|
-
)
|
|
104
|
-
});
|
|
105
|
-
},
|
|
106
|
-
/**
|
|
107
|
-
* Remove a field from a form
|
|
108
|
-
*/
|
|
109
|
-
async removeField(formId, fieldSlug) {
|
|
110
|
-
const form = await formsApi.get(formId);
|
|
111
|
-
return formsApi.update(formId, {
|
|
112
|
-
fields: (form.fields || []).filter((f) => f.slug !== fieldSlug)
|
|
113
|
-
});
|
|
114
|
-
},
|
|
115
|
-
/**
|
|
116
|
-
* Reorder fields in a form
|
|
117
|
-
*/
|
|
118
|
-
async reorderFields(formId, fieldSlugs) {
|
|
119
|
-
const form = await formsApi.get(formId);
|
|
120
|
-
const fieldsMap = new Map((form.fields || []).map((f) => [f.slug, f]));
|
|
121
|
-
const orderedFields = fieldSlugs.map((slug, index) => {
|
|
122
|
-
const field2 = fieldsMap.get(slug);
|
|
123
|
-
if (!field2) throw new Error(`Field not found: ${slug}`);
|
|
124
|
-
return { ...field2, sortOrder: index };
|
|
125
|
-
});
|
|
126
|
-
return formsApi.update(formId, { fields: orderedFields });
|
|
127
|
-
},
|
|
128
|
-
/**
|
|
129
|
-
* Clone a form
|
|
130
|
-
*/
|
|
131
|
-
async clone(formId, newSlug, newName) {
|
|
132
|
-
const form = await formsApi.get(formId);
|
|
133
|
-
return formsApi.create({
|
|
134
|
-
projectId: form.projectId,
|
|
135
|
-
slug: newSlug,
|
|
136
|
-
name: newName || `${form.name} (Copy)`,
|
|
137
|
-
description: form.description,
|
|
138
|
-
formType: form.formType,
|
|
139
|
-
successMessage: form.successMessage,
|
|
140
|
-
redirectUrl: form.redirectUrl,
|
|
141
|
-
notificationEmails: form.notificationEmails,
|
|
142
|
-
submitButtonText: form.submitButtonText,
|
|
143
|
-
layout: form.layout,
|
|
144
|
-
showProgress: form.showProgress,
|
|
145
|
-
enableSaveDraft: form.enableSaveDraft,
|
|
146
|
-
isActive: false,
|
|
147
|
-
// Clone as inactive
|
|
148
|
-
fields: (form.fields || []).map(({ id, ...field2 }) => field2),
|
|
149
|
-
// Remove IDs
|
|
150
|
-
steps: (form.steps || []).map(({ id, ...step }) => step)
|
|
151
|
-
// Remove IDs
|
|
152
|
-
});
|
|
153
|
-
},
|
|
154
|
-
/**
|
|
155
|
-
* Activate or deactivate a form
|
|
156
|
-
*/
|
|
157
|
-
async setActive(formId, isActive) {
|
|
158
|
-
return formsApi.update(formId, { isActive });
|
|
159
|
-
},
|
|
160
|
-
/**
|
|
161
|
-
* Sync a form definition to the backend
|
|
162
|
-
* Creates the form if it doesn't exist, updates if it does
|
|
163
|
-
* Perfect for defining forms in code during development
|
|
164
|
-
*
|
|
165
|
-
* @example
|
|
166
|
-
* ```tsx
|
|
167
|
-
* // In your app initialization or form component
|
|
168
|
-
* await formsApi.sync({
|
|
169
|
-
* slug: 'contact',
|
|
170
|
-
* name: 'Contact Form',
|
|
171
|
-
* formType: 'prospect',
|
|
172
|
-
* fields: [
|
|
173
|
-
* field.text('name', 'Your Name', { isRequired: true }),
|
|
174
|
-
* field.email('email', 'Email Address'),
|
|
175
|
-
* field.phone('phone', 'Phone Number'),
|
|
176
|
-
* field.textarea('message', 'Message'),
|
|
177
|
-
* ]
|
|
178
|
-
* })
|
|
179
|
-
* ```
|
|
180
|
-
*/
|
|
181
|
-
async sync(input) {
|
|
182
|
-
return apiRequest(
|
|
183
|
-
"POST",
|
|
184
|
-
"/api/public/forms/sync",
|
|
185
|
-
input
|
|
186
|
-
);
|
|
187
|
-
},
|
|
188
|
-
/**
|
|
189
|
-
* Sync multiple forms at once
|
|
190
|
-
* Useful for initializing all forms in your app
|
|
191
|
-
*/
|
|
192
|
-
async syncAll(forms) {
|
|
193
|
-
return Promise.all(forms.map((form) => formsApi.sync(form)));
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
var field = {
|
|
197
|
-
text: (slug, label, options) => ({
|
|
198
|
-
slug,
|
|
199
|
-
label,
|
|
200
|
-
fieldType: "text",
|
|
201
|
-
...options
|
|
202
|
-
}),
|
|
203
|
-
email: (slug, label, options) => ({
|
|
204
|
-
slug,
|
|
205
|
-
label,
|
|
206
|
-
fieldType: "email",
|
|
207
|
-
isRequired: true,
|
|
208
|
-
...options
|
|
209
|
-
}),
|
|
210
|
-
phone: (slug, label, options) => ({
|
|
211
|
-
slug,
|
|
212
|
-
label,
|
|
213
|
-
fieldType: "phone",
|
|
214
|
-
...options
|
|
215
|
-
}),
|
|
216
|
-
textarea: (slug, label, options) => ({
|
|
217
|
-
slug,
|
|
218
|
-
label,
|
|
219
|
-
fieldType: "textarea",
|
|
220
|
-
...options
|
|
221
|
-
}),
|
|
222
|
-
select: (slug, label, choices, options) => ({
|
|
223
|
-
slug,
|
|
224
|
-
label,
|
|
225
|
-
fieldType: "select",
|
|
226
|
-
options: choices,
|
|
227
|
-
...options
|
|
228
|
-
}),
|
|
229
|
-
radio: (slug, label, choices, options) => ({
|
|
230
|
-
slug,
|
|
231
|
-
label,
|
|
232
|
-
fieldType: "radio",
|
|
233
|
-
options: choices,
|
|
234
|
-
...options
|
|
235
|
-
}),
|
|
236
|
-
checkbox: (slug, label, options) => ({
|
|
237
|
-
slug,
|
|
238
|
-
label,
|
|
239
|
-
fieldType: "checkbox",
|
|
240
|
-
...options
|
|
241
|
-
}),
|
|
242
|
-
date: (slug, label, options) => ({
|
|
243
|
-
slug,
|
|
244
|
-
label,
|
|
245
|
-
fieldType: "date",
|
|
246
|
-
...options
|
|
247
|
-
}),
|
|
248
|
-
number: (slug, label, options) => ({
|
|
249
|
-
slug,
|
|
250
|
-
label,
|
|
251
|
-
fieldType: "number",
|
|
252
|
-
...options
|
|
253
|
-
}),
|
|
254
|
-
rating: (slug, label, options) => ({
|
|
255
|
-
slug,
|
|
256
|
-
label,
|
|
257
|
-
fieldType: "rating",
|
|
258
|
-
...options
|
|
259
|
-
}),
|
|
260
|
-
file: (slug, label, options) => ({
|
|
261
|
-
slug,
|
|
262
|
-
label,
|
|
263
|
-
fieldType: "file",
|
|
264
|
-
...options
|
|
265
|
-
}),
|
|
266
|
-
hidden: (slug, defaultValue) => ({
|
|
267
|
-
slug,
|
|
268
|
-
label: "",
|
|
269
|
-
fieldType: "hidden",
|
|
270
|
-
defaultValue
|
|
271
|
-
}),
|
|
272
|
-
heading: (slug, label) => ({
|
|
273
|
-
slug,
|
|
274
|
-
label,
|
|
275
|
-
fieldType: "heading"
|
|
276
|
-
}),
|
|
277
|
-
paragraph: (slug, label) => ({
|
|
278
|
-
slug,
|
|
279
|
-
label,
|
|
280
|
-
fieldType: "paragraph"
|
|
281
|
-
})
|
|
282
|
-
};
|
|
283
|
-
function defineForm(definition) {
|
|
284
|
-
const fieldsWithOrder = definition.fields.map((f, index) => ({
|
|
285
|
-
...f,
|
|
286
|
-
sortOrder: f.sortOrder ?? index
|
|
287
|
-
}));
|
|
288
|
-
return {
|
|
289
|
-
...definition,
|
|
290
|
-
fields: fieldsWithOrder,
|
|
291
|
-
formType: definition.formType || "contact",
|
|
292
|
-
successMessage: definition.successMessage || "Thank you for your submission!",
|
|
293
|
-
submitButtonText: definition.submitButtonText || "Submit",
|
|
294
|
-
layout: definition.layout || "stacked",
|
|
295
|
-
isActive: definition.isActive ?? true
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
async function initializeForms(forms) {
|
|
299
|
-
if (typeof window === "undefined") {
|
|
300
|
-
console.log(`[Site-Kit] ${forms.length} form(s) ready to sync: ${forms.map((f) => f.slug).join(", ")}`);
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
try {
|
|
304
|
-
const results = await formsApi.syncAll(forms);
|
|
305
|
-
const created = results.filter((r) => r.created).length;
|
|
306
|
-
const updated = results.filter((r) => r.updated).length;
|
|
307
|
-
console.log(`[Site-Kit] Forms synced: ${created} created, ${updated} updated`);
|
|
308
|
-
} catch (error) {
|
|
309
|
-
console.error("[Site-Kit] Failed to sync forms:", error);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
export { configureFormsApi, defineForm, field, formsApi, initializeForms };
|
|
314
|
-
//# sourceMappingURL=chunk-S7FRYNSU.mjs.map
|
|
315
|
-
//# sourceMappingURL=chunk-S7FRYNSU.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/forms/formsApi.ts"],"names":["field"],"mappings":"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","file":"chunk-S7FRYNSU.mjs","sourcesContent":["/**\n * @sonordev/site-kit/forms - Forms API Client\n * \n * Full API client for form management. Allows developers to create, update,\n * and delete forms programmatically. Changes sync to Portal automatically.\n * \n * @example\n * ```tsx\n * import { formsApi } from '@sonordev/site-kit/forms'\n * \n * // Create a new form\n * const form = await formsApi.create({\n * projectId: 'xxx',\n * slug: 'contact-us',\n * name: 'Contact Form',\n * formType: 'prospect',\n * fields: [\n * { slug: 'name', label: 'Name', fieldType: 'text', isRequired: true },\n * { slug: 'email', label: 'Email', fieldType: 'email', isRequired: true },\n * { slug: 'message', label: 'Message', fieldType: 'textarea' },\n * ]\n * })\n * \n * // Update fields\n * await formsApi.update(form.id, {\n * fields: [...form.fields, { slug: 'phone', label: 'Phone', fieldType: 'phone' }]\n * })\n * ```\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport type FormType = \n | 'prospect' // → CRM leads\n | 'contact' // → Contact form\n | 'support' // → Support tickets\n | 'feedback' // → Feedback entries\n | 'newsletter' // → Email subscribers\n | 'custom' // → Custom webhook\n\nexport type FieldType =\n | 'text'\n | 'email'\n | 'phone'\n | 'number'\n | 'textarea'\n | 'select'\n | 'multi_select'\n | 'radio'\n | 'checkbox'\n | 'date'\n | 'time'\n | 'datetime'\n | 'url'\n | 'file'\n | 'rating'\n | 'slider'\n | 'hidden'\n | 'heading'\n | 'paragraph'\n\nexport type FieldWidth = 'full' | 'half' | 'third' | 'quarter'\n\nexport interface FieldOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface FieldValidation {\n min?: number\n max?: number\n minLength?: number\n maxLength?: number\n pattern?: string\n patternMessage?: string\n}\n\nexport interface FieldConditional {\n field: string\n operator: 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_empty' | 'not_empty' | 'greater_than' | 'less_than'\n value?: string | number | boolean\n}\n\nexport interface FormField {\n id?: string\n slug: string\n label: string\n fieldType: FieldType\n placeholder?: string\n helpText?: string\n defaultValue?: string\n isRequired?: boolean\n validation?: FieldValidation\n options?: FieldOption[]\n conditional?: FieldConditional\n width?: FieldWidth\n sortOrder?: number\n destinationField?: string\n stepId?: string\n}\n\nexport interface FormStep {\n id?: string\n stepNumber: number\n title?: string\n description?: string\n condition?: FieldConditional\n}\n\nexport interface Form {\n id: string\n projectId: string\n slug: string\n name: string\n description?: string\n formType: FormType\n successMessage: string\n redirectUrl?: string\n notificationEmails?: string[]\n submitButtonText: string\n layout: 'stacked' | 'inline' | 'grid'\n showProgress: boolean\n enableSaveDraft: boolean\n isActive: boolean\n createdAt: string\n updatedAt: string\n fields?: FormField[]\n steps?: FormStep[]\n}\n\nexport interface CreateFormInput {\n projectId: string\n slug: string\n name: string\n description?: string\n formType?: FormType\n successMessage?: string\n redirectUrl?: string\n notificationEmails?: string[]\n submitButtonText?: string\n layout?: 'stacked' | 'inline' | 'grid'\n showProgress?: boolean\n enableSaveDraft?: boolean\n isActive?: boolean\n fields?: FormField[]\n steps?: FormStep[]\n}\n\nexport interface UpdateFormInput {\n slug?: string\n name?: string\n description?: string\n formType?: FormType\n successMessage?: string\n redirectUrl?: string\n notificationEmails?: string[]\n submitButtonText?: string\n layout?: 'stacked' | 'inline' | 'grid'\n showProgress?: boolean\n enableSaveDraft?: boolean\n isActive?: boolean\n fields?: FormField[]\n steps?: FormStep[]\n}\n\nexport interface FormsListOptions {\n projectId?: string\n formType?: FormType\n isActive?: boolean\n search?: string\n}\n\n// ============================================\n// API Client Configuration\n// ============================================\n\ninterface FormsApiConfig {\n baseUrl: string\n apiKey?: string\n getAuthToken?: () => Promise<string> | string\n}\n\nlet config: FormsApiConfig | null = null\n\n/**\n * Configure the forms API client\n */\nexport function configureFormsApi(options: FormsApiConfig) {\n config = options\n}\n\n/**\n * Get API config, falling back to SiteKitProvider globals\n */\nfunction getConfig(): FormsApiConfig {\n if (config) return config\n \n // Try to get from window globals (set by SiteKitProvider)\n if (typeof window !== 'undefined') {\n const apiUrl = (window as any).__SITE_KIT_API_URL__\n const apiKey = (window as any).__SITE_KIT_API_KEY__\n \n if (apiUrl && apiKey) {\n return { baseUrl: apiUrl, apiKey }\n }\n }\n \n throw new Error(\n 'Forms API not configured. Either wrap your app in SiteKitProvider or call configureFormsApi() first.'\n )\n}\n\n// ============================================\n// HTTP Helpers\n// ============================================\n\nasync function apiRequest<T>(\n method: 'GET' | 'POST' | 'PUT' | 'DELETE',\n path: string,\n body?: any\n): Promise<T> {\n const { baseUrl, apiKey, getAuthToken } = getConfig()\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n \n // Use API key for public endpoints, auth token for admin endpoints\n if (apiKey) {\n headers['x-api-key'] = apiKey\n } else if (getAuthToken) {\n const token = await getAuthToken()\n headers['Authorization'] = `Bearer ${token}`\n }\n \n const response = await fetch(`${baseUrl}${path}`, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n \n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: response.statusText }))\n throw new Error(error.message || `API error: ${response.status}`)\n }\n \n if (response.status === 204) {\n return undefined as T\n }\n \n return response.json()\n}\n\n// ============================================\n// Forms API\n// ============================================\n\nexport const formsApi = {\n /**\n * List all forms for a project\n */\n async list(options: FormsListOptions = {}): Promise<Form[]> {\n const params = new URLSearchParams()\n if (options.projectId) params.set('projectId', options.projectId)\n if (options.formType) params.set('formType', options.formType)\n if (options.isActive !== undefined) params.set('isActive', String(options.isActive))\n if (options.search) params.set('search', options.search)\n \n const query = params.toString()\n const result = await apiRequest<{ data: Form[] }>('GET', `/forms${query ? `?${query}` : ''}`)\n return result.data\n },\n \n /**\n * Get a single form by ID or slug\n */\n async get(idOrSlug: string): Promise<Form> {\n return apiRequest<Form>('GET', `/forms/${idOrSlug}`)\n },\n \n /**\n * Create a new form\n */\n async create(input: CreateFormInput): Promise<Form> {\n return apiRequest<Form>('POST', '/forms', input)\n },\n \n /**\n * Update an existing form\n */\n async update(id: string, input: UpdateFormInput): Promise<Form> {\n return apiRequest<Form>('PUT', `/forms/${id}`, input)\n },\n \n /**\n * Delete a form\n */\n async delete(id: string): Promise<void> {\n return apiRequest<void>('DELETE', `/forms/${id}`)\n },\n \n /**\n * Add a field to an existing form\n */\n async addField(formId: string, field: FormField): Promise<Form> {\n const form = await formsApi.get(formId)\n const maxSortOrder = Math.max(0, ...(form.fields || []).map(f => f.sortOrder || 0))\n \n return formsApi.update(formId, {\n fields: [\n ...(form.fields || []),\n { ...field, sortOrder: field.sortOrder ?? maxSortOrder + 1 }\n ]\n })\n },\n \n /**\n * Update a field in an existing form\n */\n async updateField(formId: string, fieldSlug: string, updates: Partial<FormField>): Promise<Form> {\n const form = await formsApi.get(formId)\n \n return formsApi.update(formId, {\n fields: (form.fields || []).map(f => \n f.slug === fieldSlug ? { ...f, ...updates } : f\n )\n })\n },\n \n /**\n * Remove a field from a form\n */\n async removeField(formId: string, fieldSlug: string): Promise<Form> {\n const form = await formsApi.get(formId)\n \n return formsApi.update(formId, {\n fields: (form.fields || []).filter(f => f.slug !== fieldSlug)\n })\n },\n \n /**\n * Reorder fields in a form\n */\n async reorderFields(formId: string, fieldSlugs: string[]): Promise<Form> {\n const form = await formsApi.get(formId)\n const fieldsMap = new Map((form.fields || []).map(f => [f.slug, f]))\n \n const orderedFields = fieldSlugs.map((slug, index) => {\n const field = fieldsMap.get(slug)\n if (!field) throw new Error(`Field not found: ${slug}`)\n return { ...field, sortOrder: index }\n })\n \n return formsApi.update(formId, { fields: orderedFields })\n },\n \n /**\n * Clone a form\n */\n async clone(formId: string, newSlug: string, newName?: string): Promise<Form> {\n const form = await formsApi.get(formId)\n \n return formsApi.create({\n projectId: form.projectId,\n slug: newSlug,\n name: newName || `${form.name} (Copy)`,\n description: form.description,\n formType: form.formType,\n successMessage: form.successMessage,\n redirectUrl: form.redirectUrl,\n notificationEmails: form.notificationEmails,\n submitButtonText: form.submitButtonText,\n layout: form.layout,\n showProgress: form.showProgress,\n enableSaveDraft: form.enableSaveDraft,\n isActive: false, // Clone as inactive\n fields: (form.fields || []).map(({ id, ...field }) => field), // Remove IDs\n steps: (form.steps || []).map(({ id, ...step }) => step), // Remove IDs\n })\n },\n \n /**\n * Activate or deactivate a form\n */\n async setActive(formId: string, isActive: boolean): Promise<Form> {\n return formsApi.update(formId, { isActive })\n },\n\n /**\n * Sync a form definition to the backend\n * Creates the form if it doesn't exist, updates if it does\n * Perfect for defining forms in code during development\n * \n * @example\n * ```tsx\n * // In your app initialization or form component\n * await formsApi.sync({\n * slug: 'contact',\n * name: 'Contact Form',\n * formType: 'prospect',\n * fields: [\n * field.text('name', 'Your Name', { isRequired: true }),\n * field.email('email', 'Email Address'),\n * field.phone('phone', 'Phone Number'),\n * field.textarea('message', 'Message'),\n * ]\n * })\n * ```\n */\n async sync(input: Omit<CreateFormInput, 'projectId'>): Promise<Form & { synced: boolean; created: boolean; updated: boolean }> {\n return apiRequest<Form & { synced: boolean; created: boolean; updated: boolean }>(\n 'POST',\n '/api/public/forms/sync',\n input\n )\n },\n\n /**\n * Sync multiple forms at once\n * Useful for initializing all forms in your app\n */\n async syncAll(forms: Array<Omit<CreateFormInput, 'projectId'>>): Promise<Array<Form & { synced: boolean; created: boolean; updated: boolean }>> {\n return Promise.all(forms.map(form => formsApi.sync(form)))\n },\n}\n\n// ============================================\n// Field Builder Helpers\n// ============================================\n\n/**\n * Helper functions to build field definitions\n */\nexport const field = {\n text: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'text',\n ...options,\n }),\n \n email: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'email',\n isRequired: true,\n ...options,\n }),\n \n phone: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'phone',\n ...options,\n }),\n \n textarea: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'textarea',\n ...options,\n }),\n \n select: (slug: string, label: string, choices: Array<{ value: string; label: string }>, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'select',\n options: choices,\n ...options,\n }),\n \n radio: (slug: string, label: string, choices: Array<{ value: string; label: string }>, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'radio',\n options: choices,\n ...options,\n }),\n \n checkbox: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'checkbox',\n ...options,\n }),\n \n date: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'date',\n ...options,\n }),\n \n number: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'number',\n ...options,\n }),\n \n rating: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'rating',\n ...options,\n }),\n \n file: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'file',\n ...options,\n }),\n \n hidden: (slug: string, defaultValue: string): FormField => ({\n slug,\n label: '',\n fieldType: 'hidden',\n defaultValue,\n }),\n \n heading: (slug: string, label: string): FormField => ({\n slug,\n label,\n fieldType: 'heading',\n }),\n \n paragraph: (slug: string, label: string): FormField => ({\n slug,\n label,\n fieldType: 'paragraph',\n }),\n}\n\n// ============================================\n// Form Definition Helper\n// ============================================\n\nexport interface FormDefinition extends Omit<CreateFormInput, 'projectId'> {\n slug: string\n name: string\n fields: FormField[]\n}\n\n/**\n * Define a form declaratively\n * Returns a form definition that can be synced to the backend\n * \n * @example\n * ```tsx\n * // forms/contact.ts\n * import { defineForm, field } from '@sonordev/site-kit/forms'\n * \n * export const contactForm = defineForm({\n * slug: 'contact',\n * name: 'Contact Us',\n * formType: 'prospect',\n * successMessage: 'Thanks! We\\'ll be in touch soon.',\n * fields: [\n * field.text('name', 'Your Name', { isRequired: true }),\n * field.email('email', 'Email Address'),\n * field.phone('phone', 'Phone Number'),\n * field.select('service', 'Service Needed', [\n * { value: 'consultation', label: 'Free Consultation' },\n * { value: 'representation', label: 'Legal Representation' },\n * ]),\n * field.textarea('message', 'Tell us about your case'),\n * ]\n * })\n * \n * // Then in your app:\n * await formsApi.sync(contactForm)\n * ```\n */\nexport function defineForm(definition: FormDefinition): FormDefinition {\n // Ensure fields have sort order\n const fieldsWithOrder = definition.fields.map((f, index) => ({\n ...f,\n sortOrder: f.sortOrder ?? index,\n }))\n \n return {\n ...definition,\n fields: fieldsWithOrder,\n formType: definition.formType || 'contact',\n successMessage: definition.successMessage || 'Thank you for your submission!',\n submitButtonText: definition.submitButtonText || 'Submit',\n layout: definition.layout || 'stacked',\n isActive: definition.isActive ?? true,\n }\n}\n\n/**\n * Initialize multiple forms and sync them to the backend\n * Call this once during app initialization (e.g., in layout.tsx or _app.tsx)\n * \n * @example\n * ```tsx\n * // app/layout.tsx\n * import { initializeForms } from '@sonordev/site-kit/forms'\n * import { contactForm } from './forms/contact'\n * import { consultationForm } from './forms/consultation'\n * \n * // Initialize forms (runs once per build/server start in dev)\n * if (process.env.NODE_ENV === 'development') {\n * initializeForms([contactForm, consultationForm])\n * }\n * ```\n */\nexport async function initializeForms(forms: FormDefinition[]): Promise<void> {\n if (typeof window === 'undefined') {\n // Server-side: log that forms need to be synced\n console.log(`[Site-Kit] ${forms.length} form(s) ready to sync: ${forms.map(f => f.slug).join(', ')}`)\n return\n }\n \n try {\n const results = await formsApi.syncAll(forms)\n const created = results.filter(r => r.created).length\n const updated = results.filter(r => r.updated).length\n console.log(`[Site-Kit] Forms synced: ${created} created, ${updated} updated`)\n } catch (error) {\n console.error('[Site-Kit] Failed to sync forms:', error)\n }\n}\n"]}
|