@buildbase/sdk 0.0.71 → 0.0.74
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/CHANGELOG.md +106 -0
- package/README.md +43 -10
- package/dist/cli.mjs +2 -0
- package/dist/css/styles.css +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +103 -2
- package/dist/index.mjs +1 -1
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.d.ts +30 -0
- package/dist/mcp/index.mjs +1 -1
- package/dist/react/chunks/SettingsDialog-C0ocJMBA.cjs +2 -0
- package/dist/react/chunks/SettingsDialog-CWrmSyKV.mjs +2 -0
- package/dist/react/chunks/{SubscriptionDialog-Bkue_qyM.cjs → SubscriptionDialog-CLh4zW9Y.cjs} +1 -1
- package/dist/react/chunks/{SubscriptionDialog-ZjdyTmxn.mjs → SubscriptionDialog-sH0cQdPD.mjs} +1 -1
- package/dist/react/chunks/react-BBSVsY3n.cjs +2 -0
- package/dist/react/chunks/react-CNHfoa5L.mjs +2 -0
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +130 -8
- package/dist/react/index.mjs +1 -1
- package/dist/server/browser.cjs +1 -0
- package/dist/server/browser.mjs +1 -0
- package/dist/server/index.cjs +1 -0
- package/dist/server/index.d.ts +556 -0
- package/dist/server/index.mjs +1 -0
- package/dist/server/next/index.cjs +1 -0
- package/dist/server/next/index.d.ts +156 -0
- package/dist/server/next/index.mjs +1 -0
- package/dist/tracking/index.cjs +1 -1
- package/dist/tracking/index.d.ts +205 -8
- package/dist/tracking/index.mjs +1 -1
- package/docs/SERVER-CONTENT.md +297 -0
- package/package.json +65 -5
- package/dist/react/chunks/SettingsDialog-D5lLHG9-.cjs +0 -2
- package/dist/react/chunks/SettingsDialog-DiTnAWFt.mjs +0 -2
- package/dist/react/chunks/react-BIZcTNos.mjs +0 -2
- package/dist/react/chunks/react-DM1nGVlR.cjs +0 -2
- /package/dist/react/chunks/{ar-D_agqxXa.cjs → ar-CRVhjpVE.cjs} +0 -0
- /package/dist/react/chunks/{ar-By_nJtJ6.mjs → ar-DFPDdu2U.mjs} +0 -0
- /package/dist/react/chunks/{de-D7j-9T8u.cjs → de-BGhzn711.cjs} +0 -0
- /package/dist/react/chunks/{de-CQW2yLLr.mjs → de-Bqi8scew.mjs} +0 -0
- /package/dist/react/chunks/{es-CggBj8dc.mjs → es-D_Eqhob3.mjs} +0 -0
- /package/dist/react/chunks/{es-DYtfnqFg.cjs → es-DyrMaeUp.cjs} +0 -0
- /package/dist/react/chunks/{fr-Bu6_05LA.cjs → fr-C0SkloRr.cjs} +0 -0
- /package/dist/react/chunks/{fr-CbvudRKC.mjs → fr-DkZpFQ1Q.mjs} +0 -0
- /package/dist/react/chunks/{hi-dKtSIE95.cjs → hi-B9TK87T8.cjs} +0 -0
- /package/dist/react/chunks/{hi-DrJIuj_0.mjs → hi-DrTcPkiY.mjs} +0 -0
- /package/dist/react/chunks/{ja-BtZsSYAE.mjs → ja-Dgahn--0.mjs} +0 -0
- /package/dist/react/chunks/{ja-6AwwCaS_.cjs → ja-LjzlAhAT.cjs} +0 -0
- /package/dist/react/chunks/{zh-BZsPG6yc.mjs → zh-BezRHDHs.mjs} +0 -0
- /package/dist/react/chunks/{zh-C6onHYpa.cjs → zh-CcodKi4U.cjs} +0 -0
package/dist/tracking/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{jsx as e}from"react/jsx-runtime";import{useRef as t,useState as n,useCallback as r,useEffect as i,useMemo as o,useContext as a,createContext as s}from"react";const c="__buildbaseBeforeLeave",d=globalThis,l=d[c]??(d[c]=new Set);const u="bb_attr",p=["gclid","gbraid","wbraid","dclid","fbclid","msclkid","li_fat_id","twclid","ttclid","rdt_cid","epik","irclickid","utm_source","utm_medium","utm_campaign","utm_term","utm_content","utm_id"],g=/^[\w.~-]{1,200}$/;function f(){return"undefined"==typeof window?null:window}function m(e,t){if(!e||!e.includes("."))return"";if(/^\d{1,3}(\.\d{1,3}){3}$/.test(e))return"";const n=t??f()?.document;if(!n)return"";const r=e.split(".");for(let e=r.length-2;e>=0;e--){const t="."+r.slice(e).join("."),i=`__bb_probe_${Date.now()}`;n.cookie=`${i}=1; domain=${t}; path=/; SameSite=Lax`;const o=n.cookie.includes(`${i}=1`);if(n.cookie=`${i}=; domain=${t}; path=/; max-age=0; SameSite=Lax`,o)return t}return""}function h(e){const t=e.cookie.split("; ").find(e=>e.startsWith(`${u}=`));if(!t)return{};try{const e=JSON.parse(decodeURIComponent(t.slice(8)));return"object"==typeof e&&e?e:{}}catch{return{}}}const y=p.filter(e=>!e.startsWith("utm_")),w=e=>y.some(t=>!!e[t]);function v(){const e=f();if(!e)return{};const t=e.document,n=h(t),r=function(e){const t=new URLSearchParams(e),n={};for(const e of p){const r=t.get(e);r&&(r.length>200||g.test(r)&&(n[e]=r))}return n}(e.location.search),i=Object.keys(r).length>0&&(w(r)||!w(n)),o=i?r:n;return 0===Object.keys(o).length?{}:(i&&!function(e,t){const n=new Set([...Object.keys(e),...Object.keys(t)]);for(const r of n)if(e[r]!==t[r])return!1;return!0}(r,n)&&function(e,t,n){const r=encodeURIComponent(JSON.stringify(t));e.cookie=`${u}=${r}; path=/; max-age=7776000; SameSite=Lax`+(n?`; domain=${n}`:"")}(t,o,m(e.location.hostname,t)),o)}function _(){const e=f();return e?h(e.document):{}}function k(e){try{const t=new URLSearchParams(e);return t.has("code")&&t.has("state")}catch{return!1}}const b="bb_pending_checkout";function I(){try{return"undefined"==typeof window?null:window.sessionStorage}catch{return null}}const C="bb_co";function $(){try{return"undefined"==typeof window?null:window.document??null}catch{return null}}function j(){const e=$();if(e)try{const t=m(window.location?.hostname??"",e);e.cookie=`${C}=; path=/; max-age=0; SameSite=Lax`+(t?`; domain=${t}`:"")}catch{}}function x(e,t){if(!e)return null;try{const n=JSON.parse(e);return n&&"string"==typeof n.eventId&&n.eventId?"number"!=typeof n.startedAt||t-n.startedAt>216e5?null:n:null}catch{return null}}function q(e=Date.now()){const t=I();if(!t)return null;let n=null;try{n=t.getItem(b),t.removeItem(b)}catch{return null}const r=x(n,e);return r&&j(),r}function A(e){try{return x(I()?.getItem(b)??null,e)}catch{return null}}function P(e,t=Date.now()){let n=null;try{n=new URLSearchParams(e).get("session_id")}catch{return null}if(!n)return null;const r=A(t);if(r?.sessionId===n)return q(t);const i=function(e){const t=$();if(!t||"string"!=typeof t.cookie)return null;const n=t.cookie.split("; ").find(e=>e.startsWith(`${C}=`));return n?x(decodeURIComponent(n.slice(6)),e):null}(t);return i?.sessionId!==n?null:(j(),i)}function S(e,t=Date.now()){return function(e){let t=null;try{t=new URLSearchParams(e).get("bb")}catch{return!1}if(!t)return!1;const n={};for(const e of t.split(",")){const t=e.indexOf(":");if(-1!==t)try{n[decodeURIComponent(e.slice(0,t))]=decodeURIComponent(e.slice(t+1))}catch{}}return"checkout"===n.action&&"cancel"===n.status}(e)&&A(t)?q(t):null}const O=new Set(["bif","clp","djf","gnf","jpy","kmf","krw","mga","pyg","rwf","ugx","vnd","vuv","xaf","xof","xpf"]),E=new Set(["bhd","jod","kwd","omr","tnd"]);function U(e,t){if("number"!=typeof e||!Number.isFinite(e))return;const n=(t??"").toLowerCase();return O.has(n)?e:e/(E.has(n)?1e3:100)}function L(){return"undefined"==typeof window?null:window}function T(e){const t=L();if(!t)return;t.gtag?.("consent","update",{ad_storage:e.marketing?"granted":"denied",ad_user_data:e.marketing?"granted":"denied",ad_personalization:e.marketing?"granted":"denied",analytics_storage:e.analytics?"granted":"denied"});const n=t.fbq;n?.("consent",e.marketing?"grant":"revoke")}const M={gtm:{title:"Google Tag Manager",vendor:"Google LLC",privacyUrl:"https://policies.google.com/privacy",idLabel:"Container ID",idPattern:"^GTM-[A-Z0-9]{4,10}$",idExample:"GTM-ABC1234",scriptOrigin:"https://www.googletagmanager.com",defaultConsentCategory:"analytics",supportsConsentMode:!0,needsConversionIds:!1},ga4:{title:"Google Analytics 4",vendor:"Google LLC",privacyUrl:"https://policies.google.com/privacy",idLabel:"Measurement ID",idPattern:"^G-[A-Z0-9]{8,12}$",idExample:"G-ABCD123456",scriptOrigin:"https://www.googletagmanager.com",defaultConsentCategory:"analytics",supportsConsentMode:!0,needsConversionIds:!1},google_ads:{title:"Google Ads",vendor:"Google LLC",privacyUrl:"https://policies.google.com/privacy",idLabel:"Conversion ID",idPattern:"^AW-[0-9]{9,12}$",idExample:"AW-123456789",scriptOrigin:"https://www.googletagmanager.com",defaultConsentCategory:"marketing",supportsConsentMode:!0,needsConversionIds:!0},meta_pixel:{title:"Meta Pixel",vendor:"Meta Platforms Ireland Limited",privacyUrl:"https://www.facebook.com/privacy/policy",idLabel:"Pixel ID",idPattern:"^[0-9]{15,16}$",idExample:"123456789012345",scriptOrigin:"https://connect.facebook.net",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!1,multiInstance:!0},x_pixel:{title:"X (Twitter) Pixel",vendor:"X Corp.",privacyUrl:"https://x.com/en/privacy",idLabel:"Pixel ID",idPattern:"^o[a-z0-9]{4,6}$",idExample:"o1a2b3",scriptOrigin:"https://static.ads-twitter.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!0,multiInstance:!0},linkedin:{title:"LinkedIn Insight Tag",vendor:"LinkedIn Ireland Unlimited Company",privacyUrl:"https://www.linkedin.com/legal/privacy-policy",idLabel:"Partner ID",idPattern:"^[0-9]{6,9}$",idExample:"1234567",scriptOrigin:"https://snap.licdn.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!0,multiInstance:!0},tiktok:{title:"TikTok Pixel",vendor:"TikTok Information Technologies UK Limited",privacyUrl:"https://www.tiktok.com/legal/privacy-policy",idLabel:"Pixel ID",idPattern:"^[A-Z0-9]{20}$",idExample:"C4A1B2C3D4E5F6G7H8I9",scriptOrigin:"https://analytics.tiktok.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!1,multiInstance:!0},reddit:{title:"Reddit Pixel",vendor:"Reddit, Inc.",privacyUrl:"https://www.reddit.com/policies/privacy-policy",idLabel:"Advertiser ID",idPattern:"^t2_[a-z0-9]{4,12}$",idExample:"t2_abc123",scriptOrigin:"https://www.redditstatic.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!1,multiInstance:!0},bing_uet:{title:"Microsoft Advertising (UET)",vendor:"Microsoft Corporation",privacyUrl:"https://privacy.microsoft.com/en-us/privacystatement",idLabel:"Tag ID",idPattern:"^[0-9]{7,9}$",idExample:"12345678",scriptOrigin:"https://bat.bing.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!1,multiInstance:!0},clarity:{title:"Microsoft Clarity",vendor:"Microsoft Corporation",privacyUrl:"https://privacy.microsoft.com/en-us/privacystatement",idLabel:"Project ID",idPattern:"^[a-z0-9]{10}$",idExample:"ab12cd34ef",scriptOrigin:"https://www.clarity.ms",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1},hotjar:{title:"Hotjar",vendor:"Hotjar Limited",privacyUrl:"https://www.hotjar.com/legal/policies/privacy/",idLabel:"Site ID",idPattern:"^[0-9]{6,9}$",idExample:"1234567",scriptOrigin:"https://static.hotjar.com",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1},posthog:{title:"PostHog",vendor:"PostHog, Inc.",privacyUrl:"https://posthog.com/privacy",idLabel:"Project API key",idPattern:"^phc_[A-Za-z0-9]{32,48}$",idExample:"phc_abcdefghijklmnopqrstuvwxyz012345",scriptOrigin:"https://us-assets.i.posthog.com",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1,hosts:["us.i.posthog.com","eu.i.posthog.com"]},plausible:{title:"Plausible Analytics",vendor:"Plausible Insights OÜ",privacyUrl:"https://plausible.io/privacy",idLabel:"Domain",idPattern:"^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$",idExample:"example.com",scriptOrigin:"https://plausible.io",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1},ahrefs:{title:"Ahrefs Analytics",vendor:"Ahrefs Pte. Ltd.",privacyUrl:"https://ahrefs.com/privacy",idLabel:"Analytics key",idPattern:"^[A-Za-z0-9+/=]{20,64}$",idExample:"AbCdEfGhIjKlMnOpQrStUv==",scriptOrigin:"https://analytics.ahrefs.com",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1}},D=Object.keys(M);function N(e){return"string"==typeof e&&Object.prototype.hasOwnProperty.call(M,e)}function B(e,t){return!!N(e)&&("string"==typeof t&&0!==t.length&&new RegExp(M[e].idPattern).test(t))}const R=/^[a-z][a-z0-9-]{0,40}$/,z=/^[\w.:/@+=-]{1,200}$/;function G(e){return function(e){if("string"!=typeof e)return!1;if(0===e.length||e.length>300)return!1;let t;try{t=new URL(e)}catch{return!1}return!("https:"!==t.protocol||!t.hostname||!t.hostname.includes(".")||e.includes("?")||e.includes("#")||t.username||t.password)}(e.src)&&function(e){if(null==e)return!0;if("object"!=typeof e||Array.isArray(e))return!1;const t=Object.entries(e);return!(t.length>12)&&t.every(([e,t])=>R.test(e)&&"string"==typeof t&&z.test(t))}(e.dataAttributes)}const V=Array.from(new Set(D.map(e=>M[e].scriptOrigin))).sort(),F={sign_up:{ga4:"sign_up",meta:"CompleteRegistration",tiktok:"CompleteRegistration",reddit:"SignUp"},login:{ga4:"login",meta:null,tiktok:null,reddit:null},trial_started:{ga4:"begin_checkout",meta:"StartTrial",tiktok:"StartTrial",reddit:"Lead"},checkout_started:{ga4:"begin_checkout",meta:"InitiateCheckout",tiktok:"InitiateCheckout",reddit:"AddToCart"},purchase:{ga4:"purchase",meta:"Purchase",tiktok:"CompletePayment",reddit:"Purchase"},subscription_created:{ga4:"purchase",meta:"Subscribe",tiktok:"Subscribe",reddit:"Purchase"},subscription_upgraded:{ga4:"subscription_upgraded",meta:null,tiktok:null,reddit:null},lead:{ga4:"generate_lead",meta:"Lead",tiktok:"SubmitForm",reddit:"Lead"},workspace_created:{ga4:"workspace_created",meta:null,tiktok:null,reddit:null}},H=Object.keys(F);function W(e){return H.includes(e)}function Z(){return"undefined"==typeof window?null:window}const J={gtm:"dataLayer",ga4:"gtag",google_ads:"gtag",meta_pixel:"fbq",x_pixel:"twq",linkedin:"lintrk",tiktok:"ttq",reddit:"rdt",bing_uet:"uetq",clarity:"clarity",hotjar:"hj",posthog:"posthog",plausible:"plausible",ahrefs:"__ahrefs_loaded"};function K(){return"undefined"==typeof window?null:window}function Q(e,t={}){const n=K();if(!n)return null;const r=n.document.createElement("script");r.async=!0,r.src=e;for(const[e,n]of Object.entries(t))r.setAttribute(e,n);return n.document.head.appendChild(r),r}function X(e){const t=K();if(!t)return;const n=t.document.createElement("script");n.text=e,t.document.head.appendChild(n)}function Y(e){const t=K();t&&(Array.isArray(t[e])||(t[e]=[]),"function"!=typeof t.gtag&&(t.gtag=function(){t[e].push(arguments)}))}const ee=new Set;function te(e){for(const t of ee)if(t.slice(0,t.indexOf(":"))===e)return!0;return!1}function ne(e,t){const n=K();if(!n)return!1;if("gtm"===e||"ga4"===e||"google_ads"===e){const e=n.google_tag_manager;return!(!e||"object"!=typeof e)&&Object.prototype.hasOwnProperty.call(e,t)}const r=J[e];if(!r)return!1;if(void 0===n[r])return!1;if(ee.has(`${e}:${t}`))return!0;return!M[e].multiInstance||!te(e)}const re={meta_pixel:e=>`fbq('init','${e}');fbq('track','PageView');`,x_pixel:e=>`twq('config','${e}');`,tiktok:e=>`ttq.load('${e}');ttq.page();`,reddit:e=>`rdt('init','${e}');rdt('track','PageVisit');`,bing_uet:e=>`window.uetq=window.uetq||[];window.uetq.push({ti:'${e}',enableAutoSpaTracking:false});`,linkedin:e=>`window._linkedin_data_partner_ids=window._linkedin_data_partner_ids||[];window._linkedin_data_partner_ids.push('${e}');`};function ie(e,t,n){const r=function(e,t,n){const r=K();if(!r)return!1;if("external"===e.provider){if(!e.src)return!1;const t={};for(const[n,r]of Object.entries(e.dataAttributes??{}))t[`data-${n}`]=r;return Q(e.src,t),!0}const i=e.provider,o=M[i];if(!o)return!1;const a=e.providerId;if(!a)return!1;const s=re[i];if(s&&te(i))return X(s(a)),!0;switch(i){case"gtm":{Y(t),r[t].push({"gtm.start":Date.now(),event:"gtm.js"});const e="dataLayer"===t?"":`&l=${t}`;return Q(`${o.scriptOrigin}/gtm.js?id=${a}${e}`),!0}case"ga4":case"google_ads":{Y(t),Q(`${o.scriptOrigin}/gtag/js?id=${a}`);const e=r.gtag;e("js",new Date);const s="ga4"===i&&n?.gaClientId?{client_id:n.gaClientId}:void 0;return s?e("config",a,s):e("config",a),!0}case"meta_pixel":return X(`!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,document,'script','${o.scriptOrigin}/en_US/fbevents.js');fbq('init','${a}');fbq('track','PageView');`),!0;case"x_pixel":return X(`!function(e,t,n,s,u,a){e.twq||(s=e.twq=function(){s.exe?s.exe.apply(s,arguments):s.queue.push(arguments)},s.version='1.1',s.queue=[],u=t.createElement(n),u.async=!0,u.src='${o.scriptOrigin}/uwt.js',a=t.getElementsByTagName(n)[0],a.parentNode.insertBefore(u,a))}(window,document,'script');twq('config','${a}');`),!0;case"linkedin":return X(`window._linkedin_partner_id='${a}';window._linkedin_data_partner_ids=window._linkedin_data_partner_ids||[];window._linkedin_data_partner_ids.push('${a}');window.lintrk=window.lintrk||function(a,b){(window.lintrk.q=window.lintrk.q||[]).push([a,b])};window.lintrk.q=window.lintrk.q||[];`),Q(`${o.scriptOrigin}/li.lms-analytics/insight.min.js`),!0;case"tiktok":return X(`!function(w,d,t){w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=['page','track','identify','instances','debug','on','off','once','ready','alias','group','enableCookie','disableCookie'];ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.load=function(e,n){var r='${o.scriptOrigin}/i18n/pixel/events.js';ttq._i=ttq._i||{};ttq._i[e]=[];ttq._i[e]._u=r;ttq._t=ttq._t||{};ttq._t[e]=+new Date;ttq._o=ttq._o||{};ttq._o[e]=n||{};var o=d.createElement('script');o.type='text/javascript';o.async=!0;o.src=r+'?sdkid='+e+'&lib='+t;var a=d.getElementsByTagName('script')[0];a.parentNode.insertBefore(o,a)};ttq.load('${a}');ttq.page()}(window,document,'ttq');`),!0;case"reddit":return X(`!function(w,d){if(!w.rdt){var p=w.rdt=function(){p.sendEvent?p.sendEvent.apply(p,arguments):p.callQueue.push(arguments)};p.callQueue=[];var t=d.createElement('script');t.src='${o.scriptOrigin}/ads/pixel.js';t.async=!0;var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(t,s)}}(window,document);rdt('init','${a}');rdt('track','PageVisit');`),!0;case"bing_uet":return X(`(function(w,d,t,r,u){w[u]=w[u]||[];w[u].push({ti:'${a}',enableAutoSpaTracking:false});var o=d.createElement(t);o.src='${o.scriptOrigin}/bat.js';o.async=1;var i=d.getElementsByTagName(t)[0];i.parentNode.insertBefore(o,i)})(window,document,'script',0,'uetq');`),!0;case"clarity":return X(`(function(c,l,a,r,i,t,y){c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};t=l.createElement(r);t.async=1;t.src='${o.scriptOrigin}/tag/'+i;y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y)})(window,document,'clarity','script','${a}');`),!0;case"hotjar":return X(`(function(h,o,t,j,a,r){h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};h._hjSettings={hjid:${a},hjsv:6};a=o.getElementsByTagName('head')[0];r=o.createElement('script');r.async=1;r.src='${o.scriptOrigin}/hotjar-'+h._hjSettings.hjid+'.js?sv='+h._hjSettings.hjsv;a.appendChild(r)})(window,document);`),!0;case"posthog":{const t=o.hosts,n=t?.includes(e.host??"")?e.host:t?.[0]??"us.i.posthog.com";return X(`!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split('.');2==o.length&&(t=t[o[0]],e=o[1]);t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement('script')).type='text/javascript',p.async=!0,p.src='${o.scriptOrigin}/static/array.js',(r=t.getElementsByTagName('script')[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a='posthog',u.people=u.people||[],u.toString=function(t){var e='posthog';return'posthog'!==a&&(e+='.'+a),t||(e+=' (stub)'),e},u.people.toString=function(){return u.toString(1)+'.people (stub)'},o='init capture register register_once identify alias people.set people.set_once set_config get_distinct_id getFeatureFlag isFeatureEnabled onFeatureFlags reloadFeatureFlags group reset'.split(' '),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);posthog.init('${a}',{api_host:'https://${n}'});`),!0}case"plausible":return X("window.plausible=window.plausible||function(){(window.plausible.q=window.plausible.q||[]).push(arguments)};"),Q(`${o.scriptOrigin}/js/script.js`,{"data-domain":a,defer:"true"}),!0;case"ahrefs":return Q(`${o.scriptOrigin}/analytics.js`,{"data-key":a}),r.__ahrefs_loaded=!0,!0;default:return!1}}(e,t,n);return r&&"external"!==e.provider&&e.providerId&&ee.add(`${e.provider}:${e.providerId}`),r}const oe=Symbol.for("@buildbase/sdk.tracking.context"),ae=globalThis,se=ae[oe]??(ae[oe]=s(null)),ce={consent:{manifest:[],state:null,set:()=>{}},track:()=>{},setUser:()=>{},setProperties:()=>{},getProperties:()=>({}),completeCheckout:async()=>{},installed:{},ready:!0,attribution:{}};function de(){return a(se)??ce}const le=({serverUrl:a,orgId:s,clientId:c,enabled:d=!0,consent:u="auto",autoPageview:p=!0,events:g,onEvent:f,properties:m,enrich:h,identity:y,debug:w=!1,children:_})=>{const b=t(y);b.current=y;const[I,C]=n(null),[$,j]=n(!1),[x,q]=n(!1),A="granted"===u?{analytics:!0,marketing:!0}:"denied"===u?{analytics:!1,marketing:!1}:null,[O,E]=n(A),D=t(null),R=t(f);R.current=f;const z=t(h);z.current=h;const V=t({});V.current=m??{};const H=t({}),J=r(()=>({...V.current,...H.current}),[]),K=r(e=>{const t={...H.current,...e};for(const[e,n]of Object.entries(t))void 0===n&&delete t[e];H.current=t},[]),[Q,X]=n({}),ee=t({}),[te,re]=n(0),oe=I?.dataLayerName??"dataLayer",ae=r((...e)=>{w&&console.info("[buildbase:tracking]",...e)},[w]);i(()=>{return e=()=>{0!==Object.keys(ee.current).length&&window.dispatchEvent("function"==typeof PageTransitionEvent?new PageTransitionEvent("pagehide",{persisted:!1}):new Event("pagehide"))},l.add(e),()=>{l.delete(e)};var e},[]),i(()=>{if(!(d&&a&&s&&c))return void j(!0);let e=!1;const t=`${a.replace(/\/$/,"")}/api/v1/public/${s}/tracking?clientId=${encodeURIComponent(c)}`;return fetch(t).then(e=>e.ok?e.json():null).then(t=>{if(e||!t)return;const n=t.data??t;n&&Array.isArray(n.scripts)&&C(n)}).catch(()=>{ae("config fetch failed; nothing installed")}).finally(()=>{e||j(!0)}),()=>{e=!0}},[d,a,s,c,ae]),i(()=>{d&&X(v())},[d]),i(()=>{d&&I?.enabled&&(Y(oe),function(e,t){const n=L();if(!n)return;Array.isArray(n[e])||(n[e]=[]),"function"!=typeof n.gtag&&(n.gtag=function(){n[e].push(arguments)});const r="granted"===t?"granted":"denied";n.gtag("consent","default",{ad_storage:r,ad_user_data:r,ad_personalization:r,analytics_storage:r,wait_for_update:500})}(oe,u),D.current&&T(D.current))},[d,I?.enabled,oe,u]);const ce=o(()=>I?.enabled?I.scripts.filter(e=>{const t=N(e.provider)&&M[e.provider].supportsConsentMode;return function(e,t,n,r){return"denied"!==r&&("granted"===r||(n?"marketing"===e?n.marketing:n.analytics:t&&"analytics"===e))}(e.consentCategory,t,O,u)}):[],[I,O,u]),[de,le]=n(()=>"undefined"==typeof window||!k(window.location.search));i(()=>{if(de)return;const e=setInterval(()=>{k(window.location.search)||le(!0)},50),t=setTimeout(()=>le(!0),5e3);return()=>{clearInterval(e),clearTimeout(t)}},[de]),i(()=>{if(!de)return;if(!d||!I?.enabled)return void($&&q(!0));let e=0;for(const t of ce)if(!ee.current[t.key]){if("external"===t.provider){if(!G({src:t.src,dataAttributes:t.dataAttributes})){ae("rejected external script",t.key);continue}}else{if(!N(t.provider)){ae("rejected unknown provider",t.provider);continue}if(!B(t.provider,t.providerId)){ae("rejected id for",t.provider);continue}if(ne(t.provider,t.providerId??"")){ae(`${t.provider} ${t.providerId} is already on the page; skipping. Configure each tag in exactly one place.`);continue}}ie(t,oe,b.current)&&(ee.current[t.key]=t.providerId??t.src??"",e+=1,ae("installed",t.key))}e&&re(e=>e+1);const t=window;t.__buildbase=t.__buildbase??{},t.__buildbase.tracking={installed:{...ee.current},dataLayerName:oe,clientId:c};const n=Object.keys(ee.current).length>0,r=null!==O||0===I.scripts.length;(n||r)&&q(!0)},[d,I,ce,$,O,oe,ae,de,c]),i(()=>{if(!d||!p||!I?.enabled)return;if("undefined"==typeof window)return;if(!de)return;let e=null;const t=()=>{e&&clearTimeout(e),e=setTimeout(()=>function(e,t){const n=Z();if(!n)return;const r=n[t];Array.isArray(r)&&r.push({event:"page_view",page_path:n.location.pathname,page_location:n.location.href,page_title:n.document.title});for(const t of e)switch(t.provider){case"ga4":n.gtag?.("event","page_view",{send_to:t.providerId,page_path:n.location.pathname,page_location:n.location.href,page_title:n.document.title});break;case"meta_pixel":n.fbq?.("track","PageView");break;case"tiktok":{const e=n.ttq;e?.page?.();break}case"reddit":n.rdt?.("track","PageVisit")}}(ce,oe),50)},n=window.history,r=n.pushState,i=n.replaceState;return n.pushState=function(...e){const n=r.apply(this,e);return t(),n},n.replaceState=function(...e){const n=i.apply(this,e);return t(),n},window.addEventListener("popstate",t),()=>{n.pushState=r,n.replaceState=i,window.removeEventListener("popstate",t),e&&clearTimeout(e)}},[d,p,I?.enabled,ce,oe,de]),i(()=>{if(!d)return;const e=function(e,t){const n=e?.mode??"auto",r=e?.overrides??{};if(("manual"===n||Object.values(r).some(e=>"manual"===e))&&!t)return'[buildbase:tracking] events are set to "manual" but no onEvent handler was provided, so those events would never fire anywhere. Pass onEvent, or use mode "auto".';for(const e of Object.keys(r))if(!W(e))return`[buildbase:tracking] unknown event "${e}" in events.overrides. Overrides only apply to the events the SDK fires itself.`;return null}(g,!!f);if(e)throw new Error(e)},[d,g,f]);const ue=r((e,t={},n)=>{if(!d)return;const r=n?.eventId||function(){const e=globalThis.crypto;return e?.randomUUID?e.randomUUID():`${Date.now().toString(16)}-${Math.random().toString(16).slice(2,10)}`}(),i=g?.mode??"auto",o=(W(e)?g?.overrides?.[e]:void 0)??i,a={...V.current,...H.current,...Q,...t},s=z.current?.({name:e,params:a})??{},c={...a,...s},l=R.current?.({name:e,params:c,eventId:r,handledBy:o});"manual"!==o&&!0!==l?(!function(e,t,n,r,i){const o=Z();if(!o)return;const a=o[i];Array.isArray(a)&&a.push({event:e,...t,event_id:n});const s=W(e)?F[e]:{ga4:e,meta:null,tiktok:null,reddit:null};for(const i of r){const r=i.provider,a=M[r];if(a){if(a.needsConversionIds){const a=i.conversionIds?.[e];if(!a)continue;"google_ads"===r?o.gtag?.("event","conversion",{send_to:`${i.providerId}/${a}`,transaction_id:n,...t}):"x_pixel"===r?o.twq?.("event",a,{...t,conversion_id:n}):"linkedin"===r&&o.lintrk?.("track",{conversion_id:a});continue}switch(r){case"ga4":s.ga4&&o.gtag?.("event",s.ga4,{...t,send_to:i.providerId,event_id:n});break;case"meta_pixel":s.meta&&o.fbq?.("track",s.meta,t,{eventID:n});break;case"tiktok":if(s.tiktok){const e=o.ttq;e?.track?.(s.tiktok,{...t,event_id:n})}break;case"reddit":s.reddit&&o.rdt?.("track",s.reddit,{...t,conversionId:n});break;case"bing_uet":{const r=o.uetq;r?.push?.("event",s.ga4??e,{...t,event_id:n});break}case"clarity":o.clarity?.("event",e);break;case"hotjar":{const t=o.hj;t?.("event",e);break}case"posthog":{const r=o.posthog;r?.capture?.(e,{...t,event_id:n});break}case"plausible":o.plausible?.(e,{props:t})}}}}(e,c,r,ce,oe),ae("event fired:",e,r)):ae("event handled by app:",e)},[d,g,ce,oe,Q,ae]),pe=r(async(e,t={})=>{const n=function(e){return{name:"trial_started"===e.kind?"trial_started":"purchase",params:{...e.workspaceId?{workspace_id:e.workspaceId}:{},...e.planVersionId?{plan_version_id:e.planVersionId}:{},...e.creditPackageId?{credit_package_id:e.creditPackageId}:{},...e.billingInterval?{billing_interval:e.billingInterval}:{},...e.currency?{currency:e.currency.toUpperCase()}:{},..."number"==typeof e.value?{value:e.value}:{},...e.sessionId?{transaction_id:e.sessionId}:{}}}}(e);let r=n.params;if(e.sessionId&&a&&s){const t=await async function(e,t){try{const n=e.serverUrl.replace(/\/$/,""),r=await fetch(`${n}/api/v1/public/${encodeURIComponent(e.orgId)}/checkout/${encodeURIComponent(t)}`,{credentials:"omit",..."undefined"!=typeof AbortSignal&&AbortSignal.timeout?{signal:AbortSignal.timeout(2e3)}:{}});if(!r.ok)return null;const i=await r.json(),o=i?.data??i;return"number"!=typeof o?.amount?null:{value:U(o.amount,o.currency),currency:"string"==typeof o.currency?o.currency:void 0,...Array.isArray(o.items)&&o.items.length?{items:o.items}:{}}}catch{return null}}({serverUrl:a,orgId:s},e.sessionId);t&&"number"==typeof t.value&&(r={...r,value:t.value,...t.currency?{currency:t.currency.toUpperCase()}:{},...t.items?.length?{items:t.items}:{}})}if(ue(n.name,{...r,...t},{eventId:e.eventId}),"purchase"===n.name&&e.sessionId&&a&&s){const t=(I?.scripts??[]).find(e=>"ga4"===e.provider&&e.providerId);t&&ne("ga4",t.providerId??"")&&function(e,t,n){try{const r=e.serverUrl.replace(/\/$/,"");fetch(`${r}/api/v1/public/${encodeURIComponent(e.orgId)}/checkout/${encodeURIComponent(t)}/reported`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider:n}),keepalive:!0,credentials:"omit"}).catch(()=>{})}catch{}}({serverUrl:a,orgId:s},e.sessionId,"ga4")}},[a,s,ue,I]),[ge]=n(()=>"undefined"==typeof window?"":window.location.search);i(()=>{if(!d||!x)return;if("undefined"==typeof window)return;const e=P(window.location.search);if(e)return void pe(e);const t=S(ge);t&&ue("checkout_abandoned",{...t.workspaceId?{workspace_id:t.workspaceId}:{},...t.planVersionId?{plan_version_id:t.planVersionId}:{},...t.creditPackageId?{credit_package_id:t.creditPackageId}:{},...t.billingInterval?{billing_interval:t.billingInterval}:{},...t.currency?{currency:t.currency.toUpperCase()}:{},..."number"==typeof t.value?{value:t.value}:{},seconds_at_checkout:Math.max(0,Math.round((Date.now()-t.startedAt)/1e3))})},[d,x,pe,ge,ue]);const fe=r(e=>{D.current=e,E(e),T(e)},[]),me=r((e,t)=>function(e,t,n){const r=Z();if(!r)return;const i=!!n&&Object.keys(n).length>0;for(const o of t)switch(o.provider){case"ga4":case"google_ads":r.gtag?.("set",{user_id:e}),i&&r.gtag?.("set",{user_properties:n});break;case"meta_pixel":o.providerId&&r.fbq?.("init",o.providerId,{external_id:e});break;case"posthog":r.posthog?.identify?.(e,i?n:void 0);break;case"clarity":if(r.clarity?.("identify",e),i)for(const[e,t]of Object.entries(n))r.clarity?.("set",e,String(t));break;case"hotjar":r.hj?.("identify",e,{});break;case"tiktok":{const t=r.ttq;t?.identify?.({external_id:e});break}}}(e,ce,t),[ce]),he=o(()=>({consent:{manifest:I?.consent?.manifest??[],state:O,set:fe},track:ue,setUser:me,setProperties:K,getProperties:J,completeCheckout:pe,installed:{...ee.current},ready:x,attribution:Q}),[I,O,fe,ue,me,K,J,pe,x,te,Q]);return e(se.Provider,{value:he,children:_})};function ue(e={}){const{completeCheckout:n,ready:r}=de(),o=t(e);o.current=e;const a=t(!1);i(()=>{if(!r)return;if(a.current)return;const e=P(window.location.search)??q();e&&(a.current=!0,n(e,o.current))},[r,n])}le.displayName="BuildBaseTracking";const pe={sign_in_started:"The sign-in / sign-up button was pressed.",pricing_viewed:"A <PricingPage> finished loading its plans.",pricing_plan_selected:"A plan was chosen on a <PricingPage>.",workspace_switcher_opened:"The workspace switcher was opened.",workspace_settings_opened:"The workspace settings modal was opened.",workspace_settings_section_viewed:"A different section of the settings modal was opened.",plan_picker_opened:"The plan picker was shown.",billing_interval_changed:"Monthly / quarterly / yearly was switched in the plan picker.",plan_selected:"A plan was chosen in the plan picker.",plan_picker_dismissed:"The plan picker was closed without choosing a plan.",checkout_abandoned:"The customer came back from Stripe without paying.",billing_portal_opened:"Stripe’s billing portal was opened.",subscription_cancel_started:"The cancel-subscription confirmation was opened.",subscription_cancelled:"A subscription was cancelled.",subscription_resumed:"A cancelled subscription was resumed.",feature_gate_shown:'A feature gate rendered its "not on your plan" side.',quota_limit_reached:"A quota gate rendered because a quota is used up.",quota_threshold_reached:"A usage-threshold gate rendered.",plan_gate_shown:'A plan gate rendered its "needs another plan" side.',subscription_notice_shown:"A billing notice (trial ending, payment failed…) was shown.",sdk_error:"An SDK operation failed (component, action and code only)."};export{p as ATTRIBUTION_PARAMS,le as BuildBaseTracking,F as EVENT_MAPPINGS,pe as FUNNEL_EVENTS,M as TAG_PROVIDERS,D as TAG_PROVIDER_IDS,V as TAG_SCRIPT_ORIGINS,v as captureAttribution,_ as getAttribution,W as isCanonicalEvent,N as isTagProviderId,B as isValidProviderId,ue as useCheckoutCompleted,de as useTracking};
|
|
2
|
+
import{jsx as e}from"react/jsx-runtime";import{useRef as t,useState as n,useMemo as r,useCallback as i,useEffect as o,useContext as a,createContext as s}from"react";const c="__buildbaseBeforeLeave",d=globalThis,l=d[c]??(d[c]=new Set);const u="bb_attr",p=["gclid","gbraid","wbraid","dclid","fbclid","msclkid","li_fat_id","twclid","ttclid","rdt_cid","epik","irclickid","utm_source","utm_medium","utm_campaign","utm_term","utm_content","utm_id"],g=/^[\w.~-]{1,200}$/;function f(){return"undefined"==typeof window?null:window}function m(e,t){if(!e||!e.includes("."))return"";if(/^\d{1,3}(\.\d{1,3}){3}$/.test(e))return"";const n=t??f()?.document;if(!n)return"";const r=e.split(".");for(let e=r.length-2;e>=0;e--){const t="."+r.slice(e).join("."),i=`__bb_probe_${Date.now()}`;n.cookie=`${i}=1; domain=${t}; path=/; SameSite=Lax`;const o=n.cookie.includes(`${i}=1`);if(n.cookie=`${i}=; domain=${t}; path=/; max-age=0; SameSite=Lax`,o)return t}return""}const h="$t",y="$l";function w(e){return function(e){const t=e.cookie.split("; ").find(e=>e.startsWith(`${u}=`));if(!t)return{params:{}};try{const e=JSON.parse(decodeURIComponent(t.slice(8)));if("object"!=typeof e||!e)return{params:{}};const{[h]:n,[y]:r,...i}=e;return{params:i,..."number"==typeof n&&n>0?{capturedAt:n}:{},..."string"==typeof r&&r?{landingUrl:r}:{}}}catch{return{params:{}}}}(e).params}function v(e){try{const{origin:t,pathname:n}=e.location;return t&&"null"!==t?`${t}${n}`.slice(0,300):void 0}catch{return}}const _=p.filter(e=>!e.startsWith("utm_")),b=e=>_.some(t=>!!e[t]);function k(){const e=f();if(!e)return{};const t=e.document,n=w(t),r=function(e){const t=new URLSearchParams(e),n={};for(const e of p){const r=t.get(e);r&&(r.length>200||g.test(r)&&(n[e]=r))}return n}(e.location.search),i=Object.keys(r).length>0&&(b(r)||!b(n)),o=i?r:n;return 0===Object.keys(o).length?{}:(i&&!function(e,t){const n=new Set([...Object.keys(e),...Object.keys(t)]);for(const r of n)if(e[r]!==t[r])return!1;return!0}(r,n)&&function(e,t,n,r){const i=encodeURIComponent(JSON.stringify({...t,[h]:r.capturedAt,...r.landingUrl?{[y]:r.landingUrl}:{}}));e.cookie=`${u}=${i}; path=/; max-age=7776000; SameSite=Lax`+(n?`; domain=${n}`:"")}(t,o,m(e.location.hostname,t),{capturedAt:Date.now(),landingUrl:v(e)}),o)}function I(){const e=f();return e?w(e.document):{}}function C(e){try{const t=new URLSearchParams(e);return t.has("code")&&t.has("state")}catch{return!1}}const $="bb_pending_checkout";function S(){try{return"undefined"==typeof window?null:window.sessionStorage}catch{return null}}const A="bb_co";function j(){try{return"undefined"==typeof window?null:window.document??null}catch{return null}}function x(){const e=j();if(e)try{const t=m(window.location?.hostname??"",e);e.cookie=`${A}=; path=/; max-age=0; SameSite=Lax`+(t?`; domain=${t}`:"")}catch{}}function q(e,t){if(!e)return null;try{const n=JSON.parse(e);return n&&"string"==typeof n.eventId&&n.eventId?"number"!=typeof n.startedAt||t-n.startedAt>216e5?null:n:null}catch{return null}}function U(e=Date.now()){const t=S();if(!t)return null;let n=null;try{n=t.getItem($),t.removeItem($)}catch{return null}const r=q(n,e);return r&&x(),r}function O(e){try{return q(S()?.getItem($)??null,e)}catch{return null}}function P(e,t=Date.now()){let n=null;try{n=new URLSearchParams(e).get("session_id")}catch{return null}if(!n)return null;const r=O(t);if(r?.sessionId===n)return U(t);const i=function(e){const t=j();if(!t||"string"!=typeof t.cookie)return null;const n=t.cookie.split("; ").find(e=>e.startsWith(`${A}=`));return n?q(decodeURIComponent(n.slice(6)),e):null}(t);return i?.sessionId!==n?null:(x(),i)}function E(e,t=Date.now()){return function(e){let t=null;try{t=new URLSearchParams(e).get("bb")}catch{return!1}if(!t)return!1;const n={};for(const e of t.split(",")){const t=e.indexOf(":");if(-1!==t)try{n[decodeURIComponent(e.slice(0,t))]=decodeURIComponent(e.slice(t+1))}catch{}}return"checkout"===n.action&&"cancel"===n.status}(e)&&O(t)?U(t):null}const T=new Set(["bif","clp","djf","gnf","jpy","kmf","krw","mga","pyg","rwf","ugx","vnd","vuv","xaf","xof","xpf"]),L=new Set(["bhd","jod","kwd","omr","tnd"]);function D(e,t){if("number"!=typeof e||!Number.isFinite(e))return;const n=(t??"").toLowerCase();return T.has(n)?e:e/(L.has(n)?1e3:100)}const M=["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","IS","LI","NO"],N={default:"granted",regions:{denied:["EEA","GB","CH"]}},R=/^[A-Z]{2}(-[A-Z0-9]{1,3})?$/;function B(e){const t=new Set;for(const n of e??[]){const e=String(n).trim().toUpperCase();if("EEA"===e)for(const e of M)t.add(e);else R.test(e)&&t.add(e)}return[...t]}function H(e,t,n){return e.includes(t)}function V(e,t,n){const r=(t??"").trim().toUpperCase();if(!/^[A-Z]{2}$/.test(r)||"XX"===r||"T1"===r)return"denied";const i=(n??"").trim().toUpperCase()||void 0,o=B(e.regions?.denied),a=B(e.regions?.granted);if(i){if(o.includes(`${r}-${i}`))return"denied";if(a.includes(`${r}-${i}`))return"granted"}return H(o,r)?"denied":H(a,r)||"granted"===e.default?"granted":"denied"}function z(){return"undefined"==typeof window?null:window}const G=["ad_storage","ad_user_data","ad_personalization","analytics_storage"];function F(e){const t={};for(const n of G)t[n]=e;return t}function J(e){const t=z();if(!t)return;const n=t.gtag;n?.("consent","update",{ad_storage:e.marketing?"granted":"denied",ad_user_data:e.marketing?"granted":"denied",ad_personalization:e.marketing?"granted":"denied",analytics_storage:e.analytics?"granted":"denied"}),n?.("set","ads_data_redaction",!e.marketing);const r=t.fbq;r?.("consent",e.marketing?"grant":"revoke")}const Z="bb_cid";function W(){if("undefined"!=typeof document&&"undefined"!=typeof window)try{const e=document.cookie.split("; ").find(e=>e.startsWith(`${Z}=`)),t=e?.slice(7);if(t&&/^[\w-]{16,64}$/.test(t))return t;const n=function(){const e=globalThis.crypto;if(e&&"function"==typeof e.randomUUID)return e.randomUUID();const t=new Uint8Array(16);if(e&&"function"==typeof e.getRandomValues)e.getRandomValues(t);else for(let e=0;e<t.length;e++)t[e]=Math.floor(256*Math.random());return Array.from(t).map(e=>e.toString(16).padStart(2,"0")).join("")}(),r=m(window.location.hostname,document);return document.cookie=`${Z}=${n}; path=/; max-age=34128000; SameSite=Lax`+(r?`; domain=${r}`:""),n}catch{return}}const K="bb_consent_recorded";function X(e){if("function"!=typeof fetch||!e.serverUrl||!e.orgId||!e.clientId)return;const t=JSON.stringify([e.orgId,e.clientId,!!e.state.analytics,!!e.state.marketing,e.manifestVersion??"",e.consentString??"",e.headers?.["x-session-id"]?"account":"anonymous"]);if(!e.source&&function(e){try{return window.localStorage.getItem(K)===e}catch{return!1}}(t))return;!function(e){try{window.localStorage.setItem(K,e)}catch{}}(t);const n=W();if(!n)return;const r=`${e.serverUrl.replace(/\/$/,"")}/api/v1/public/${e.orgId}/consent`;try{fetch(r,{method:"POST",keepalive:!0,headers:{"content-type":"application/json",...e.headers??{}},body:JSON.stringify({clientId:e.clientId,visitorId:n,choices:{analytics:!!e.state.analytics,marketing:!!e.state.marketing},...e.manifestVersion?{manifestVersion:e.manifestVersion}:{},...e.source?{source:e.source.slice(0,40)}:{},...e.consentString?{consentString:e.consentString.slice(0,2e3)}:{}})}).catch(()=>{})}catch{}}const Q=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),Y=(e,t)=>e>>>t|e<<32-t;function ee(e){return function(e){let t="";for(let n=0;n<e.length;n++)t+=e[n].toString(16).padStart(2,"0");return t}(function(e){let t=1779033703,n=3144134277,r=1013904242,i=2773480762,o=1359893119,a=2600822924,s=528734635,c=1541459225;const d=e.length,l=d+1,u=l+(56-l%64+64)%64+8,p=new Uint8Array(u);p.set(e,0),p[d]=128;const g=8*d,f=Math.floor(g/4294967296),m=g>>>0;p[u-8]=f>>>24&255,p[u-7]=f>>>16&255,p[u-6]=f>>>8&255,p[u-5]=255&f,p[u-4]=m>>>24&255,p[u-3]=m>>>16&255,p[u-2]=m>>>8&255,p[u-1]=255&m;const h=new Uint32Array(64);for(let e=0;e<u;e+=64){for(let t=0;t<16;t++){const n=e+4*t;h[t]=p[n]<<24|p[n+1]<<16|p[n+2]<<8|p[n+3]}for(let e=16;e<64;e++){const t=Y(h[e-15],7)^Y(h[e-15],18)^h[e-15]>>>3,n=Y(h[e-2],17)^Y(h[e-2],19)^h[e-2]>>>10;h[e]=h[e-16]+t+h[e-7]+n>>>0}let d=t,l=n,u=r,g=i,f=o,m=a,y=s,w=c;for(let e=0;e<64;e++){const t=w+(Y(f,6)^Y(f,11)^Y(f,25))+(f&m^~f&y)+Q[e]+h[e]>>>0,n=d&l^d&u^l&u;w=y,y=m,m=f,f=g+t>>>0,g=u,u=l,l=d,d=t+((Y(d,2)^Y(d,13)^Y(d,22))+n>>>0)>>>0}t=t+d>>>0,n=n+l>>>0,r=r+u>>>0,i=i+g>>>0,o=o+f>>>0,a=a+m>>>0,s=s+y>>>0,c=c+w>>>0}const y=new Uint8Array(32),w=[t,n,r,i,o,a,s,c];for(let e=0;e<8;e++)y[4*e]=w[e]>>>24&255,y[4*e+1]=w[e]>>>16&255,y[4*e+2]=w[e]>>>8&255,y[4*e+3]=255&w[e];return y}(e))}function te(e){const t=String(e??"").trim().toLowerCase(),n=t.lastIndexOf("@");if(n<1||n===t.length-1)return"";let r=t.slice(0,n);const i=t.slice(n+1);return"gmail.com"!==i&&"googlemail.com"!==i||(r=r.replace(/\./g,"")),`${r}@${i}`}function ne(e){const t=String(e??"").trim();if(!t.startsWith("+"))return"";const n=t.replace(/[^\d]/g,"");return n.length>=8&&n.length<=15?`+${n}`:""}async function re(e){const t=globalThis.crypto?.subtle;if(t&&"function"==typeof t.digest)try{const n=await t.digest("SHA-256",(new TextEncoder).encode(e));return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("")}catch{}return ee((n=e,(new TextEncoder).encode(n)));var n}async function ie(e){const t=te(e.email),n=ne(e.phone),r={};return t&&(r.emailHash=await re(t)),n&&(r.phoneHash=await re(n)),r}function oe(e,t){if("undefined"==typeof window)return;if(!t.emailHash&&!t.phoneHash)return;const n=window;e.some(e=>"google_ads"===e.provider||"ga4"===e.provider||"gtm"===e.provider)&&n.gtag?.("set","user_data",{...t.emailHash?{sha256_email_address:t.emailHash}:{},...t.phoneHash?{sha256_phone_number:t.phoneHash}:{}});for(const r of e)"meta_pixel"===r.provider&&r.providerId&&n.fbq?.("init",r.providerId,{...t.emailHash?{em:t.emailHash}:{},...t.phoneHash?{ph:t.phoneHash}:{}})}const ae={gtm:{title:"Google Tag Manager",vendor:"Google LLC",privacyUrl:"https://policies.google.com/privacy",idLabel:"Container ID",idPattern:"^GTM-[A-Z0-9]{4,10}$",idExample:"GTM-ABC1234",scriptOrigin:"https://www.googletagmanager.com",defaultConsentCategory:"analytics",supportsConsentMode:!0,needsConversionIds:!1},ga4:{title:"Google Analytics 4",vendor:"Google LLC",privacyUrl:"https://policies.google.com/privacy",idLabel:"Measurement ID",idPattern:"^G-[A-Z0-9]{8,12}$",idExample:"G-ABCD123456",scriptOrigin:"https://www.googletagmanager.com",defaultConsentCategory:"analytics",supportsConsentMode:!0,needsConversionIds:!1},google_ads:{title:"Google Ads",vendor:"Google LLC",privacyUrl:"https://policies.google.com/privacy",idLabel:"Conversion ID",idPattern:"^AW-[0-9]{9,12}$",idExample:"AW-123456789",scriptOrigin:"https://www.googletagmanager.com",defaultConsentCategory:"marketing",supportsConsentMode:!0,needsConversionIds:!0},meta_pixel:{title:"Meta Pixel",vendor:"Meta Platforms Ireland Limited",privacyUrl:"https://www.facebook.com/privacy/policy",idLabel:"Pixel ID",idPattern:"^[0-9]{15,16}$",idExample:"123456789012345",scriptOrigin:"https://connect.facebook.net",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!1,multiInstance:!0},x_pixel:{title:"X (Twitter) Pixel",vendor:"X Corp.",privacyUrl:"https://x.com/en/privacy",idLabel:"Pixel ID",idPattern:"^o[a-z0-9]{4,6}$",idExample:"o1a2b3",scriptOrigin:"https://static.ads-twitter.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!0,multiInstance:!0},linkedin:{title:"LinkedIn Insight Tag",vendor:"LinkedIn Ireland Unlimited Company",privacyUrl:"https://www.linkedin.com/legal/privacy-policy",idLabel:"Partner ID",idPattern:"^[0-9]{6,9}$",idExample:"1234567",scriptOrigin:"https://snap.licdn.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!0,multiInstance:!0},tiktok:{title:"TikTok Pixel",vendor:"TikTok Information Technologies UK Limited",privacyUrl:"https://www.tiktok.com/legal/privacy-policy",idLabel:"Pixel ID",idPattern:"^[A-Z0-9]{20}$",idExample:"C4A1B2C3D4E5F6G7H8I9",scriptOrigin:"https://analytics.tiktok.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!1,multiInstance:!0},reddit:{title:"Reddit Pixel",vendor:"Reddit, Inc.",privacyUrl:"https://www.reddit.com/policies/privacy-policy",idLabel:"Advertiser ID",idPattern:"^t2_[a-z0-9]{4,12}$",idExample:"t2_abc123",scriptOrigin:"https://www.redditstatic.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!1,multiInstance:!0},bing_uet:{title:"Microsoft Advertising (UET)",vendor:"Microsoft Corporation",privacyUrl:"https://privacy.microsoft.com/en-us/privacystatement",idLabel:"Tag ID",idPattern:"^[0-9]{7,9}$",idExample:"12345678",scriptOrigin:"https://bat.bing.com",defaultConsentCategory:"marketing",supportsConsentMode:!1,needsConversionIds:!1,multiInstance:!0},clarity:{title:"Microsoft Clarity",vendor:"Microsoft Corporation",privacyUrl:"https://privacy.microsoft.com/en-us/privacystatement",idLabel:"Project ID",idPattern:"^[a-z0-9]{10}$",idExample:"ab12cd34ef",scriptOrigin:"https://www.clarity.ms",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1},hotjar:{title:"Hotjar",vendor:"Hotjar Limited",privacyUrl:"https://www.hotjar.com/legal/policies/privacy/",idLabel:"Site ID",idPattern:"^[0-9]{6,9}$",idExample:"1234567",scriptOrigin:"https://static.hotjar.com",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1},posthog:{title:"PostHog",vendor:"PostHog, Inc.",privacyUrl:"https://posthog.com/privacy",idLabel:"Project API key",idPattern:"^phc_[A-Za-z0-9]{32,48}$",idExample:"phc_abcdefghijklmnopqrstuvwxyz012345",scriptOrigin:"https://us-assets.i.posthog.com",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1,hosts:["us.i.posthog.com","eu.i.posthog.com"]},plausible:{title:"Plausible Analytics",vendor:"Plausible Insights OÜ",privacyUrl:"https://plausible.io/privacy",idLabel:"Domain",idPattern:"^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$",idExample:"example.com",scriptOrigin:"https://plausible.io",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1},ahrefs:{title:"Ahrefs Analytics",vendor:"Ahrefs Pte. Ltd.",privacyUrl:"https://ahrefs.com/privacy",idLabel:"Analytics key",idPattern:"^[A-Za-z0-9+/=]{20,64}$",idExample:"AbCdEfGhIjKlMnOpQrStUv==",scriptOrigin:"https://analytics.ahrefs.com",defaultConsentCategory:"analytics",supportsConsentMode:!1,needsConversionIds:!1}},se=Object.keys(ae);function ce(e){return"string"==typeof e&&Object.prototype.hasOwnProperty.call(ae,e)}function de(e,t){return!!ce(e)&&("string"==typeof t&&0!==t.length&&new RegExp(ae[e].idPattern).test(t))}const le=/^[a-z][a-z0-9-]{0,40}$/,ue=/^[\w.:/@+=-]{1,200}$/;function pe(e){return function(e){if("string"!=typeof e)return!1;if(0===e.length||e.length>300)return!1;let t;try{t=new URL(e)}catch{return!1}return!("https:"!==t.protocol||!t.hostname||!t.hostname.includes(".")||e.includes("?")||e.includes("#")||t.username||t.password)}(e.src)&&function(e){if(null==e)return!0;if("object"!=typeof e||Array.isArray(e))return!1;const t=Object.entries(e);return!(t.length>12)&&t.every(([e,t])=>le.test(e)&&"string"==typeof t&&ue.test(t))}(e.dataAttributes)}const ge=Array.from(new Set(se.map(e=>ae[e].scriptOrigin))).sort(),fe={sign_up:{ga4:"sign_up",meta:"CompleteRegistration",tiktok:"CompleteRegistration",reddit:"SignUp"},login:{ga4:"login",meta:null,tiktok:null,reddit:null},trial_started:{ga4:"begin_checkout",meta:"StartTrial",tiktok:"StartTrial",reddit:"Lead"},checkout_started:{ga4:"begin_checkout",meta:"InitiateCheckout",tiktok:"InitiateCheckout",reddit:"AddToCart"},purchase:{ga4:"purchase",meta:"Purchase",tiktok:"CompletePayment",reddit:"Purchase"},subscription_created:{ga4:"purchase",meta:"Subscribe",tiktok:"Subscribe",reddit:"Purchase"},subscription_upgraded:{ga4:"subscription_upgraded",meta:null,tiktok:null,reddit:null},lead:{ga4:"generate_lead",meta:"Lead",tiktok:"SubmitForm",reddit:"Lead"},workspace_created:{ga4:"workspace_created",meta:null,tiktok:null,reddit:null}},me=Object.keys(fe);function he(e){return me.includes(e)}function ye(){return"undefined"==typeof window?null:window}const we={gtm:"dataLayer",ga4:"gtag",google_ads:"gtag",meta_pixel:"fbq",x_pixel:"twq",linkedin:"lintrk",tiktok:"ttq",reddit:"rdt",bing_uet:"uetq",clarity:"clarity",hotjar:"hj",posthog:"posthog",plausible:"plausible",ahrefs:"__ahrefs_loaded"};function ve(){return"undefined"==typeof window?null:window}function _e(e,t={}){const n=ve();if(!n)return null;const r=n.document.createElement("script");r.async=!0,r.src=e;for(const[e,n]of Object.entries(t))r.setAttribute(e,n);return n.document.head.appendChild(r),r}function be(e){const t=ve();if(!t)return;const n=t.document.createElement("script");n.text=e,t.document.head.appendChild(n)}function ke(e){const t=ve();t&&(Array.isArray(t[e])||(t[e]=[]),"function"!=typeof t.gtag&&(t.gtag=function(){t[e].push(arguments)}))}const Ie=new Set;function Ce(e){for(const t of Ie)if(t.slice(0,t.indexOf(":"))===e)return!0;return!1}function $e(e,t){const n=ve();if(!n)return!1;if("gtm"===e||"ga4"===e||"google_ads"===e){const e=n.google_tag_manager;return!(!e||"object"!=typeof e)&&Object.prototype.hasOwnProperty.call(e,t)}const r=we[e];if(!r)return!1;if(void 0===n[r])return!1;if(Ie.has(`${e}:${t}`))return!0;return!ae[e].multiInstance||!Ce(e)}const Se={meta_pixel:e=>`fbq('init','${e}');fbq('track','PageView');`,x_pixel:e=>`twq('config','${e}');`,tiktok:e=>`ttq.load('${e}');ttq.page();`,reddit:e=>`rdt('init','${e}');rdt('track','PageVisit');`,bing_uet:e=>`window.uetq=window.uetq||[];window.uetq.push({ti:'${e}',enableAutoSpaTracking:false});`,linkedin:e=>`window._linkedin_data_partner_ids=window._linkedin_data_partner_ids||[];window._linkedin_data_partner_ids.push('${e}');`};function Ae(e,t,n){const r=function(e,t,n){const r=ve();if(!r)return!1;if("external"===e.provider){if(!e.src)return!1;const t={};for(const[n,r]of Object.entries(e.dataAttributes??{}))t[`data-${n}`]=r;return _e(e.src,t),!0}const i=e.provider,o=ae[i];if(!o)return!1;const a=e.providerId;if(!a)return!1;const s=Se[i];if(s&&Ce(i))return be(s(a)),!0;switch(i){case"gtm":{ke(t),r[t].push({"gtm.start":Date.now(),event:"gtm.js"});const e="dataLayer"===t?"":`&l=${t}`;return _e(`${o.scriptOrigin}/gtm.js?id=${a}${e}`),!0}case"ga4":case"google_ads":{ke(t),_e(`${o.scriptOrigin}/gtag/js?id=${a}`);const e=r.gtag;e("js",new Date);const s="ga4"===i&&n?.gaClientId?{client_id:n.gaClientId}:void 0;return s?e("config",a,s):e("config",a),!0}case"meta_pixel":return be(`!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,document,'script','${o.scriptOrigin}/en_US/fbevents.js');fbq('init','${a}');fbq('track','PageView');`),!0;case"x_pixel":return be(`!function(e,t,n,s,u,a){e.twq||(s=e.twq=function(){s.exe?s.exe.apply(s,arguments):s.queue.push(arguments)},s.version='1.1',s.queue=[],u=t.createElement(n),u.async=!0,u.src='${o.scriptOrigin}/uwt.js',a=t.getElementsByTagName(n)[0],a.parentNode.insertBefore(u,a))}(window,document,'script');twq('config','${a}');`),!0;case"linkedin":return be(`window._linkedin_partner_id='${a}';window._linkedin_data_partner_ids=window._linkedin_data_partner_ids||[];window._linkedin_data_partner_ids.push('${a}');window.lintrk=window.lintrk||function(a,b){(window.lintrk.q=window.lintrk.q||[]).push([a,b])};window.lintrk.q=window.lintrk.q||[];`),_e(`${o.scriptOrigin}/li.lms-analytics/insight.min.js`),!0;case"tiktok":return be(`!function(w,d,t){w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=['page','track','identify','instances','debug','on','off','once','ready','alias','group','enableCookie','disableCookie'];ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.load=function(e,n){var r='${o.scriptOrigin}/i18n/pixel/events.js';ttq._i=ttq._i||{};ttq._i[e]=[];ttq._i[e]._u=r;ttq._t=ttq._t||{};ttq._t[e]=+new Date;ttq._o=ttq._o||{};ttq._o[e]=n||{};var o=d.createElement('script');o.type='text/javascript';o.async=!0;o.src=r+'?sdkid='+e+'&lib='+t;var a=d.getElementsByTagName('script')[0];a.parentNode.insertBefore(o,a)};ttq.load('${a}');ttq.page()}(window,document,'ttq');`),!0;case"reddit":return be(`!function(w,d){if(!w.rdt){var p=w.rdt=function(){p.sendEvent?p.sendEvent.apply(p,arguments):p.callQueue.push(arguments)};p.callQueue=[];var t=d.createElement('script');t.src='${o.scriptOrigin}/ads/pixel.js';t.async=!0;var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(t,s)}}(window,document);rdt('init','${a}');rdt('track','PageVisit');`),!0;case"bing_uet":return be(`(function(w,d,t,r,u){w[u]=w[u]||[];w[u].push({ti:'${a}',enableAutoSpaTracking:false});var o=d.createElement(t);o.src='${o.scriptOrigin}/bat.js';o.async=1;var i=d.getElementsByTagName(t)[0];i.parentNode.insertBefore(o,i)})(window,document,'script',0,'uetq');`),!0;case"clarity":return be(`(function(c,l,a,r,i,t,y){c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};t=l.createElement(r);t.async=1;t.src='${o.scriptOrigin}/tag/'+i;y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y)})(window,document,'clarity','script','${a}');`),!0;case"hotjar":return be(`(function(h,o,t,j,a,r){h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};h._hjSettings={hjid:${a},hjsv:6};a=o.getElementsByTagName('head')[0];r=o.createElement('script');r.async=1;r.src='${o.scriptOrigin}/hotjar-'+h._hjSettings.hjid+'.js?sv='+h._hjSettings.hjsv;a.appendChild(r)})(window,document);`),!0;case"posthog":{const t=o.hosts,n=t?.includes(e.host??"")?e.host:t?.[0]??"us.i.posthog.com";return be(`!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split('.');2==o.length&&(t=t[o[0]],e=o[1]);t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement('script')).type='text/javascript',p.async=!0,p.src='${o.scriptOrigin}/static/array.js',(r=t.getElementsByTagName('script')[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a='posthog',u.people=u.people||[],u.toString=function(t){var e='posthog';return'posthog'!==a&&(e+='.'+a),t||(e+=' (stub)'),e},u.people.toString=function(){return u.toString(1)+'.people (stub)'},o='init capture register register_once identify alias people.set people.set_once set_config get_distinct_id getFeatureFlag isFeatureEnabled onFeatureFlags reloadFeatureFlags group reset'.split(' '),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);posthog.init('${a}',{api_host:'https://${n}'});`),!0}case"plausible":return be("window.plausible=window.plausible||function(){(window.plausible.q=window.plausible.q||[]).push(arguments)};"),_e(`${o.scriptOrigin}/js/script.js`,{"data-domain":a,defer:"true"}),!0;case"ahrefs":return _e(`${o.scriptOrigin}/analytics.js`,{"data-key":a}),r.__ahrefs_loaded=!0,!0;default:return!1}}(e,t,n);return r&&"external"!==e.provider&&e.providerId&&Ie.add(`${e.provider}:${e.providerId}`),r}const je=Symbol.for("@buildbase/sdk.tracking.context"),xe=globalThis,qe=xe[je]??(xe[je]=s(null)),Ue={consent:{manifest:[],state:null,effective:null,default:null,country:null,set:()=>{}},track:()=>{},setUser:()=>{},setIdentity:()=>{},setConsentRecordHeaders:()=>{},setProperties:()=>{},getProperties:()=>({}),completeCheckout:async()=>{},installed:{},ready:!0,attribution:{}};function Oe(){return a(qe)??Ue}const Pe=({serverUrl:a,orgId:s,clientId:c,enabled:d=!0,consent:u="auto",autoPageview:p=!0,events:g,onEvent:f,properties:m,enrich:h,identity:y,debug:w=!1,children:v})=>{const _=t(y);_.current=y;const[b,I]=n(null),[$,S]=n(!1),[A,j]=n(!1),x="object"==typeof u?JSON.stringify(u):"",q=r(()=>x?function(e){if(!e||"object"!=typeof e)return null;const t=e;if("granted"!==t.default&&"denied"!==t.default)return null;const n=e=>Array.isArray(e)?e.filter(e=>"string"==typeof e):void 0;return{default:t.default,regions:{...n(t.regions?.denied)?{denied:n(t.regions?.denied)}:{},...n(t.regions?.granted)?{granted:n(t.regions?.granted)}:{}}}}(JSON.parse(x)):null,[x]),U="string"==typeof u?u:"auto",O="granted"===U?{analytics:!0,marketing:!0}:"denied"===U?{analytics:!1,marketing:!1}:null,[T,L]=n(O),M=t(null),N=t(f);N.current=f;const R=t(h);R.current=h;const H=t({});H.current=m??{};const G=t({}),Z=i(()=>({...H.current,...G.current}),[]),W=i(e=>{const t={...G.current,...e};for(const[e,n]of Object.entries(t))void 0===n&&delete t[e];G.current=t},[]),[K,Q]=n({}),Y=t({}),[ee,te]=n(0),ne=t(null),[re,se]=n(0),le=t({}),ue=t(null);ue.current=b;const ge=b?.dataLayerName??"dataLayer",me=i((...e)=>{w&&console.info("[buildbase:tracking]",...e)},[w]);o(()=>{return e=()=>{0!==Object.keys(Y.current).length&&window.dispatchEvent("function"==typeof PageTransitionEvent?new PageTransitionEvent("pagehide",{persisted:!1}):new Event("pagehide"))},l.add(e),()=>{l.delete(e)};var e},[]),o(()=>{if(!(d&&a&&s&&c))return void S(!0);let e=!1;const t=`${a.replace(/\/$/,"")}/api/v1/public/${s}/tracking?clientId=${encodeURIComponent(c)}`;return fetch(t).then(e=>e.ok?e.json():null).then(t=>{if(e||!t)return;const n=t.data??t;n&&Array.isArray(n.scripts)&&I(n)}).catch(()=>{me("config fetch failed; nothing installed")}).finally(()=>{e||S(!0)}),()=>{e=!0}},[d,a,s,c,me]),o(()=>{d&&Q(k())},[d]);const we="auto"===U?q??b?.consent?.defaults??null:null,ve=r(()=>b?"auto"!==U?U:q?V(q,b.country,b.region):b.consent?.defaults?b.resolvedConsentDefault??V(b.consent.defaults,b.country,b.region):"denied":null,[b,U,q]),_e=T??("granted"===ve?{analytics:!0,marketing:!0}:null),be=!!b?.enhancedConversions&&!!_e?.marketing,Ie=!!b?.scripts?.some(e=>"ga4"===e.provider||"google_ads"===e.provider||"gtm"===e.provider),Ce=we?JSON.stringify(we):"";o(()=>{d&&b?.enabled&&(ke(ge),function(e,t,n={}){const r=z();if(!r)return;Array.isArray(r[e])||(r[e]=[]),"function"!=typeof r.gtag&&(r.gtag=function(){r[e].push(arguments)});const i=r.gtag,o="auto"===t?n.regional:null;let a="granted"===t?"granted":"denied";if(o){const e=B(o.regions?.denied),t=B(o.regions?.granted).filter(t=>!e.includes(t));e.length&&i("consent","default",{...F("denied"),region:e,wait_for_update:500}),t.length&&i("consent","default",{...F("granted"),region:t}),a=o.default}i("consent","default",{...F(a),..."denied"===a?{wait_for_update:500}:{}}),n.google&&(i("set","url_passthrough",!0),i("set","ads_data_redaction","granted"!==(n.resolved??a)))}(ge,U,{regional:Ce?JSON.parse(Ce):null,resolved:ve,google:Ie}),M.current&&J(M.current))},[d,b?.enabled,ge,U,Ce,Ie]);const Se=r(()=>b?.enabled?b.scripts.filter(e=>{const t=ce(e.provider)&&ae[e.provider].supportsConsentMode;return function(e,t,n,r){return"denied"!==r&&("granted"===r||!!t||!!n&&("marketing"===e?n.marketing:n.analytics))}(e.consentCategory,t,_e,U)}):[],[b,T,ve,U]),[je,xe]=n(()=>"undefined"==typeof window||!C(window.location.search));o(()=>{if(je)return;const e=setInterval(()=>{C(window.location.search)||xe(!0)},50),t=setTimeout(()=>xe(!0),5e3);return()=>{clearInterval(e),clearTimeout(t)}},[je]),o(()=>{if(!je)return;if(!d||!b?.enabled)return void($&&j(!0));let e=0;for(const t of Se)if(!Y.current[t.key]){if("external"===t.provider){if(!pe({src:t.src,dataAttributes:t.dataAttributes})){me("rejected external script",t.key);continue}}else{if(!ce(t.provider)){me("rejected unknown provider",t.provider);continue}if(!de(t.provider,t.providerId)){me("rejected id for",t.provider);continue}if($e(t.provider,t.providerId??"")){me(`${t.provider} ${t.providerId} is already on the page; skipping. Configure each tag in exactly one place.`);continue}}Ae(t,ge,_.current)&&(Y.current[t.key]=t.providerId??t.src??"",e+=1,me("installed",t.key))}e&&te(e=>e+1);const t=window;t.__buildbase=t.__buildbase??{},t.__buildbase.tracking={installed:{...Y.current},dataLayerName:ge,clientId:c};const n=Object.keys(Y.current).length>0,r=null!==_e||0===b.scripts.length;(n||r)&&j(!0)},[d,b,Se,$,T,ve,ge,me,je,c]),o(()=>{if(!d||!p||!b?.enabled)return;if("undefined"==typeof window)return;if(!je)return;let e=null;const t=()=>{e&&clearTimeout(e),e=setTimeout(()=>function(e,t){const n=ye();if(!n)return;const r=n[t];Array.isArray(r)&&r.push({event:"page_view",page_path:n.location.pathname,page_location:n.location.href,page_title:n.document.title});for(const t of e)switch(t.provider){case"ga4":n.gtag?.("event","page_view",{send_to:t.providerId,page_path:n.location.pathname,page_location:n.location.href,page_title:n.document.title});break;case"meta_pixel":n.fbq?.("track","PageView");break;case"tiktok":{const e=n.ttq;e?.page?.();break}case"reddit":n.rdt?.("track","PageVisit")}}(Se,ge),50)},n=window.history,r=n.pushState,i=n.replaceState;return n.pushState=function(...e){const n=r.apply(this,e);return t(),n},n.replaceState=function(...e){const n=i.apply(this,e);return t(),n},window.addEventListener("popstate",t),()=>{n.pushState=r,n.replaceState=i,window.removeEventListener("popstate",t),e&&clearTimeout(e)}},[d,p,b?.enabled,Se,ge,je]),o(()=>{if(!d)return;const e=function(e,t){const n=e?.mode??"auto",r=e?.overrides??{};if(("manual"===n||Object.values(r).some(e=>"manual"===e))&&!t)return'[buildbase:tracking] events are set to "manual" but no onEvent handler was provided, so those events would never fire anywhere. Pass onEvent, or use mode "auto".';for(const e of Object.keys(r))if(!he(e))return`[buildbase:tracking] unknown event "${e}" in events.overrides. Overrides only apply to the events the SDK fires itself.`;return null}(g,!!f);if(e)throw new Error(e)},[d,g,f]);const Ue=i((e,t={},n)=>{if(!d)return;const r=n?.eventId||function(){const e=globalThis.crypto;return e?.randomUUID?e.randomUUID():`${Date.now().toString(16)}-${Math.random().toString(16).slice(2,10)}`}(),i=g?.mode??"auto",o=(he(e)?g?.overrides?.[e]:void 0)??i,a={...H.current,...G.current,...K,...t},s=R.current?.({name:e,params:a})??{},c={...a,...s},l=N.current?.({name:e,params:c,eventId:r,handledBy:o});"manual"!==o&&!0!==l?(be&&ne.current&&oe(Se,ne.current),function(e,t,n,r,i){const o=ye();if(!o)return;const a=o[i];Array.isArray(a)&&a.push({event:e,...t,event_id:n});const s=he(e)?fe[e]:{ga4:e,meta:null,tiktok:null,reddit:null};for(const i of r){const r=i.provider,a=ae[r];if(a){if(a.needsConversionIds){const a=i.conversionIds?.[e];if(!a)continue;"google_ads"===r?o.gtag?.("event","conversion",{send_to:`${i.providerId}/${a}`,transaction_id:n,...t}):"x_pixel"===r?o.twq?.("event",a,{...t,conversion_id:n}):"linkedin"===r&&o.lintrk?.("track",{conversion_id:a});continue}switch(r){case"ga4":s.ga4&&o.gtag?.("event",s.ga4,{...t,send_to:i.providerId,event_id:n});break;case"meta_pixel":s.meta&&o.fbq?.("track",s.meta,t,{eventID:n});break;case"tiktok":if(s.tiktok){const e=o.ttq;e?.track?.(s.tiktok,{...t,event_id:n})}break;case"reddit":s.reddit&&o.rdt?.("track",s.reddit,{...t,conversionId:n});break;case"bing_uet":{const r=o.uetq;r?.push?.("event",s.ga4??e,{...t,event_id:n});break}case"clarity":o.clarity?.("event",e);break;case"hotjar":{const t=o.hj;t?.("event",e);break}case"posthog":{const r=o.posthog;r?.capture?.(e,{...t,event_id:n});break}case"plausible":o.plausible?.(e,{props:t})}}}}(e,c,r,Se,ge),me("event fired:",e,r)):me("event handled by app:",e)},[d,g,Se,ge,K,me,be]),Oe=i(async(e,t={})=>{const n=function(e){return{name:"trial_started"===e.kind?"trial_started":"purchase",params:{...e.workspaceId?{workspace_id:e.workspaceId}:{},...e.planVersionId?{plan_version_id:e.planVersionId}:{},...e.creditPackageId?{credit_package_id:e.creditPackageId}:{},...e.billingInterval?{billing_interval:e.billingInterval}:{},...e.currency?{currency:e.currency.toUpperCase()}:{},..."number"==typeof e.value?{value:e.value}:{},...e.sessionId?{transaction_id:e.sessionId}:{}}}}(e);let r=n.params;if(e.sessionId&&a&&s){const t=await async function(e,t){try{const n=e.serverUrl.replace(/\/$/,""),r=await fetch(`${n}/api/v1/public/${encodeURIComponent(e.orgId)}/checkout/${encodeURIComponent(t)}`,{credentials:"omit",..."undefined"!=typeof AbortSignal&&AbortSignal.timeout?{signal:AbortSignal.timeout(2e3)}:{}});if(!r.ok)return null;const i=await r.json(),o=i?.data??i;return"number"!=typeof o?.amount?null:{value:D(o.amount,o.currency),currency:"string"==typeof o.currency?o.currency:void 0,...Array.isArray(o.items)&&o.items.length?{items:o.items}:{}}}catch{return null}}({serverUrl:a,orgId:s},e.sessionId);t&&"number"==typeof t.value&&(r={...r,value:t.value,...t.currency?{currency:t.currency.toUpperCase()}:{},...t.items?.length?{items:t.items}:{}})}if(Ue(n.name,{...r,...t},{eventId:e.eventId}),"purchase"===n.name&&e.sessionId&&a&&s){const t=(b?.scripts??[]).find(e=>"ga4"===e.provider&&e.providerId);t&&$e("ga4",t.providerId??"")&&function(e,t,n){try{const r=e.serverUrl.replace(/\/$/,"");fetch(`${r}/api/v1/public/${encodeURIComponent(e.orgId)}/checkout/${encodeURIComponent(t)}/reported`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider:n}),keepalive:!0,credentials:"omit"}).catch(()=>{})}catch{}}({serverUrl:a,orgId:s},e.sessionId,"ga4")}},[a,s,Ue,b]),[Pe]=n(()=>"undefined"==typeof window?"":window.location.search);o(()=>{if(!d||!A)return;if("undefined"==typeof window)return;const e=P(window.location.search);if(e)return void Oe(e);const t=E(Pe);t&&Ue("checkout_abandoned",{...t.workspaceId?{workspace_id:t.workspaceId}:{},...t.planVersionId?{plan_version_id:t.planVersionId}:{},...t.creditPackageId?{credit_package_id:t.creditPackageId}:{},...t.billingInterval?{billing_interval:t.billingInterval}:{},...t.currency?{currency:t.currency.toUpperCase()}:{},..."number"==typeof t.value?{value:t.value}:{},seconds_at_checkout:Math.max(0,Math.round((Date.now()-t.startedAt)/1e3))})},[d,A,Oe,Pe,Ue]);const Ee=i((e,t)=>{M.current=e,L(e),J(e),d&&X({serverUrl:a,orgId:s,clientId:c,state:e,manifestVersion:ue.current?.consent?.manifestVersion,source:t?.source,consentString:t?.consentString,headers:le.current})},[d,a,s,c]),Te=i(e=>{le.current={...e}},[]),Le=i(e=>{if(!e)return ne.current=null,void se(e=>e+1);ie(e).then(e=>{ne.current=e.emailHash||e.phoneHash?e:null,se(e=>e+1)})},[]),De=i((e,t)=>{const n=function(e){if(!e)return{traits:e,identity:null};const{email:t,phone:n,...r}=e,i={};return"string"==typeof t&&t&&(i.email=t),"string"==typeof n&&n&&(i.phone=n),{traits:r,identity:i.email||i.phone?i:null}}(t);n.identity&&Le(n.identity),function(e,t,n){const r=ye();if(!r)return;const i=!!n&&Object.keys(n).length>0;for(const o of t)switch(o.provider){case"ga4":case"google_ads":r.gtag?.("set",{user_id:e}),i&&r.gtag?.("set",{user_properties:n});break;case"meta_pixel":o.providerId&&r.fbq?.("init",o.providerId,{external_id:e});break;case"posthog":r.posthog?.identify?.(e,i?n:void 0);break;case"clarity":if(r.clarity?.("identify",e),i)for(const[e,t]of Object.entries(n))r.clarity?.("set",e,String(t));break;case"hotjar":r.hj?.("identify",e,{});break;case"tiktok":{const t=r.ttq;t?.identify?.({external_id:e});break}}}(e,Se,n.traits)},[Se,Le]);o(()=>{be&&ne.current&&0!==Object.keys(Y.current).length&&oe(Se,ne.current)},[be,Se,re,ee]);const Me=r(()=>({consent:{manifest:b?.consent?.manifest??[],state:T,effective:_e,default:ve,country:b?.country??null,set:Ee},track:Ue,setUser:De,setIdentity:Le,setConsentRecordHeaders:Te,setProperties:W,getProperties:Z,completeCheckout:Oe,installed:{...Y.current},ready:A,attribution:K}),[b,T,ve,Ee,Ue,De,Le,Te,W,Z,Oe,A,ee,K]);return e(qe.Provider,{value:Me,children:v})};function Ee(e={}){const{completeCheckout:n,ready:r}=Oe(),i=t(e);i.current=e;const a=t(!1);o(()=>{if(!r)return;if(a.current)return;const e=P(window.location.search)??U();e&&(a.current=!0,n(e,i.current))},[r,n])}Pe.displayName="BuildBaseTracking";const Te={sign_in_started:"The sign-in / sign-up button was pressed.",pricing_viewed:"A <PricingPage> finished loading its plans.",pricing_plan_selected:"A plan was chosen on a <PricingPage>.",workspace_switcher_opened:"The workspace switcher was opened.",workspace_settings_opened:"The workspace settings modal was opened.",workspace_settings_section_viewed:"A different section of the settings modal was opened.",plan_picker_opened:"The plan picker was shown.",billing_interval_changed:"Monthly / quarterly / yearly was switched in the plan picker.",plan_selected:"A plan was chosen in the plan picker.",plan_picker_dismissed:"The plan picker was closed without choosing a plan.",checkout_abandoned:"The customer came back from Stripe without paying.",billing_portal_opened:"Stripe’s billing portal was opened.",subscription_cancel_started:"The cancel-subscription confirmation was opened.",subscription_cancelled:"A subscription was cancelled.",subscription_resumed:"A cancelled subscription was resumed.",feature_gate_shown:'A feature gate rendered its "not on your plan" side.',quota_limit_reached:"A quota gate rendered because a quota is used up.",quota_threshold_reached:"A usage-threshold gate rendered.",plan_gate_shown:'A plan gate rendered its "needs another plan" side.',subscription_notice_shown:"A billing notice (trial ending, payment failed…) was shown.",sdk_error:"An SDK operation failed (component, action and code only)."};export{p as ATTRIBUTION_PARAMS,Pe as BuildBaseTracking,M as EEA_COUNTRIES,fe as EVENT_MAPPINGS,Te as FUNNEL_EVENTS,N as SAFE_REGIONAL_CONSENT,ae as TAG_PROVIDERS,se as TAG_PROVIDER_IDS,ge as TAG_SCRIPT_ORIGINS,k as captureAttribution,B as expandRegions,I as getAttribution,ie as hashIdentity,he as isCanonicalEvent,ce as isTagProviderId,de as isValidProviderId,te as normalizeEmail,ne as normalizePhone,V as resolveConsentDefault,Ee as useCheckoutCompleted,Oe as useTracking};
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# Content from your server
|
|
2
|
+
|
|
3
|
+
Blogs, docs, FAQs, testimonials, rich content and collection data are read
|
|
4
|
+
with an **org API token**. That token is your organization's key, so these
|
|
5
|
+
reads happen on your server or at build time, never in a browser.
|
|
6
|
+
|
|
7
|
+
`@buildbase/sdk/server` does the reading, caches it, and keeps the cache
|
|
8
|
+
honest when content changes. It works on any JavaScript server runtime, and
|
|
9
|
+
the HTTP rules underneath work from any language.
|
|
10
|
+
|
|
11
|
+
- [Pick a pattern](#pick-a-pattern)
|
|
12
|
+
- [Server client](#server-client)
|
|
13
|
+
- [Caching](#caching)
|
|
14
|
+
- [Content webhooks](#content-webhooks)
|
|
15
|
+
- [Build-time pull](#build-time-pull)
|
|
16
|
+
- [Next.js](#nextjs)
|
|
17
|
+
- [Other languages](#other-languages)
|
|
18
|
+
- [Reference](#reference)
|
|
19
|
+
|
|
20
|
+
## Pick a pattern
|
|
21
|
+
|
|
22
|
+
| Your app | Use |
|
|
23
|
+
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
24
|
+
| Has a server (Express, Fastify, NestJS, Hono, Remix, Astro SSR, Next) | [Server client](#server-client) with the [webhook](#content-webhooks) |
|
|
25
|
+
| Static site, single-page app, or no backend | [Build-time pull](#build-time-pull), rebuilt by a deploy hook when content changes |
|
|
26
|
+
| Not JavaScript (Python, Go, PHP, Ruby, Java) | [The HTTP API directly](#other-languages), with `If-None-Match` and the same webhook |
|
|
27
|
+
|
|
28
|
+
Whichever you pick, a page render should not call BuildBase. Fetch once, cache,
|
|
29
|
+
and let a webhook tell you when to fetch again. Reads that ignore caching
|
|
30
|
+
count against your plan's content-read allowance.
|
|
31
|
+
|
|
32
|
+
## Server client
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createServerClient } from '@buildbase/sdk/server';
|
|
36
|
+
|
|
37
|
+
export const content = createServerClient({
|
|
38
|
+
serverUrl: 'https://api.console.buildbase.app',
|
|
39
|
+
apiToken: process.env.BUILDBASE_API_TOKEN!, // <orgId>:<secret>
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const posts = await content.blogs.list({ limit: 20, sort: { publishedAt: -1 } });
|
|
43
|
+
const post = await content.blogs.byPath('guides/getting-started');
|
|
44
|
+
const refund = await content.richContent.get('refund-policy');
|
|
45
|
+
const questions = await content.faqs.questions('help-center');
|
|
46
|
+
const quotes = await content.testimonials.list();
|
|
47
|
+
const releases = await content.collections.data<{ title: string; version: string }>(
|
|
48
|
+
'release-notes'
|
|
49
|
+
);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Create the token in the console under **Settings, API tokens**. Give it the
|
|
53
|
+
read-only **content-reader** role: a token that can render a blog should not
|
|
54
|
+
be able to change your billing.
|
|
55
|
+
|
|
56
|
+
The client refuses to run in a browser. Bundlers building for the browser
|
|
57
|
+
resolve `@buildbase/sdk/server` to a module that throws at load, so a stray
|
|
58
|
+
import fails the build loudly instead of shipping your token.
|
|
59
|
+
|
|
60
|
+
Runtimes: Node 18+, Bun, Deno, Cloudflare Workers, Vercel and Netlify edge.
|
|
61
|
+
It uses only the standard `fetch`, `Request` and `Response`.
|
|
62
|
+
|
|
63
|
+
### Express, Fastify, NestJS
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import express from 'express';
|
|
67
|
+
import { createContentWebhookHandler, toNodeHandler } from '@buildbase/sdk/server';
|
|
68
|
+
import { content } from './content';
|
|
69
|
+
|
|
70
|
+
const app = express();
|
|
71
|
+
|
|
72
|
+
app.get('/blog/:slug', async (req, res) => {
|
|
73
|
+
const post = await content.blogs.byPath(req.params.slug);
|
|
74
|
+
if (!post) return res.status(404).send('Not found');
|
|
75
|
+
res.render('post', { post });
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// A raw body: the signature covers the exact bytes BuildBase sent.
|
|
79
|
+
app.post(
|
|
80
|
+
'/webhooks/buildbase',
|
|
81
|
+
express.raw({ type: 'application/json' }),
|
|
82
|
+
toNodeHandler(
|
|
83
|
+
createContentWebhookHandler({
|
|
84
|
+
secret: process.env.BUILDBASE_WEBHOOK_SECRET!,
|
|
85
|
+
cache: content.cache,
|
|
86
|
+
})
|
|
87
|
+
)
|
|
88
|
+
);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Fastify and NestJS take the same `toNodeHandler(...)`; give the route a raw
|
|
92
|
+
body (a content-type parser that keeps the payload as a string or Buffer).
|
|
93
|
+
|
|
94
|
+
### Hono, Cloudflare Workers, Deno, Bun
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { Hono } from 'hono';
|
|
98
|
+
import { createServerClient, handleContentWebhook, kvCache } from '@buildbase/sdk/server';
|
|
99
|
+
|
|
100
|
+
type Env = { BUILDBASE_API_TOKEN: string; BUILDBASE_WEBHOOK_SECRET: string; CONTENT: KVNamespace };
|
|
101
|
+
|
|
102
|
+
const app = new Hono<{ Bindings: Env }>();
|
|
103
|
+
const client = (env: Env) =>
|
|
104
|
+
createServerClient({
|
|
105
|
+
serverUrl: 'https://api.console.buildbase.app',
|
|
106
|
+
apiToken: env.BUILDBASE_API_TOKEN,
|
|
107
|
+
cache: kvCache(env.CONTENT), // shared across isolates
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
app.get('/faq', async c => c.json(await client(c.env).faqs.questions('help-center')));
|
|
111
|
+
|
|
112
|
+
app.post('/webhooks/buildbase', c =>
|
|
113
|
+
handleContentWebhook(c.req.raw, {
|
|
114
|
+
secret: c.env.BUILDBASE_WEBHOOK_SECRET,
|
|
115
|
+
cache: client(c.env).cache,
|
|
116
|
+
})
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
export default app;
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Caching
|
|
123
|
+
|
|
124
|
+
Every read is cached. While an entry is fresh, a read costs nothing. Once it
|
|
125
|
+
is stale, the client asks BuildBase with `If-None-Match`; if nothing changed
|
|
126
|
+
the answer is an empty `304`, served from BuildBase's own cache without
|
|
127
|
+
touching its database.
|
|
128
|
+
|
|
129
|
+
| Option | Default | Meaning |
|
|
130
|
+
| ------------------- | --------------- | ----------------------------------------------------------------------------------------- |
|
|
131
|
+
| `cache` | `memoryCache()` | Where entries live. `false` turns caching off. |
|
|
132
|
+
| `defaultTtlSeconds` | `60` | Freshness when the response carries no `Cache-Control: max-age`. |
|
|
133
|
+
| `retainSeconds` | `86400` | How long a stale entry is kept, for revalidation and the error fallback. |
|
|
134
|
+
| `staleOnError` | `true` | Serve the last good copy if BuildBase errors or is unreachable. 401 and 403 always throw. |
|
|
135
|
+
| `timeoutMs` | `10000` | Per request. |
|
|
136
|
+
|
|
137
|
+
Stores:
|
|
138
|
+
|
|
139
|
+
- `memoryCache({ maxEntries })`: per process. Fine for one server.
|
|
140
|
+
- `redisCache(client, { prefix })`: shared. ioredis and node-redis v4+ both work.
|
|
141
|
+
- `kvCache(binding, { prefix })`: Cloudflare Workers KV, or Upstash Redis REST.
|
|
142
|
+
- Your own: implement `CacheStore` (`get`, `set`, `delete`, `deleteByTag`).
|
|
143
|
+
|
|
144
|
+
Identical reads that arrive at the same time share one request.
|
|
145
|
+
|
|
146
|
+
BuildBase answers content reads with
|
|
147
|
+
`Cache-Control: private, max-age=60, stale-while-revalidate=300`. The client
|
|
148
|
+
honours both numbers: an entry is fresh for 60 seconds, and for the five
|
|
149
|
+
minutes after that a read gets the cached copy at once while one background
|
|
150
|
+
request revalidates it. Only past both does a read wait for BuildBase.
|
|
151
|
+
`private` does not stop the client caching; it tells shared proxies and CDNs
|
|
152
|
+
not to store a response that was fetched with your token, and this cache lives
|
|
153
|
+
on your own server.
|
|
154
|
+
|
|
155
|
+
### Tags
|
|
156
|
+
|
|
157
|
+
Each cached read carries tags, and `content.revalidate(tag)` drops everything
|
|
158
|
+
under one. The same strings appear in content webhooks:
|
|
159
|
+
|
|
160
|
+
| Tag | Covers |
|
|
161
|
+
| ----------------------------- | ----------------------------------------- |
|
|
162
|
+
| `buildbase:blog` | every blog list |
|
|
163
|
+
| `buildbase:blog:<slug>` | one post, by slug (same for every module) |
|
|
164
|
+
| `buildbase:blog:id:<id>` | one post, by id |
|
|
165
|
+
| `buildbase:collection:<slug>` | every record of one collection |
|
|
166
|
+
| `buildbase:all` | everything this client cached |
|
|
167
|
+
|
|
168
|
+
Modules: `blog`, `doc`, `faq`, `faq_collection`, `testimonial`,
|
|
169
|
+
`rich_content`, `collection`. `contentTags.*` builds them, and
|
|
170
|
+
`getContentTags(result)` tells you which tags a result was stored under.
|
|
171
|
+
|
|
172
|
+
## Content webhooks
|
|
173
|
+
|
|
174
|
+
In the console, under **Settings, Webhooks**, add an endpoint pointing at your
|
|
175
|
+
route and subscribe it to the content events (or to everything; the handler
|
|
176
|
+
ignores what it does not need):
|
|
177
|
+
|
|
178
|
+
`blog.published`, `blog.updated`, `blog.unpublished`, `blog.deleted`, the same
|
|
179
|
+
four for `doc`, `faq.updated`, `faq_collection.updated`,
|
|
180
|
+
`testimonial.updated`, `testimonial.deleted`, `rich_content.updated`,
|
|
181
|
+
`rich_content.deleted`, `collection.version_published`,
|
|
182
|
+
`collection.record_created`, `collection.record_updated`,
|
|
183
|
+
`collection.record_deleted`.
|
|
184
|
+
|
|
185
|
+
`handleContentWebhook(request, { secret, cache })` verifies the signature
|
|
186
|
+
(HMAC-SHA256 over `<timestamp>.<body>`, five-minute window), drops the tags the
|
|
187
|
+
event names, and answers `200`. A bad signature gets `401`. Pass `revalidate`
|
|
188
|
+
instead of, or as well as, `cache` to invalidate a framework's own cache, and
|
|
189
|
+
`onEvent` to trigger anything else, such as a static site rebuild.
|
|
190
|
+
|
|
191
|
+
## Build-time pull
|
|
192
|
+
|
|
193
|
+
For sites with no server of their own: pull the content once, in CI, and ship
|
|
194
|
+
it as a JSON file. The token stays in CI.
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
BUILDBASE_SERVER_URL=https://api.console.buildbase.app \
|
|
198
|
+
BUILDBASE_API_TOKEN=$BUILDBASE_API_TOKEN \
|
|
199
|
+
npx buildbase content pull --out src/content/buildbase.json
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
| Flag | Default |
|
|
203
|
+
| ----------------------- | ------------------------------------------------------ |
|
|
204
|
+
| `--out <file>` | required |
|
|
205
|
+
| `--modules <list>` | `blogs,docs,faqs,testimonials,richContent,collections` |
|
|
206
|
+
| `--collections <slugs>` | every live collection |
|
|
207
|
+
| `--page-size <n>` | `100` |
|
|
208
|
+
| `--server-url <url>` | `BUILDBASE_SERVER_URL` |
|
|
209
|
+
|
|
210
|
+
The file is `{ generatedAt, blogs, docs, faqs, testimonials, richContent, collections }`,
|
|
211
|
+
with published content only. `pullContent(client, options)` does the same from
|
|
212
|
+
your own build script.
|
|
213
|
+
|
|
214
|
+
To rebuild when content changes, point a content webhook at a small function
|
|
215
|
+
that calls your host's deploy hook, or use the console's deploy hooks
|
|
216
|
+
(**Settings, Deployments**).
|
|
217
|
+
|
|
218
|
+
## Next.js
|
|
219
|
+
|
|
220
|
+
Next.js has its own data cache, keyed by tags. `@buildbase/sdk/server/next`
|
|
221
|
+
hands caching to it:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
// lib/content.ts
|
|
225
|
+
import { createServerClient } from '@buildbase/sdk/server';
|
|
226
|
+
import { withNextCache } from '@buildbase/sdk/server/next';
|
|
227
|
+
|
|
228
|
+
export const content = createServerClient({
|
|
229
|
+
serverUrl: process.env.BUILDBASE_SERVER_URL!,
|
|
230
|
+
apiToken: process.env.BUILDBASE_API_TOKEN!,
|
|
231
|
+
...withNextCache({ revalidate: 300 }),
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
// app/api/webhooks/buildbase/route.ts
|
|
237
|
+
import { createNextWebhookHandler } from '@buildbase/sdk/server/next';
|
|
238
|
+
|
|
239
|
+
export const POST = createNextWebhookHandler({ secret: process.env.BUILDBASE_WEBHOOK_SECRET! });
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Every read goes out with `{ next: { tags, revalidate } }`, and the webhook calls
|
|
243
|
+
`revalidateTag` for what changed. `next` is an optional peer dependency; apps
|
|
244
|
+
on other frameworks never load it.
|
|
245
|
+
|
|
246
|
+
## Other languages
|
|
247
|
+
|
|
248
|
+
The client is a convenience; the rules are HTTP.
|
|
249
|
+
|
|
250
|
+
- Send the token as `Authorization: Bearer <orgId>:<secret>` from your server.
|
|
251
|
+
- Reads answer with `ETag` and `Cache-Control`. Store the body and the ETag;
|
|
252
|
+
send `If-None-Match: <etag>` next time and a `304` means your copy is current.
|
|
253
|
+
- `filter` and `sort` are bracket-encoded: `?filter[published]=true&sort[publishedAt]=-1&$limit=20`.
|
|
254
|
+
- Verify webhooks: `hex(HMAC-SHA256(secret, timestamp + "." + rawBody))` must
|
|
255
|
+
equal the part after `sha256=` in `x-buildbase-signature`, and
|
|
256
|
+
`x-buildbase-timestamp` must be within five minutes. Then drop `data.tags`.
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
curl -s -D - -H "Authorization: Bearer $BUILDBASE_API_TOKEN" \
|
|
260
|
+
"https://api.console.buildbase.app/api/rich-content/slug/refund-policy"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
import hmac, hashlib, time
|
|
265
|
+
|
|
266
|
+
def verify(secret: str, body: bytes, signature: str, timestamp: str) -> bool:
|
|
267
|
+
if abs(time.time() - int(timestamp)) > 300:
|
|
268
|
+
return False
|
|
269
|
+
expected = hmac.new(secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
|
|
270
|
+
return hmac.compare_digest("sha256=" + expected, signature)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Reference
|
|
274
|
+
|
|
275
|
+
| Call | Endpoint | Returns |
|
|
276
|
+
| ---------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------ |
|
|
277
|
+
| `blogs.list({ page, limit, filter, sort, includeDrafts })` | `GET /api/blogs` | `Paginated<BlogPost>`, published only by default |
|
|
278
|
+
| `blogs.get(id)` | `GET /api/blogs/:id` | `BlogPost \| null` |
|
|
279
|
+
| `blogs.byPath(path, { draftPreview })` | `GET /api/blogs/path?path=` | `BlogPost \| null` |
|
|
280
|
+
| `blogs.tree({ folder })` | `GET /api/blogs/folders/tree` | folder tree |
|
|
281
|
+
| `blogs.tags()`, `blogs.authors()` | `GET /api/blogs/tags`, `/authors` | `Paginated<...>` |
|
|
282
|
+
| `docs.*` | the same under `/api/docs` | `DocPage` |
|
|
283
|
+
| `faqs.collections()` | `GET /api/faqs/collections` | `Paginated<FaqCollection>` |
|
|
284
|
+
| `faqs.collection(slugOrId)` | `GET /api/faqs/collections/slug/:slug` or `/:id` | `FaqCollection \| null` |
|
|
285
|
+
| `faqs.questions(slugOrId)` | `GET /api/faqs/collections/slug/:slug/faqs` or `/:id/faqs` | `Faq[]`, `[]` when the collection does not exist |
|
|
286
|
+
| `testimonials.list({ includeUnpublished })` | `GET /api/testimonials` | published only by default |
|
|
287
|
+
| `testimonials.get(id)` | `GET /api/testimonials/:id` | `Testimonial \| null` |
|
|
288
|
+
| `richContent.get(slug)`, `.list()` | `GET /api/rich-content/slug/:slug` | `RichContent \| null` |
|
|
289
|
+
| `collections.data(slug, { version })`, `.list()` | `GET /api/collections/data/:slug?latest=true`, or `?version=` | `CollectionRecord[]` |
|
|
290
|
+
| `revalidate(tag)`, `revalidateAll()` | | drops cached reads |
|
|
291
|
+
|
|
292
|
+
The slug routes for FAQ collections, `GET /api/testimonials/:id` and
|
|
293
|
+
collection data without a `version` need the BuildBase server release that
|
|
294
|
+
ships content delivery; an older server answers those with 404 or 400. The
|
|
295
|
+
rest of the table works on any server.
|
|
296
|
+
|
|
297
|
+
Errors are `BuildBaseContentError` with `status`, `url` and the response `body`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildbase/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.74",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A SDK for Buildbase",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -37,12 +37,57 @@
|
|
|
37
37
|
"require": "./dist/mcp/index.cjs",
|
|
38
38
|
"default": "./dist/mcp/index.cjs"
|
|
39
39
|
},
|
|
40
|
+
"./server": {
|
|
41
|
+
"types": "./dist/server/index.d.ts",
|
|
42
|
+
"workerd": "./dist/server/index.mjs",
|
|
43
|
+
"worker": "./dist/server/index.mjs",
|
|
44
|
+
"edge-light": "./dist/server/index.mjs",
|
|
45
|
+
"deno": "./dist/server/index.mjs",
|
|
46
|
+
"bun": "./dist/server/index.mjs",
|
|
47
|
+
"react-server": {
|
|
48
|
+
"import": "./dist/server/index.mjs",
|
|
49
|
+
"require": "./dist/server/index.cjs"
|
|
50
|
+
},
|
|
51
|
+
"node": {
|
|
52
|
+
"import": "./dist/server/index.mjs",
|
|
53
|
+
"require": "./dist/server/index.cjs"
|
|
54
|
+
},
|
|
55
|
+
"browser": {
|
|
56
|
+
"import": "./dist/server/browser.mjs",
|
|
57
|
+
"require": "./dist/server/browser.cjs"
|
|
58
|
+
},
|
|
59
|
+
"import": "./dist/server/index.mjs",
|
|
60
|
+
"require": "./dist/server/index.cjs",
|
|
61
|
+
"default": "./dist/server/index.cjs"
|
|
62
|
+
},
|
|
63
|
+
"./server/next": {
|
|
64
|
+
"types": "./dist/server/next/index.d.ts",
|
|
65
|
+
"edge-light": "./dist/server/next/index.mjs",
|
|
66
|
+
"react-server": {
|
|
67
|
+
"import": "./dist/server/next/index.mjs",
|
|
68
|
+
"require": "./dist/server/next/index.cjs"
|
|
69
|
+
},
|
|
70
|
+
"node": {
|
|
71
|
+
"import": "./dist/server/next/index.mjs",
|
|
72
|
+
"require": "./dist/server/next/index.cjs"
|
|
73
|
+
},
|
|
74
|
+
"browser": {
|
|
75
|
+
"import": "./dist/server/browser.mjs",
|
|
76
|
+
"require": "./dist/server/browser.cjs"
|
|
77
|
+
},
|
|
78
|
+
"import": "./dist/server/next/index.mjs",
|
|
79
|
+
"require": "./dist/server/next/index.cjs",
|
|
80
|
+
"default": "./dist/server/next/index.cjs"
|
|
81
|
+
},
|
|
40
82
|
"./css": {
|
|
41
83
|
"types": "./dist/css/styles.d.ts",
|
|
42
84
|
"default": "./dist/css/styles.css"
|
|
43
85
|
},
|
|
44
86
|
"./package.json": "./package.json"
|
|
45
87
|
},
|
|
88
|
+
"bin": {
|
|
89
|
+
"buildbase": "dist/cli.mjs"
|
|
90
|
+
},
|
|
46
91
|
"typesVersions": {
|
|
47
92
|
"*": {
|
|
48
93
|
"react": [
|
|
@@ -59,6 +104,12 @@
|
|
|
59
104
|
],
|
|
60
105
|
"tracking": [
|
|
61
106
|
"./dist/tracking/index.d.ts"
|
|
107
|
+
],
|
|
108
|
+
"server": [
|
|
109
|
+
"./dist/server/index.d.ts"
|
|
110
|
+
],
|
|
111
|
+
"server/next": [
|
|
112
|
+
"./dist/server/next/index.d.ts"
|
|
62
113
|
]
|
|
63
114
|
}
|
|
64
115
|
},
|
|
@@ -71,14 +122,17 @@
|
|
|
71
122
|
"docs/ERROR_CODES.md",
|
|
72
123
|
"docs/MCP-AND-AGENT-READINESS.md",
|
|
73
124
|
"docs/THEMING.md",
|
|
74
|
-
"docs/UI-CONFIG.md"
|
|
125
|
+
"docs/UI-CONFIG.md",
|
|
126
|
+
"docs/SERVER-CONTENT.md"
|
|
75
127
|
],
|
|
76
128
|
"sideEffects": [
|
|
77
|
-
"**/*.css"
|
|
129
|
+
"**/*.css",
|
|
130
|
+
"./dist/server/browser.mjs",
|
|
131
|
+
"./dist/server/browser.cjs"
|
|
78
132
|
],
|
|
79
133
|
"scripts": {
|
|
80
134
|
"build": "rollup -c && rollup -c rollup.dts.config.js && npm run postbuild",
|
|
81
|
-
"postbuild": "rimraf dist/types dist/react/types dist/data/types dist/mcp/types dist/tracking/types dist/*.map dist/react/*.map dist/data/*.map dist/mcp/*.map dist/tracking/*.map && mkdir -p dist/css && [ -f dist/react/styles.css ] && mv dist/react/styles.css dist/css/styles.css || true && cp src/css.d.ts dist/css/styles.d.ts",
|
|
135
|
+
"postbuild": "rimraf dist/types dist/react/types dist/data/types dist/mcp/types dist/tracking/types dist/server/types dist/server/next/types dist/server/browser-types dist/cli-types dist/*.map dist/react/*.map dist/data/*.map dist/mcp/*.map dist/tracking/*.map dist/server/*.map dist/server/next/*.map && mkdir -p dist/css && [ -f dist/react/styles.css ] && mv dist/react/styles.css dist/css/styles.css || true && cp src/css.d.ts dist/css/styles.d.ts",
|
|
82
136
|
"build:analyze": "rollup --config rollup.config.analyze.js",
|
|
83
137
|
"dev": "rollup -c -w",
|
|
84
138
|
"clean": "rimraf dist",
|
|
@@ -103,7 +157,13 @@
|
|
|
103
157
|
},
|
|
104
158
|
"peerDependencies": {
|
|
105
159
|
"react": "^18.0.0 || ^19.0.0",
|
|
106
|
-
"react-dom": "^18.0.0 || ^19.0.0"
|
|
160
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
161
|
+
"next": ">=13"
|
|
162
|
+
},
|
|
163
|
+
"peerDependenciesMeta": {
|
|
164
|
+
"next": {
|
|
165
|
+
"optional": true
|
|
166
|
+
}
|
|
107
167
|
},
|
|
108
168
|
"dependencies": {
|
|
109
169
|
"@hookform/resolvers": "^5.0.1",
|