@sonordev/site-kit 3.0.5 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +107 -0
- package/agent-manifest.json +377 -0
- package/dist/AnalyticsProvider-A3STXJ65.js +29 -0
- package/dist/{AnalyticsProvider-WTOGN7LV.js.map → AnalyticsProvider-A3STXJ65.js.map} +1 -1
- package/dist/AnalyticsProvider-LEXGFM2K.mjs +8 -0
- package/dist/{AnalyticsProvider-MLT26JRP.mjs.map → AnalyticsProvider-LEXGFM2K.mjs.map} +1 -1
- package/dist/BlogPostFaqSection-4AD2NIGG.js +13 -0
- package/dist/{BlogPostFaqSection-H556RV62.js.map → BlogPostFaqSection-4AD2NIGG.js.map} +1 -1
- package/dist/{BlogPostFaqSection-VSHOKKUD.mjs → BlogPostFaqSection-TU6YEC7P.mjs} +3 -3
- package/dist/{BlogPostFaqSection-VSHOKKUD.mjs.map → BlogPostFaqSection-TU6YEC7P.mjs.map} +1 -1
- package/dist/ChatWidget-4QR2ZDRE.mjs +8 -0
- package/dist/{ChatWidget-QPZTPSPE.mjs.map → ChatWidget-4QR2ZDRE.mjs.map} +1 -1
- package/dist/ChatWidget-U3K2VHVN.js +17 -0
- package/dist/{ChatWidget-MAL7FB4M.js.map → ChatWidget-U3K2VHVN.js.map} +1 -1
- package/dist/EngageWidget-2FMKYJJT.mjs +7 -0
- package/dist/{EngageWidget-IPBUA4DW.mjs.map → EngageWidget-2FMKYJJT.mjs.map} +1 -1
- package/dist/EngageWidget-TOGMQ2G6.js +16 -0
- package/dist/{EngageWidget-N3CABK3L.js.map → EngageWidget-TOGMQ2G6.js.map} +1 -1
- package/dist/{SignalCore-4MDIJUAP.mjs → SignalCore-5QJG3IJB.mjs} +60 -47
- package/dist/SignalCore-5QJG3IJB.mjs.map +1 -0
- package/dist/{SignalCore-ZMFUE3N4.js → SignalCore-JB3VHHTG.js} +60 -47
- package/dist/SignalCore-JB3VHHTG.js.map +1 -0
- package/dist/SitemapSync-BJWSTERT.js +15 -0
- package/dist/{SitemapSync-FUCH6Y6J.js.map → SitemapSync-BJWSTERT.js.map} +1 -1
- package/dist/SitemapSync-T6PIDW64.mjs +6 -0
- package/dist/{SitemapSync-LCSPRAWU.mjs.map → SitemapSync-T6PIDW64.mjs.map} +1 -1
- package/dist/analytics/index.js +11 -9
- package/dist/analytics/index.mjs +4 -2
- package/dist/blog/index.js +12 -12
- package/dist/blog/index.mjs +2 -2
- package/dist/blog/server-ui.js +5 -5
- package/dist/blog/server-ui.mjs +1 -1
- package/dist/brand.css +21 -6
- package/dist/{chunk-O7E6QVK3.js → chunk-52VXHSVT.js} +3 -3
- package/dist/{chunk-O7E6QVK3.js.map → chunk-52VXHSVT.js.map} +1 -1
- package/dist/{chunk-I2GTT2DG.js → chunk-5RX4CUR2.js} +19 -21
- package/dist/chunk-5RX4CUR2.js.map +1 -0
- package/dist/{chunk-5AESOLXS.mjs → chunk-5ZNKNNJ4.mjs} +13 -11
- package/dist/chunk-5ZNKNNJ4.mjs.map +1 -0
- package/dist/{chunk-3YQCPLGP.mjs → chunk-7OK6BI3A.mjs} +41 -79
- package/dist/chunk-7OK6BI3A.mjs.map +1 -0
- package/dist/{chunk-TCVHI3JP.mjs → chunk-7R7SGJG3.mjs} +71 -109
- package/dist/chunk-7R7SGJG3.mjs.map +1 -0
- package/dist/{chunk-FT5JNCD4.mjs → chunk-AB2VYIYU.mjs} +11 -11
- package/dist/{chunk-FT5JNCD4.mjs.map → chunk-AB2VYIYU.mjs.map} +1 -1
- package/dist/{chunk-FMZOZQBV.mjs → chunk-AMBTOIYM.mjs} +19 -21
- package/dist/chunk-AMBTOIYM.mjs.map +1 -0
- package/dist/chunk-B5YNHSRA.js +102 -0
- package/dist/chunk-B5YNHSRA.js.map +1 -0
- package/dist/{chunk-I5TJIESQ.js → chunk-BMKZHXWQ.js} +11 -11
- package/dist/{chunk-I5TJIESQ.js.map → chunk-BMKZHXWQ.js.map} +1 -1
- package/dist/{chunk-NNZDHLXN.js → chunk-BNBCSHTK.js} +35 -9
- package/dist/chunk-BNBCSHTK.js.map +1 -0
- package/dist/{chunk-AN4ATCYQ.mjs → chunk-BUCF5FUY.mjs} +3 -3
- package/dist/{chunk-AN4ATCYQ.mjs.map → chunk-BUCF5FUY.mjs.map} +1 -1
- package/dist/{chunk-3GCEFS73.js → chunk-DCZUMCEC.js} +39 -62
- package/dist/chunk-DCZUMCEC.js.map +1 -0
- package/dist/{chunk-EUDTPXUI.mjs → chunk-DYCEEU67.mjs} +3 -3
- package/dist/{chunk-EUDTPXUI.mjs.map → chunk-DYCEEU67.mjs.map} +1 -1
- package/dist/chunk-E4TWVVSW.mjs +97 -0
- package/dist/chunk-E4TWVVSW.mjs.map +1 -0
- package/dist/{chunk-VCWSSGCU.js → chunk-E7M5MDGC.js} +32 -43
- package/dist/chunk-E7M5MDGC.js.map +1 -0
- package/dist/{chunk-QTWA44S3.mjs → chunk-GMO6POZ2.mjs} +7 -8
- package/dist/chunk-GMO6POZ2.mjs.map +1 -0
- package/dist/chunk-GMSPDTEV.js +264 -0
- package/dist/chunk-GMSPDTEV.js.map +1 -0
- package/dist/{chunk-UJQYSVYV.js → chunk-GQF6QAQS.js} +4 -4
- package/dist/{chunk-UJQYSVYV.js.map → chunk-GQF6QAQS.js.map} +1 -1
- package/dist/{chunk-65SMJBHW.mjs → chunk-IR5UC236.mjs} +69 -74
- package/dist/chunk-IR5UC236.mjs.map +1 -0
- package/dist/{chunk-MLJXELPA.js → chunk-LF3ID6WN.js} +71 -111
- package/dist/chunk-LF3ID6WN.js.map +1 -0
- package/dist/{chunk-YFGKIKXA.mjs → chunk-MKZHVSKL.mjs} +3 -3
- package/dist/{chunk-YFGKIKXA.mjs.map → chunk-MKZHVSKL.mjs.map} +1 -1
- package/dist/{chunk-IBDVZ6BF.js → chunk-MX6DK246.js} +69 -74
- package/dist/chunk-MX6DK246.js.map +1 -0
- package/dist/{chunk-DGHPOWLU.js → chunk-MYAXI33P.js} +8 -8
- package/dist/{chunk-DGHPOWLU.js.map → chunk-MYAXI33P.js.map} +1 -1
- package/dist/{chunk-YJWKHCOB.js → chunk-NDROQRDB.js} +13 -11
- package/dist/chunk-NDROQRDB.js.map +1 -0
- package/dist/{chunk-RI6JZUAE.js → chunk-NJIHMZPC.js} +7 -8
- package/dist/chunk-NJIHMZPC.js.map +1 -0
- package/dist/{chunk-KHFNPPOX.mjs → chunk-NQ2P7AB3.mjs} +31 -42
- package/dist/chunk-NQ2P7AB3.mjs.map +1 -0
- package/dist/{chunk-PST3NOEM.mjs → chunk-O237KKCX.mjs} +4 -4
- package/dist/{chunk-PST3NOEM.mjs.map → chunk-O237KKCX.mjs.map} +1 -1
- package/dist/chunk-Q2NBD54V.js +69 -0
- package/dist/chunk-Q2NBD54V.js.map +1 -0
- package/dist/chunk-QLM7RNQI.mjs +6 -0
- package/dist/chunk-QLM7RNQI.mjs.map +1 -0
- package/dist/chunk-SBT4J733.mjs +259 -0
- package/dist/chunk-SBT4J733.mjs.map +1 -0
- package/dist/{chunk-EBJ4S5DU.js → chunk-SGPIGHMN.js} +4 -4
- package/dist/{chunk-EBJ4S5DU.js.map → chunk-SGPIGHMN.js.map} +1 -1
- package/dist/chunk-V6NVBFEP.js +54 -0
- package/dist/chunk-V6NVBFEP.js.map +1 -0
- package/dist/{chunk-KMZ527EM.mjs → chunk-VTHCUHMK.mjs} +34 -8
- package/dist/chunk-VTHCUHMK.mjs.map +1 -0
- package/dist/chunk-WAAFJPNR.js +8 -0
- package/dist/chunk-WAAFJPNR.js.map +1 -0
- package/dist/chunk-WZHWWOUC.js +51 -0
- package/dist/chunk-WZHWWOUC.js.map +1 -0
- package/dist/chunk-X3S6KXAP.mjs +47 -0
- package/dist/chunk-X3S6KXAP.mjs.map +1 -0
- package/dist/chunk-X4OPM3SK.mjs +43 -0
- package/dist/chunk-X4OPM3SK.mjs.map +1 -0
- package/dist/{chunk-T4QBSRA4.mjs → chunk-XHEXIYKY.mjs} +37 -60
- package/dist/chunk-XHEXIYKY.mjs.map +1 -0
- package/dist/{chunk-IFVMZFNT.js → chunk-XM67L4HL.js} +41 -79
- package/dist/chunk-XM67L4HL.js.map +1 -0
- package/dist/chunk-ZPLN537Q.mjs +57 -0
- package/dist/chunk-ZPLN537Q.mjs.map +1 -0
- package/dist/cli/index.js +8986 -1276
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +8972 -1280
- package/dist/cli/index.mjs.map +1 -1
- package/dist/commerce/index.js +50 -48
- package/dist/commerce/index.mjs +5 -3
- package/dist/engage/index.js +11 -8
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +8 -5
- package/dist/engage/index.mjs.map +1 -1
- package/dist/fleet/contract.d.mts +99 -0
- package/dist/fleet/contract.d.ts +99 -0
- package/dist/fleet/contract.js +53 -0
- package/dist/fleet/contract.js.map +1 -0
- package/dist/fleet/contract.mjs +4 -0
- package/dist/fleet/contract.mjs.map +1 -0
- package/dist/fleet/index.d.mts +89 -0
- package/dist/fleet/index.d.ts +89 -0
- package/dist/fleet/index.js +74 -0
- package/dist/fleet/index.js.map +1 -0
- package/dist/fleet/index.mjs +9 -0
- package/dist/fleet/index.mjs.map +1 -0
- package/dist/forms/contract.d.mts +69 -0
- package/dist/forms/contract.d.ts +69 -0
- package/dist/forms/contract.js +33 -0
- package/dist/forms/contract.js.map +1 -0
- package/dist/forms/contract.mjs +4 -0
- package/dist/forms/contract.mjs.map +1 -0
- package/dist/forms/index.js +27 -23
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +20 -16
- package/dist/forms/index.mjs.map +1 -1
- package/dist/forms/styles.css +14 -10
- package/dist/images/index.js +10 -8
- package/dist/images/index.mjs +3 -1
- package/dist/index.js +103 -102
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -13
- package/dist/index.mjs.map +1 -1
- package/dist/layout/client.d.mts +8 -1
- package/dist/layout/client.d.ts +8 -1
- package/dist/layout/client.js +8 -3
- package/dist/layout/client.mjs +7 -2
- package/dist/layout/index.d.mts +7 -1
- package/dist/layout/index.d.ts +7 -1
- package/dist/layout/index.js +57 -4
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/index.mjs +56 -3
- package/dist/layout/index.mjs.map +1 -1
- package/dist/maps/index.d.mts +4 -2
- package/dist/maps/index.d.ts +4 -2
- package/dist/maps/index.js +9 -18
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/index.mjs +9 -18
- package/dist/maps/index.mjs.map +1 -1
- package/dist/portfolio/contract.d.mts +61 -0
- package/dist/portfolio/contract.d.ts +61 -0
- package/dist/portfolio/contract.js +43 -0
- package/dist/portfolio/contract.js.map +1 -0
- package/dist/portfolio/contract.mjs +38 -0
- package/dist/portfolio/contract.mjs.map +1 -0
- package/dist/seo/client.js +4 -2
- package/dist/seo/client.mjs +3 -1
- package/dist/seo/index.js +4 -2
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +3 -1
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo-pages/contract.d.mts +62 -0
- package/dist/seo-pages/contract.d.ts +62 -0
- package/dist/seo-pages/contract.js +48 -0
- package/dist/seo-pages/contract.js.map +1 -0
- package/dist/seo-pages/contract.mjs +44 -0
- package/dist/seo-pages/contract.mjs.map +1 -0
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sites/contract.d.mts +57 -0
- package/dist/sites/contract.d.ts +57 -0
- package/dist/sites/contract.js +37 -0
- package/dist/sites/contract.js.map +1 -0
- package/dist/sites/contract.mjs +4 -0
- package/dist/sites/contract.mjs.map +1 -0
- package/dist/sync/index.js +15 -13
- package/dist/sync/index.mjs +3 -1
- package/package.json +44 -4
- package/skills/site-kit/SKILL.md +66 -0
- package/dist/AnalyticsProvider-MLT26JRP.mjs +0 -6
- package/dist/AnalyticsProvider-WTOGN7LV.js +0 -27
- package/dist/BlogPostFaqSection-H556RV62.js +0 -13
- package/dist/ChatWidget-MAL7FB4M.js +0 -14
- package/dist/ChatWidget-QPZTPSPE.mjs +0 -5
- package/dist/EngageWidget-IPBUA4DW.mjs +0 -5
- package/dist/EngageWidget-N3CABK3L.js +0 -14
- package/dist/SignalCore-4MDIJUAP.mjs.map +0 -1
- package/dist/SignalCore-ZMFUE3N4.js.map +0 -1
- package/dist/SitemapSync-FUCH6Y6J.js +0 -13
- package/dist/SitemapSync-LCSPRAWU.mjs +0 -4
- package/dist/chunk-3GCEFS73.js.map +0 -1
- package/dist/chunk-3YQCPLGP.mjs.map +0 -1
- package/dist/chunk-5AESOLXS.mjs.map +0 -1
- package/dist/chunk-65SMJBHW.mjs.map +0 -1
- package/dist/chunk-FMZOZQBV.mjs.map +0 -1
- package/dist/chunk-I2GTT2DG.js.map +0 -1
- package/dist/chunk-IBDVZ6BF.js.map +0 -1
- package/dist/chunk-IFVMZFNT.js.map +0 -1
- package/dist/chunk-KHFNPPOX.mjs.map +0 -1
- package/dist/chunk-KMZ527EM.mjs.map +0 -1
- package/dist/chunk-MLJXELPA.js.map +0 -1
- package/dist/chunk-NNZDHLXN.js.map +0 -1
- package/dist/chunk-QTWA44S3.mjs.map +0 -1
- package/dist/chunk-RI6JZUAE.js.map +0 -1
- package/dist/chunk-T4QBSRA4.mjs.map +0 -1
- package/dist/chunk-TCVHI3JP.mjs.map +0 -1
- package/dist/chunk-VCWSSGCU.js.map +0 -1
- package/dist/chunk-YJWKHCOB.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sites/contract.ts"],"names":[],"mappings":";;;AAgBO,IAAM,0BAAA,GAA6B;AAanC,SAAS,kBAAkB,IAAA,EAAqC;AACrE,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,IAAA;AAC9C,EAAA,IAAI,CAAA,GAAI,IAAA,CAAK,IAAA,EAAK,CAAE,WAAA,EAAY;AAChC,EAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AAEf,EAAA,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,cAAA,EAAgB,EAAE,CAAA;AAEhC,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,IAAI,SAAS,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,GAAG,KAAK,CAAA;AAEpC,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,IAAI,SAAS,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,GAAG,KAAK,CAAA;AACpC,EAAA,OAAO,CAAA,IAAK,IAAA;AACd;AAGO,SAAS,SAAS,IAAA,EAAsB;AAC7C,EAAA,OAAO,KAAK,UAAA,CAAW,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA;AACnD;AAOO,SAAS,QAAA,CAAS,GAA8B,CAAA,EAAuC;AAC5F,EAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,EAAG,OAAO,KAAA;AACrB,EAAA,OAAO,QAAA,CAAS,CAAC,CAAA,KAAM,QAAA,CAAS,CAAC,CAAA;AACnC;AAMO,SAAS,YAAY,KAAA,EAAiD;AAC3E,EAAA,IAAI,CAAC,KAAA,IAAU,CAAC,KAAA,CAAM,UAAA,CAAW,SAAS,CAAA,IAAK,CAAC,KAAA,CAAM,UAAA,CAAW,UAAU,CAAA,EAAI,OAAO,IAAA;AACtF,EAAA,IAAI;AACF,IAAA,OAAO,iBAAA,CAAkB,IAAI,GAAA,CAAI,KAAK,EAAE,IAAI,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGO,SAAS,qBAAqB,KAAA,EAAiC;AACpE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,CAAM,SAAS,CAAA,IAAK,iBAAA,CAAkB,KAAK,CAAA,KAAM,KAAA;AACvF;AAMO,IAAM,qBAAA,GAAwB;AAAA,EACnC,OAAA,EAAS,yCAAA;AAAA,EACT,GAAA,EAAK,4CAAA;AAAA,EACL,KAAA,EAAO,oBAAA;AAAA,EACP,WAAA,EACE,yJAAA;AAAA,EACF,IAAA,EAAM,CAAC,QAAA,EAAU,MAAM,CAAA;AAAA,EACvB,OAAA,EAAS;AACX","file":"chunk-WZHWWOUC.js","sourcesContent":["/**\n * @sonordev/site-kit/sites/contract — Multi-site \"site\" dimension host contract (v1)\n *\n * Single source of truth for normalizing and comparing sub-site host values\n * (the multi-site `site` dimension, see CLAUDE.md). Same pattern as\n * `@sonordev/site-kit/llms/contract` and `@sonordev/site-kit/slots/contract`:\n * site-kit owns the canonical logic; the Nest APIs keep byte-identical inline\n * mirrors (sonor-api `src/common/utils/site-host.ts`, signal-api\n * `src/shared/utils/seo-page-pick.util.ts`) guarded by the shared drift-test\n * vectors in `contract.test.ts` — so a divergent copy fails CI on either side.\n *\n * Pure string logic only (no Node built-ins) so it is safe in the browser:\n * site-kit itself normalizes `__SITE_KIT_SITE__` with `normalizeSiteHost`.\n */\n\n/** Bump on breaking changes to the normalized host shape. */\nexport const SITE_HOST_CONTRACT_VERSION = 1 as const\n\n/**\n * normalizeSiteHost — canonical normalizer for a sub-site host value before it\n * is persisted or used as a filter.\n *\n * `https://OhioPowerStudies.com:3000/path` → `ohiopowerstudies.com`\n *\n * Lowercases, strips protocol, keeps host only (drops path + query), strips\n * port (rollups span dev/prod). Returns null for empty/non-string input.\n * Note: `www.` is intentionally preserved here — use `sameSite`/`stripWww`\n * for www-insensitive equality.\n */\nexport function normalizeSiteHost(site?: string | null): string | null {\n if (!site || typeof site !== 'string') return null\n let s = site.trim().toLowerCase()\n if (!s) return null\n // Strip protocol if present\n s = s.replace(/^https?:\\/\\//, '')\n // Keep host only — drop everything from first slash onward\n const slash = s.indexOf('/')\n if (slash >= 0) s = s.slice(0, slash)\n // Strip port (rollups span dev/prod)\n const colon = s.indexOf(':')\n if (colon >= 0) s = s.slice(0, colon)\n return s || null\n}\n\n/** Strip a leading `www.` from a host (\"www.tps.com\" → \"tps.com\"). */\nexport function stripWww(host: string): string {\n return host.startsWith('www.') ? host.slice(4) : host\n}\n\n/**\n * www-insensitive sub-site host equality — `www.a.com` and `a.com` are the\n * same site. Operands are expected already-normalized (lowercase host);\n * returns false if either side is missing.\n */\nexport function sameSite(a: string | null | undefined, b: string | null | undefined): boolean {\n if (!a || !b) return false\n return stripWww(a) === stripWww(b)\n}\n\n/**\n * Host of a full URL (\"https://ohiopowerstudies.com/x\" → \"ohiopowerstudies.com\"),\n * null for site-relative paths (\"/services\") and unparseable input.\n */\nexport function hostFromUrl(value: string | null | undefined): string | null {\n if (!value || (!value.startsWith('http://') && !value.startsWith('https://'))) return null\n try {\n return normalizeSiteHost(new URL(value).host)\n } catch {\n return null\n }\n}\n\n/** True when `value` is a non-empty normalized host (lowercase, no protocol/path/port). */\nexport function isNormalizedSiteHost(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && normalizeSiteHost(value) === value\n}\n\n/**\n * Agent-native contract: JSON Schema for a normalized `site` value, so services\n * and agents can validate the dimension mechanically without importing the code.\n */\nexport const SITE_HOST_JSON_SCHEMA = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n $id: 'https://sonor.io/schemas/site-host.v1.json',\n title: 'NormalizedSiteHost',\n description:\n 'A normalized sub-site host (the multi-site `site` dimension): lowercase, no protocol, no path, no port. null denotes a project-wide (unattributed) row.',\n type: ['string', 'null'],\n pattern: '^[a-z0-9.-]+$',\n} as const\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/forms/contract.ts
|
|
2
|
+
var FORMS_HONEYPOT_CONTRACT_VERSION = 1;
|
|
3
|
+
var DEFAULT_HONEYPOT_FIELD = "_sk_hp_url";
|
|
4
|
+
var GENERIC_HONEYPOT_FIELDS = Object.freeze([
|
|
5
|
+
DEFAULT_HONEYPOT_FIELD,
|
|
6
|
+
"website",
|
|
7
|
+
"_hp_field",
|
|
8
|
+
"bot-field",
|
|
9
|
+
"bot_field"
|
|
10
|
+
]);
|
|
11
|
+
function resolveHoneypotFieldNames(opts) {
|
|
12
|
+
const names = /* @__PURE__ */ new Set();
|
|
13
|
+
if (!opts.enabled) return names;
|
|
14
|
+
const real = new Set(opts.realFieldSlugs ?? []);
|
|
15
|
+
for (const generic of GENERIC_HONEYPOT_FIELDS) {
|
|
16
|
+
if (!real.has(generic)) names.add(generic);
|
|
17
|
+
}
|
|
18
|
+
if (opts.formHoneypotField) names.add(opts.formHoneypotField);
|
|
19
|
+
return names;
|
|
20
|
+
}
|
|
21
|
+
function isHoneypotTriggered(data, fieldNames) {
|
|
22
|
+
for (const fieldName of fieldNames) {
|
|
23
|
+
const value = data?.[fieldName];
|
|
24
|
+
if (value == null) continue;
|
|
25
|
+
if (typeof value !== "string" || value.trim() !== "") return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
var HONEYPOT_CONFIG_JSON_SCHEMA = {
|
|
30
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
31
|
+
$id: "https://sonor.io/schemas/honeypot-config.v1.json",
|
|
32
|
+
title: "HoneypotConfig",
|
|
33
|
+
description: "The honeypot slice of a public managed-form config.",
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
honeypot_enabled: { type: "boolean" },
|
|
37
|
+
honeypot_field: {
|
|
38
|
+
description: `Trap field name; defaults to "${DEFAULT_HONEYPOT_FIELD}" when unset.`,
|
|
39
|
+
type: "string"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
additionalProperties: true
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export { DEFAULT_HONEYPOT_FIELD, FORMS_HONEYPOT_CONTRACT_VERSION, GENERIC_HONEYPOT_FIELDS, HONEYPOT_CONFIG_JSON_SCHEMA, isHoneypotTriggered, resolveHoneypotFieldNames };
|
|
46
|
+
//# sourceMappingURL=chunk-X3S6KXAP.mjs.map
|
|
47
|
+
//# sourceMappingURL=chunk-X3S6KXAP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/contract.ts"],"names":[],"mappings":";AAkBO,IAAM,+BAAA,GAAkC;AAOxC,IAAM,sBAAA,GAAyB;AAO/B,IAAM,uBAAA,GAA6C,OAAO,MAAA,CAAO;AAAA,EACtE,sBAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAC;AAQM,SAAS,0BAA0B,IAAA,EAI1B;AACd,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAY;AAC9B,EAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,OAAO,KAAA;AAC1B,EAAA,MAAM,OAAO,IAAI,GAAA,CAAI,IAAA,CAAK,cAAA,IAAkB,EAAE,CAAA;AAC9C,EAAA,KAAA,MAAW,WAAW,uBAAA,EAAyB;AAC7C,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA,EAAG,KAAA,CAAM,IAAI,OAAO,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,IAAA,CAAK,iBAAA,EAAmB,KAAA,CAAM,GAAA,CAAI,KAAK,iBAAiB,CAAA;AAC5D,EAAA,OAAO,KAAA;AACT;AAMO,SAAS,mBAAA,CACd,MACA,UAAA,EACS;AACT,EAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,IAAA,MAAM,KAAA,GAAQ,OAAO,SAAS,CAAA;AAC9B,IAAA,IAAI,SAAS,IAAA,EAAM;AAGnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,MAAM,IAAA,EAAK,KAAM,IAAI,OAAO,IAAA;AAAA,EAC/D;AACA,EAAA,OAAO,KAAA;AACT;AAMO,IAAM,2BAAA,GAA8B;AAAA,EACzC,OAAA,EAAS,yCAAA;AAAA,EACT,GAAA,EAAK,kDAAA;AAAA,EACL,KAAA,EAAO,gBAAA;AAAA,EACP,WAAA,EAAa,qDAAA;AAAA,EACb,IAAA,EAAM,QAAA;AAAA,EACN,UAAA,EAAY;AAAA,IACV,gBAAA,EAAkB,EAAE,IAAA,EAAM,SAAA,EAAU;AAAA,IACpC,cAAA,EAAgB;AAAA,MACd,WAAA,EAAa,iCAAiC,sBAAsB,CAAA,aAAA,CAAA;AAAA,MACpE,IAAA,EAAM;AAAA;AACR,GACF;AAAA,EACA,oBAAA,EAAsB;AACxB","file":"chunk-X3S6KXAP.mjs","sourcesContent":["/**\n * @sonordev/site-kit/forms/contract — managed-form honeypot policy (v1)\n *\n * Single source of truth for the honeypot trap-field naming + server-side\n * detection policy, shared by the client (site-kit emits the trap field) and\n * the server (sonor-api names the trap in the form config it returns AND\n * detects hits on intake). Same pattern as the other site-kit contracts:\n * sonor-api keeps a byte-identical inline mirror\n * (`src/modules/forms/honeypot-contract.ts`) guarded by the shared drift-test\n * vectors in `contract.test.ts`.\n *\n * The default field name (`_sk_hp_url`) is deliberately obscure: a common name\n * like \"website\" collides with real form fields and flags genuine submissions\n * as spam, so generic names are only trusted when they DON'T match a real\n * field of the form (see `resolveHoneypotFieldNames`).\n */\n\n/** Bump on breaking changes to the honeypot policy. */\nexport const FORMS_HONEYPOT_CONTRACT_VERSION = 1 as const\n\n/**\n * Default honeypot field name emitted by site-kit and used by the server as the\n * fallback trap name when a form has no explicitly configured `honeypot_field`.\n * Deliberately obscure to avoid colliding with real form fields.\n */\nexport const DEFAULT_HONEYPOT_FIELD = '_sk_hp_url'\n\n/**\n * Generic trap names the server also watches on intake — the canonical default\n * plus legacy names still emitted by older deployed forms. Each is only trusted\n * when it doesn't collide with a real configured field of the form.\n */\nexport const GENERIC_HONEYPOT_FIELDS: readonly string[] = Object.freeze([\n DEFAULT_HONEYPOT_FIELD,\n 'website',\n '_hp_field',\n 'bot-field',\n 'bot_field',\n])\n\n/**\n * Build the set of field names the server treats as honeypot traps for one form.\n * Generic names that collide with a real field slug are dropped (or every real\n * lead using that field would be flagged); the form's dedicated\n * `honeypot_field` is always honored. Returns an empty set when disabled.\n */\nexport function resolveHoneypotFieldNames(opts: {\n enabled: boolean\n formHoneypotField?: string | null\n realFieldSlugs?: Iterable<string>\n}): Set<string> {\n const names = new Set<string>()\n if (!opts.enabled) return names\n const real = new Set(opts.realFieldSlugs ?? [])\n for (const generic of GENERIC_HONEYPOT_FIELDS) {\n if (!real.has(generic)) names.add(generic)\n }\n if (opts.formHoneypotField) names.add(opts.formHoneypotField)\n return names\n}\n\n/**\n * True when any watched trap field carries a non-empty value — the marker of an\n * automated submission (real users never see or fill the trap).\n */\nexport function isHoneypotTriggered(\n data: Record<string, unknown> | null | undefined,\n fieldNames: Iterable<string>,\n): boolean {\n for (const fieldName of fieldNames) {\n const value = data?.[fieldName]\n if (value == null) continue\n // A filled trap is almost always a non-empty string; any non-string value a\n // bot injected (number/object/bool) also counts as filled.\n if (typeof value !== 'string' || value.trim() !== '') return true\n }\n return false\n}\n\n/**\n * Agent-native contract: JSON Schema for the honeypot slice of the public form\n * config, so services and agents can validate it mechanically.\n */\nexport const HONEYPOT_CONFIG_JSON_SCHEMA = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n $id: 'https://sonor.io/schemas/honeypot-config.v1.json',\n title: 'HoneypotConfig',\n description: 'The honeypot slice of a public managed-form config.',\n type: 'object',\n properties: {\n honeypot_enabled: { type: 'boolean' },\n honeypot_field: {\n description: `Trap field name; defaults to \"${DEFAULT_HONEYPOT_FIELD}\" when unset.`,\n type: 'string',\n },\n },\n additionalProperties: true,\n} as const\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/sites/contract.ts
|
|
2
|
+
var SITE_HOST_CONTRACT_VERSION = 1;
|
|
3
|
+
function normalizeSiteHost(site) {
|
|
4
|
+
if (!site || typeof site !== "string") return null;
|
|
5
|
+
let s = site.trim().toLowerCase();
|
|
6
|
+
if (!s) return null;
|
|
7
|
+
s = s.replace(/^https?:\/\//, "");
|
|
8
|
+
const slash = s.indexOf("/");
|
|
9
|
+
if (slash >= 0) s = s.slice(0, slash);
|
|
10
|
+
const colon = s.indexOf(":");
|
|
11
|
+
if (colon >= 0) s = s.slice(0, colon);
|
|
12
|
+
return s || null;
|
|
13
|
+
}
|
|
14
|
+
function stripWww(host) {
|
|
15
|
+
return host.startsWith("www.") ? host.slice(4) : host;
|
|
16
|
+
}
|
|
17
|
+
function sameSite(a, b) {
|
|
18
|
+
if (!a || !b) return false;
|
|
19
|
+
return stripWww(a) === stripWww(b);
|
|
20
|
+
}
|
|
21
|
+
function hostFromUrl(value) {
|
|
22
|
+
if (!value || !value.startsWith("http://") && !value.startsWith("https://")) return null;
|
|
23
|
+
try {
|
|
24
|
+
return normalizeSiteHost(new URL(value).host);
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function isNormalizedSiteHost(value) {
|
|
30
|
+
return typeof value === "string" && value.length > 0 && normalizeSiteHost(value) === value;
|
|
31
|
+
}
|
|
32
|
+
var SITE_HOST_JSON_SCHEMA = {
|
|
33
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
34
|
+
$id: "https://sonor.io/schemas/site-host.v1.json",
|
|
35
|
+
title: "NormalizedSiteHost",
|
|
36
|
+
description: "A normalized sub-site host (the multi-site `site` dimension): lowercase, no protocol, no path, no port. null denotes a project-wide (unattributed) row.",
|
|
37
|
+
type: ["string", "null"],
|
|
38
|
+
pattern: "^[a-z0-9.-]+$"
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { SITE_HOST_CONTRACT_VERSION, SITE_HOST_JSON_SCHEMA, hostFromUrl, isNormalizedSiteHost, normalizeSiteHost, sameSite, stripWww };
|
|
42
|
+
//# sourceMappingURL=chunk-X4OPM3SK.mjs.map
|
|
43
|
+
//# sourceMappingURL=chunk-X4OPM3SK.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sites/contract.ts"],"names":[],"mappings":";AAgBO,IAAM,0BAAA,GAA6B;AAanC,SAAS,kBAAkB,IAAA,EAAqC;AACrE,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,IAAA;AAC9C,EAAA,IAAI,CAAA,GAAI,IAAA,CAAK,IAAA,EAAK,CAAE,WAAA,EAAY;AAChC,EAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AAEf,EAAA,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,cAAA,EAAgB,EAAE,CAAA;AAEhC,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,IAAI,SAAS,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,GAAG,KAAK,CAAA;AAEpC,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,IAAI,SAAS,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,GAAG,KAAK,CAAA;AACpC,EAAA,OAAO,CAAA,IAAK,IAAA;AACd;AAGO,SAAS,SAAS,IAAA,EAAsB;AAC7C,EAAA,OAAO,KAAK,UAAA,CAAW,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA;AACnD;AAOO,SAAS,QAAA,CAAS,GAA8B,CAAA,EAAuC;AAC5F,EAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,EAAG,OAAO,KAAA;AACrB,EAAA,OAAO,QAAA,CAAS,CAAC,CAAA,KAAM,QAAA,CAAS,CAAC,CAAA;AACnC;AAMO,SAAS,YAAY,KAAA,EAAiD;AAC3E,EAAA,IAAI,CAAC,KAAA,IAAU,CAAC,KAAA,CAAM,UAAA,CAAW,SAAS,CAAA,IAAK,CAAC,KAAA,CAAM,UAAA,CAAW,UAAU,CAAA,EAAI,OAAO,IAAA;AACtF,EAAA,IAAI;AACF,IAAA,OAAO,iBAAA,CAAkB,IAAI,GAAA,CAAI,KAAK,EAAE,IAAI,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGO,SAAS,qBAAqB,KAAA,EAAiC;AACpE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,CAAM,SAAS,CAAA,IAAK,iBAAA,CAAkB,KAAK,CAAA,KAAM,KAAA;AACvF;AAMO,IAAM,qBAAA,GAAwB;AAAA,EACnC,OAAA,EAAS,yCAAA;AAAA,EACT,GAAA,EAAK,4CAAA;AAAA,EACL,KAAA,EAAO,oBAAA;AAAA,EACP,WAAA,EACE,yJAAA;AAAA,EACF,IAAA,EAAM,CAAC,QAAA,EAAU,MAAM,CAAA;AAAA,EACvB,OAAA,EAAS;AACX","file":"chunk-X4OPM3SK.mjs","sourcesContent":["/**\n * @sonordev/site-kit/sites/contract — Multi-site \"site\" dimension host contract (v1)\n *\n * Single source of truth for normalizing and comparing sub-site host values\n * (the multi-site `site` dimension, see CLAUDE.md). Same pattern as\n * `@sonordev/site-kit/llms/contract` and `@sonordev/site-kit/slots/contract`:\n * site-kit owns the canonical logic; the Nest APIs keep byte-identical inline\n * mirrors (sonor-api `src/common/utils/site-host.ts`, signal-api\n * `src/shared/utils/seo-page-pick.util.ts`) guarded by the shared drift-test\n * vectors in `contract.test.ts` — so a divergent copy fails CI on either side.\n *\n * Pure string logic only (no Node built-ins) so it is safe in the browser:\n * site-kit itself normalizes `__SITE_KIT_SITE__` with `normalizeSiteHost`.\n */\n\n/** Bump on breaking changes to the normalized host shape. */\nexport const SITE_HOST_CONTRACT_VERSION = 1 as const\n\n/**\n * normalizeSiteHost — canonical normalizer for a sub-site host value before it\n * is persisted or used as a filter.\n *\n * `https://OhioPowerStudies.com:3000/path` → `ohiopowerstudies.com`\n *\n * Lowercases, strips protocol, keeps host only (drops path + query), strips\n * port (rollups span dev/prod). Returns null for empty/non-string input.\n * Note: `www.` is intentionally preserved here — use `sameSite`/`stripWww`\n * for www-insensitive equality.\n */\nexport function normalizeSiteHost(site?: string | null): string | null {\n if (!site || typeof site !== 'string') return null\n let s = site.trim().toLowerCase()\n if (!s) return null\n // Strip protocol if present\n s = s.replace(/^https?:\\/\\//, '')\n // Keep host only — drop everything from first slash onward\n const slash = s.indexOf('/')\n if (slash >= 0) s = s.slice(0, slash)\n // Strip port (rollups span dev/prod)\n const colon = s.indexOf(':')\n if (colon >= 0) s = s.slice(0, colon)\n return s || null\n}\n\n/** Strip a leading `www.` from a host (\"www.tps.com\" → \"tps.com\"). */\nexport function stripWww(host: string): string {\n return host.startsWith('www.') ? host.slice(4) : host\n}\n\n/**\n * www-insensitive sub-site host equality — `www.a.com` and `a.com` are the\n * same site. Operands are expected already-normalized (lowercase host);\n * returns false if either side is missing.\n */\nexport function sameSite(a: string | null | undefined, b: string | null | undefined): boolean {\n if (!a || !b) return false\n return stripWww(a) === stripWww(b)\n}\n\n/**\n * Host of a full URL (\"https://ohiopowerstudies.com/x\" → \"ohiopowerstudies.com\"),\n * null for site-relative paths (\"/services\") and unparseable input.\n */\nexport function hostFromUrl(value: string | null | undefined): string | null {\n if (!value || (!value.startsWith('http://') && !value.startsWith('https://'))) return null\n try {\n return normalizeSiteHost(new URL(value).host)\n } catch {\n return null\n }\n}\n\n/** True when `value` is a non-empty normalized host (lowercase, no protocol/path/port). */\nexport function isNormalizedSiteHost(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && normalizeSiteHost(value) === value\n}\n\n/**\n * Agent-native contract: JSON Schema for a normalized `site` value, so services\n * and agents can validate the dimension mechanically without importing the code.\n */\nexport const SITE_HOST_JSON_SCHEMA = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n $id: 'https://sonor.io/schemas/site-host.v1.json',\n title: 'NormalizedSiteHost',\n description:\n 'A normalized sub-site host (the multi-site `site` dimension): lowercase, no protocol, no path, no port. null denotes a project-wide (unattributed) row.',\n type: ['string', 'null'],\n pattern: '^[a-z0-9.-]+$',\n} as const\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useAnalyticsOptional } from './chunk-
|
|
2
|
+
import { useAnalyticsOptional } from './chunk-IR5UC236.mjs';
|
|
3
|
+
import { sonorFetch } from './chunk-SBT4J733.mjs';
|
|
3
4
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
5
|
import React5, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
|
|
5
6
|
|
|
@@ -101,18 +102,15 @@ function getApiKey() {
|
|
|
101
102
|
async function apiPost(endpoint, body = {}) {
|
|
102
103
|
const { apiUrl, apiKey } = getApiConfig();
|
|
103
104
|
if (!apiKey) {
|
|
104
|
-
console.
|
|
105
|
+
console.warn("[Commerce] No API key configured");
|
|
105
106
|
return null;
|
|
106
107
|
}
|
|
107
108
|
try {
|
|
108
|
-
const response = await
|
|
109
|
+
const response = await sonorFetch(`${apiUrl}${endpoint}`, {
|
|
109
110
|
method: "POST",
|
|
110
|
-
headers: {
|
|
111
|
-
"Content-Type": "application/json",
|
|
112
|
-
"x-api-key": apiKey
|
|
113
|
-
},
|
|
111
|
+
headers: { "Content-Type": "application/json" },
|
|
114
112
|
body: JSON.stringify(body)
|
|
115
|
-
});
|
|
113
|
+
}, { apiKey });
|
|
116
114
|
if (!response.ok) {
|
|
117
115
|
const text = await response.text();
|
|
118
116
|
let body2 = null;
|
|
@@ -121,12 +119,12 @@ async function apiPost(endpoint, body = {}) {
|
|
|
121
119
|
} catch {
|
|
122
120
|
body2 = text;
|
|
123
121
|
}
|
|
124
|
-
console.
|
|
122
|
+
console.warn(`[Commerce] API error:`, response.status, response.statusText || "Unknown", body2);
|
|
125
123
|
return null;
|
|
126
124
|
}
|
|
127
125
|
return await response.json();
|
|
128
126
|
} catch (error) {
|
|
129
|
-
console.
|
|
127
|
+
console.warn("[Commerce] Network error:", error);
|
|
130
128
|
return null;
|
|
131
129
|
}
|
|
132
130
|
}
|
|
@@ -266,14 +264,11 @@ async function fetchActiveProcessor() {
|
|
|
266
264
|
const { apiUrl, apiKey } = getApiConfig();
|
|
267
265
|
if (!apiKey) return null;
|
|
268
266
|
try {
|
|
269
|
-
const response = await
|
|
267
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/processor`, {
|
|
270
268
|
method: "POST",
|
|
271
|
-
headers: {
|
|
272
|
-
"Content-Type": "application/json",
|
|
273
|
-
"x-api-key": apiKey
|
|
274
|
-
},
|
|
269
|
+
headers: { "Content-Type": "application/json" },
|
|
275
270
|
body: JSON.stringify({})
|
|
276
|
-
});
|
|
271
|
+
}, { apiKey });
|
|
277
272
|
if (!response.ok) return null;
|
|
278
273
|
const data = await response.json();
|
|
279
274
|
return data?.processor || null;
|
|
@@ -285,12 +280,9 @@ async function registerForEvent(eventId, scheduleId, customer) {
|
|
|
285
280
|
const { apiUrl, apiKey } = getApiConfig();
|
|
286
281
|
const analyticsSessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_sk_sid") : null;
|
|
287
282
|
try {
|
|
288
|
-
const response = await
|
|
283
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/register`, {
|
|
289
284
|
method: "POST",
|
|
290
|
-
headers: {
|
|
291
|
-
"Content-Type": "application/json",
|
|
292
|
-
"x-api-key": apiKey
|
|
293
|
-
},
|
|
285
|
+
headers: { "Content-Type": "application/json" },
|
|
294
286
|
body: JSON.stringify({
|
|
295
287
|
offeringId: eventId,
|
|
296
288
|
scheduleId,
|
|
@@ -298,7 +290,7 @@ async function registerForEvent(eventId, scheduleId, customer) {
|
|
|
298
290
|
analyticsSessionId
|
|
299
291
|
// Pass for conversion tracking
|
|
300
292
|
})
|
|
301
|
-
});
|
|
293
|
+
}, { apiKey, retries: 0 });
|
|
302
294
|
if (!response.ok) {
|
|
303
295
|
const error = await response.json();
|
|
304
296
|
return { success: false, error: error.message || "Registration failed" };
|
|
@@ -316,14 +308,11 @@ async function registerForEvent(eventId, scheduleId, customer) {
|
|
|
316
308
|
async function validateDiscountCode(code, subtotal, offeringIds = []) {
|
|
317
309
|
const { apiUrl, apiKey } = getApiConfig();
|
|
318
310
|
try {
|
|
319
|
-
const response = await
|
|
311
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/discount/validate`, {
|
|
320
312
|
method: "POST",
|
|
321
|
-
headers: {
|
|
322
|
-
"Content-Type": "application/json",
|
|
323
|
-
"x-api-key": apiKey
|
|
324
|
-
},
|
|
313
|
+
headers: { "Content-Type": "application/json" },
|
|
325
314
|
body: JSON.stringify({ code, subtotal, offeringIds })
|
|
326
|
-
});
|
|
315
|
+
}, { apiKey });
|
|
327
316
|
if (!response.ok) {
|
|
328
317
|
const body = await response.json().catch(() => ({}));
|
|
329
318
|
return { valid: false, message: body?.message || "Invalid discount code" };
|
|
@@ -337,14 +326,11 @@ async function fetchProcessorConfig() {
|
|
|
337
326
|
const { apiUrl, apiKey } = getApiConfig();
|
|
338
327
|
if (!apiKey) return null;
|
|
339
328
|
try {
|
|
340
|
-
const response = await
|
|
329
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/processor-config`, {
|
|
341
330
|
method: "POST",
|
|
342
|
-
headers: {
|
|
343
|
-
"Content-Type": "application/json",
|
|
344
|
-
"x-api-key": apiKey
|
|
345
|
-
},
|
|
331
|
+
headers: { "Content-Type": "application/json" },
|
|
346
332
|
body: JSON.stringify({})
|
|
347
|
-
});
|
|
333
|
+
}, { apiKey });
|
|
348
334
|
if (!response.ok) return null;
|
|
349
335
|
return await response.json();
|
|
350
336
|
} catch {
|
|
@@ -356,17 +342,14 @@ async function createPaymentIntent(options) {
|
|
|
356
342
|
const apiKey = getApiKey();
|
|
357
343
|
const sessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_sk_sid") : null;
|
|
358
344
|
try {
|
|
359
|
-
const response = await
|
|
345
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/create-payment-intent`, {
|
|
360
346
|
method: "POST",
|
|
361
|
-
headers: {
|
|
362
|
-
"Content-Type": "application/json",
|
|
363
|
-
"x-api-key": apiKey
|
|
364
|
-
},
|
|
347
|
+
headers: { "Content-Type": "application/json" },
|
|
365
348
|
body: JSON.stringify({
|
|
366
349
|
...options,
|
|
367
350
|
analyticsSessionId: sessionId
|
|
368
351
|
})
|
|
369
|
-
});
|
|
352
|
+
}, { apiKey, retries: 0 });
|
|
370
353
|
const data = await response.json();
|
|
371
354
|
if (!response.ok) throw new Error(data.message || "Failed to create payment intent");
|
|
372
355
|
return data;
|
|
@@ -379,12 +362,9 @@ async function createCheckoutSession(optionsOrOfferingId, legacyOptions) {
|
|
|
379
362
|
const options = typeof optionsOrOfferingId === "string" ? { offeringId: optionsOrOfferingId, ...legacyOptions } : optionsOrOfferingId;
|
|
380
363
|
const analyticsSessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_sk_sid") : null;
|
|
381
364
|
try {
|
|
382
|
-
const response = await
|
|
365
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/checkout`, {
|
|
383
366
|
method: "POST",
|
|
384
|
-
headers: {
|
|
385
|
-
"Content-Type": "application/json",
|
|
386
|
-
"x-api-key": apiKey
|
|
387
|
-
},
|
|
367
|
+
headers: { "Content-Type": "application/json" },
|
|
388
368
|
body: JSON.stringify({
|
|
389
369
|
...options,
|
|
390
370
|
analyticsSessionId,
|
|
@@ -392,7 +372,7 @@ async function createCheckoutSession(optionsOrOfferingId, legacyOptions) {
|
|
|
392
372
|
successUrl: options.successUrl || (typeof window !== "undefined" ? window.location.href : ""),
|
|
393
373
|
cancelUrl: options.cancelUrl || (typeof window !== "undefined" ? window.location.href : "")
|
|
394
374
|
})
|
|
395
|
-
});
|
|
375
|
+
}, { apiKey, retries: 0 });
|
|
396
376
|
if (!response.ok) {
|
|
397
377
|
const text = await response.text();
|
|
398
378
|
let body = {};
|
|
@@ -402,8 +382,8 @@ async function createCheckoutSession(optionsOrOfferingId, legacyOptions) {
|
|
|
402
382
|
}
|
|
403
383
|
const errObj = body?.error && typeof body.error === "object" ? body.error : body;
|
|
404
384
|
const message = (typeof body?.message === "string" ? body.message : null) || (typeof errObj?.message === "string" ? errObj.message : null) || (typeof errObj?.detail === "string" ? errObj.detail : null) || (typeof body?.error === "string" ? body.error : null) || "Payment could not be processed. Please try again or use a different card.";
|
|
405
|
-
if (typeof console !== "undefined"
|
|
406
|
-
console.
|
|
385
|
+
if (typeof console !== "undefined") {
|
|
386
|
+
console.warn("[Commerce] Checkout failed:", response.status, message, body);
|
|
407
387
|
}
|
|
408
388
|
return { success: false, error: message };
|
|
409
389
|
}
|
|
@@ -687,7 +667,7 @@ function OfferingList({
|
|
|
687
667
|
}
|
|
688
668
|
setOfferings(data);
|
|
689
669
|
} catch (e) {
|
|
690
|
-
console.
|
|
670
|
+
console.warn("Failed to load offerings:", e);
|
|
691
671
|
setError("Failed to load items.");
|
|
692
672
|
} finally {
|
|
693
673
|
setLoading(false);
|
|
@@ -1175,7 +1155,7 @@ function ProductEmbed({
|
|
|
1175
1155
|
}
|
|
1176
1156
|
setProduct(data);
|
|
1177
1157
|
} catch (e) {
|
|
1178
|
-
console.
|
|
1158
|
+
console.warn("Failed to load product:", e);
|
|
1179
1159
|
} finally {
|
|
1180
1160
|
setLoading(false);
|
|
1181
1161
|
}
|
|
@@ -3952,7 +3932,7 @@ function ProductGrid({
|
|
|
3952
3932
|
setProducts(data);
|
|
3953
3933
|
setTotal(count);
|
|
3954
3934
|
} catch (e) {
|
|
3955
|
-
console.
|
|
3935
|
+
console.warn("Failed to load products:", e);
|
|
3956
3936
|
} finally {
|
|
3957
3937
|
setLoading(false);
|
|
3958
3938
|
}
|
|
@@ -7121,26 +7101,23 @@ function EventsWidget({
|
|
|
7121
7101
|
setLoading(true);
|
|
7122
7102
|
setError(null);
|
|
7123
7103
|
try {
|
|
7124
|
-
const response = await
|
|
7104
|
+
const response = await sonorFetch(`${apiUrl}/api/public/commerce/events`, {
|
|
7125
7105
|
method: "POST",
|
|
7126
|
-
headers: {
|
|
7127
|
-
"Content-Type": "application/json",
|
|
7128
|
-
"x-api-key": apiKey
|
|
7129
|
-
},
|
|
7106
|
+
headers: { "Content-Type": "application/json" },
|
|
7130
7107
|
body: JSON.stringify({
|
|
7131
7108
|
type: "event",
|
|
7132
7109
|
category,
|
|
7133
7110
|
limit: limit * 2
|
|
7134
7111
|
// Fetch extra for calendar view
|
|
7135
7112
|
})
|
|
7136
|
-
});
|
|
7113
|
+
}, { apiKey });
|
|
7137
7114
|
if (!response.ok) {
|
|
7138
7115
|
throw new Error("Failed to fetch events");
|
|
7139
7116
|
}
|
|
7140
7117
|
const data = await response.json();
|
|
7141
7118
|
setEvents(data.events || []);
|
|
7142
7119
|
} catch (err) {
|
|
7143
|
-
console.
|
|
7120
|
+
console.warn("Error loading events:", err);
|
|
7144
7121
|
setError("Unable to load events. Please try again later.");
|
|
7145
7122
|
} finally {
|
|
7146
7123
|
setLoading(false);
|
|
@@ -7759,5 +7736,5 @@ function groupEventsByOffering(events) {
|
|
|
7759
7736
|
}
|
|
7760
7737
|
|
|
7761
7738
|
export { CalendarView, CheckoutForm, EventCalendar, EventCheckout, EventEmbed, EventModal, EventTile, EventsWidget, OfferingCard, OfferingList, ProductDetail, ProductEmbed, ProductGrid, ProductPage, RegistrationForm, SizeChart, UpcomingEvents, createCheckoutSession, createPaymentIntent, fetchActiveProcessor, fetchCategories, fetchLatestOffering, fetchNextEvent, fetchOffering, fetchOfferings, fetchProcessorConfig, fetchProductBySlug, fetchProducts, fetchProductsPublic, fetchServices, fetchShippingRates, fetchUpcomingEvents, formatDate, formatDateRange, formatDateTime, formatPrice, formatTime, getOfferingUrl, getRelativeTimeUntil, getSpotsRemaining, isEventSoldOut, registerForEvent, useEventModal, validateAddress, validateDiscountCode };
|
|
7762
|
-
//# sourceMappingURL=chunk-
|
|
7763
|
-
//# sourceMappingURL=chunk-
|
|
7739
|
+
//# sourceMappingURL=chunk-XHEXIYKY.mjs.map
|
|
7740
|
+
//# sourceMappingURL=chunk-XHEXIYKY.mjs.map
|