@datanova/browser
Version:
Lightweight browser SDK for event tracking and A/B testing
1 lines • 36.7 kB
Source Map (JSON)
{"version":3,"sources":["../src/storage/base-storage.ts","../src/storage/local-storage.ts","../src/storage/session-storage.ts","../src/core/context.ts","../src/types.ts","../src/core/experiment-manager.ts","../src/utils.ts","../src/core/tracker.ts","../src/datanova.ts","../src/services/events/datanova.ts","../src/services/events/console.ts","../src/services/events/noop.ts","../src/services/experiments/datanova.ts","../src/services/experiments/random.ts","../src/identity.ts","../src/createDatanova.ts"],"names":["BrowserStorage","type","customPrefix","origin","originHash","key","item","value","str","hash","i","char","browserLocalStorage","browserSessionStorage","ContextManager","userId","properties","contextOverrides","sessionId","fingerprint","prefix","timestamp","random","EventType","InternalEventType","ExperimentManager","experimentsService","tracker","experimentId","identifier","assignmentKey","previousAssignment","variant","assignmentRecord","deepClone","obj","clonedMap","cloned","Tracker","eventsService","contextManager","eventName","eventType","eventContext","event","Datanova","config","DatanovaEventsService","sdkKey","endpoint","response","error","ConsoleEventsService","styles","NoopEventsService","_event","ASSIGNMENT_REASONS","ASSIGNMENT_TTLS","DatanovaExperimentsService","storageKey","stored","request","reason","assignment","RandomExperimentsService","splitRatio","cacheKey","cached","generateAnonymousId","createDatanova","keyOrServices","datanova"],"mappings":"AAEO,IAAMA,CAAAA,CAAN,KAAqB,CAI1B,WAAA,CAAYC,EAAmBC,CAAAA,CAAuB,CAOpD,GANI,OAAO,MAAA,CAAW,IACpB,IAAA,CAAK,OAAA,CAAUD,IAAS,cAAA,CAAiB,MAAA,CAAO,aAAe,MAAA,CAAO,cAAA,CAEtE,KAAK,OAAA,CAAU,IAAA,CAGbC,EACF,IAAA,CAAK,MAAA,CAASA,OACT,CACL,IAAMC,EAAS,OAAO,MAAA,CAAW,IAAc,MAAA,CAAO,QAAA,CAAS,OAAS,SAAA,CAClEC,CAAAA,CAAa,KAAK,UAAA,CAAWD,CAAM,EAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,EAAE,CAAA,CAChE,KAAK,MAAA,CAAS,CAAA,qBAAA,EAAwBC,CAAU,CAAA,CAAA,EAClD,CACF,CAEA,GAAA,CAAOC,CAAAA,CAAuB,CAC5B,GAAI,CAAC,KAAK,OAAA,CACR,OAAO,KAGT,GAAI,CACF,IAAMC,CAAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,MAAA,CAASD,CAAG,CAAA,CACnD,OAAOC,EAAO,IAAA,CAAK,KAAA,CAAMA,CAAI,CAAA,CAAI,IACnC,MAAQ,CACN,OAAO,IACT,CACF,CAEA,IAAOD,CAAAA,CAAaE,CAAAA,CAAgB,CAClC,GAAK,IAAA,CAAK,OAAA,CAIV,GAAI,CACF,IAAA,CAAK,QAAQ,OAAA,CAAQ,IAAA,CAAK,OAASF,CAAAA,CAAK,IAAA,CAAK,UAAUE,CAAK,CAAC,EAC/D,CAAA,KAAQ,CAER,CACF,CAEA,MAAA,CAAOF,EAAmB,CACxB,GAAK,KAAK,OAAA,CAIV,GAAI,CACF,IAAA,CAAK,OAAA,CAAQ,WAAW,IAAA,CAAK,MAAA,CAASA,CAAG,EAC3C,CAAA,KAAQ,CAER,CACF,CAEQ,WAAWG,CAAAA,CAAqB,CACtC,IAAIC,CAAAA,CAAO,CAAA,CACX,QAASC,CAAAA,CAAI,CAAA,CAAGA,EAAIF,CAAAA,CAAI,MAAA,CAAQE,CAAAA,EAAAA,CAAK,CACnC,IAAMC,CAAAA,CAAOH,EAAI,UAAA,CAAWE,CAAC,EAC7BD,CAAAA,CAAAA,CAAQA,CAAAA,EAAQ,GAAKA,CAAAA,CAAOE,CAAAA,CAC5BF,EAAOA,CAAAA,CAAOA,EAChB,CACA,OAAO,IAAA,CAAK,IAAIA,CAAI,CACtB,CACF,CAAA,CClEO,IAAMG,CAAAA,CAAsB,IAAIZ,CAAAA,CAAe,cAAc,ECA7D,IAAMa,CAAAA,CAAwB,IAAIb,CAAAA,CAAe,gBAAgB,ECEjE,IAAMc,CAAAA,CAAN,KAAqB,CAO1B,WAAA,EAAc,CACZ,IAAA,CAAK,SAAA,CAAY,KAAK,oBAAA,EAAqB,CAC3C,KAAK,WAAA,CAAc,IAAA,CAAK,sBAAA,GAC1B,CAEA,OAAA,CAAQC,EAAgBC,CAAAA,CAA4C,CAClE,KAAK,MAAA,CAASD,CAAAA,CACd,KAAK,cAAA,CAAiBC,EACxB,CAEA,SAAA,EAAkB,CAChB,KAAK,MAAA,CAAS,MAAA,CACd,KAAK,cAAA,CAAiB,OACxB,CAEA,eAAA,CAAgBC,CAAAA,CAA0C,CACxD,IAAA,CAAK,gBAAA,CAAmBA,EAC1B,CAEA,UAAA,EAAsB,CAYpB,OAAO,CACL,GAZ2B,CAC3B,MAAA,CAAQ,KAAK,MAAA,CACb,cAAA,CAAgB,KAAK,cAAA,CACrB,SAAA,CAAW,KAAK,SAAA,CAChB,OAAA,CAAS,KAAK,iBAAA,EAAkB,CAChC,OAAA,CAAS,CACP,IAAA,CAAM,mBAAA,CACN,QAAS,OACX,CACF,EAIE,GAAG,IAAA,CAAK,gBACV,CACF,CAEA,eAAwB,CACtB,OAAO,KAAK,MAAA,EAAU,IAAA,CAAK,aAAe,IAAA,CAAK,SACjD,CAEQ,iBAAA,EAAoC,CAC1C,OAAI,OAAO,MAAA,CAAW,GAAA,CACb,CACL,GAAA,CAAK,EAAA,CACL,MAAO,EAAA,CACP,QAAA,CAAU,GACV,IAAA,CAAM,EAAA,CACN,OAAQ,EAAA,CACR,SAAA,CAAW,EACb,CAAA,CAGK,CACL,IAAK,MAAA,CAAO,QAAA,CAAS,KACrB,KAAA,CAAO,QAAA,CAAS,KAAA,CAChB,QAAA,CAAU,QAAA,CAAS,QAAA,CACnB,KAAM,MAAA,CAAO,QAAA,CAAS,SACtB,MAAA,CAAQ,MAAA,CAAO,SAAS,MAAA,CACxB,SAAA,CAAW,UAAU,SACvB,CACF,CAEQ,oBAAA,EAA+B,CACrC,IAAMZ,CAAAA,CAAM,YAAA,CACRa,EAAYL,CAAAA,CAAsB,GAAA,CAAYR,CAAG,CAAA,CAErD,OAAKa,CAAAA,GACHA,EAAY,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA,CAChCL,CAAAA,CAAsB,IAAIR,CAAAA,CAAKa,CAAS,GAGnCA,CACT,CAEQ,wBAAiC,CACvC,IAAMb,EAAM,aAAA,CACRc,CAAAA,CAAcP,EAAoB,GAAA,CAAYP,CAAG,CAAA,CAErD,OAAKc,CAAAA,GACHA,CAAAA,CAAc,KAAK,UAAA,CAAW,IAAI,EAClCP,CAAAA,CAAoB,GAAA,CAAIP,EAAKc,CAAW,CAAA,CAAA,CAGnCA,CACT,CAEQ,UAAA,CAAWC,EAAwB,CACzC,IAAMC,EAAY,IAAA,CAAK,GAAA,GAAM,QAAA,CAAS,EAAE,CAAA,CAClCC,CAAAA,CAAS,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,SAAA,CAAU,CAAA,CAAG,EAAE,CAAA,CACzD,OAAO,GAAGF,CAAM,CAAA,CAAA,EAAIC,CAAS,CAAA,CAAA,EAAIC,CAAM,EACzC,CACF,CAAA,KC/FaC,CAAAA,CAAY,CACvB,KAAA,CAAO,OAAA,CACP,SAAA,CAAW,UAAA,CACX,WAAY,YAAA,CACZ,MAAA,CAAQ,SACR,MAAA,CAAQ,QACV,EAIaC,CAAAA,CAAoB,CAC/B,OAAQ,QACV,ECZO,IAAMC,CAAAA,CAAN,KAAwB,CAC7B,WAAA,CACUC,CAAAA,CACAC,EACR,CAFQ,IAAA,CAAA,kBAAA,CAAAD,EACA,IAAA,CAAA,OAAA,CAAAC,EACP,CAEH,MAAM,UAAA,CAAWC,EAAsBC,CAAAA,CAAsC,CAC3E,IAAMC,CAAAA,CAAgB,IAAA,CAAK,iBAAiBF,CAAAA,CAAcC,CAAU,EAE9DE,CAAAA,CAAqBnB,CAAAA,CAAoB,IAAsBkB,CAAa,CAAA,CAE5EE,EAAU,MAAM,IAAA,CAAK,kBAAA,CAAmB,UAAA,CAAWJ,CAAAA,CAAcC,CAAU,EAIjF,GAF8B,CAACE,GAAsBA,CAAAA,CAAmB,OAAA,GAAYC,EAEzD,CACzB,IAAMC,EAAqC,CACzC,OAAA,CAAAD,EACA,UAAA,CAAY,IAAA,CAAK,KACnB,CAAA,CACApB,EAAoB,GAAA,CAAIkB,CAAAA,CAAeG,CAAgB,CAAA,CAEvD,IAAA,CAAK,OAAA,EAAS,MAAM,mBAAA,CAAqBT,CAAAA,CAAkB,OAAqB,CAC9E,aAAA,CAAeI,EACf,OAAA,CAAAI,CACF,CAAC,EACH,CAEA,OAAOA,CACT,CAEQ,iBAAiBJ,CAAAA,CAAsBC,CAAAA,CAA4B,CACzE,OAAO,CAAA,WAAA,EAAcD,CAAY,CAAA,CAAA,EAAIC,CAAU,CAAA,CACjD,CACF,CAAA,CC1CO,SAASK,EAAaC,CAAAA,CAAW,CACtC,GAAIA,CAAAA,GAAQ,IAAA,EAAQ,OAAOA,CAAAA,EAAQ,QAAA,CACjC,OAAOA,CAAAA,CAGT,GAAIA,aAAe,IAAA,CACjB,OAAO,IAAI,IAAA,CAAKA,CAAAA,CAAI,SAAS,CAAA,CAG/B,GAAI,KAAA,CAAM,OAAA,CAAQA,CAAG,CAAA,CACnB,OAAOA,EAAI,GAAA,CAAK7B,CAAAA,EAAS4B,EAAU5B,CAAI,CAAC,EAG1C,GAAI6B,CAAAA,YAAe,IACjB,OAAO,IAAI,IAAI,KAAA,CAAM,IAAA,CAAKA,CAAG,CAAA,CAAE,GAAA,CAAK7B,CAAAA,EAAS4B,EAAU5B,CAAI,CAAC,CAAC,CAAA,CAG/D,GAAI6B,aAAe,GAAA,CAAK,CACtB,IAAMC,CAAAA,CAAY,IAAI,IACtB,OAAAD,CAAAA,CAAI,QAAQ,CAAC5B,CAAAA,CAAOF,IAAQ,CAC1B+B,CAAAA,CAAU,GAAA,CAAIF,CAAAA,CAAU7B,CAAG,CAAA,CAAG6B,EAAU3B,CAAK,CAAC,EAChD,CAAC,CAAA,CAEM6B,CACT,CAEA,IAAMC,EAAS,EAAC,CAEhB,QAAWhC,CAAAA,IAAO8B,CAAAA,CACZ,OAAO,SAAA,CAAU,cAAA,CAAe,KAAKA,CAAAA,CAAK9B,CAAG,CAAA,GAC/CgC,CAAAA,CAAOhC,CAAG,CAAA,CAAI6B,EAAUC,CAAAA,CAAI9B,CAAG,CAAC,CAAA,CAAA,CAIpC,OAAOgC,CACT,CC5BO,IAAMC,EAAN,KAAkC,CACvC,YACUC,CAAAA,CACAC,CAAAA,CACR,CAFQ,IAAA,CAAA,aAAA,CAAAD,CAAAA,CACA,oBAAAC,EACP,CAEH,MAAMC,CAAAA,CAAmBC,CAAAA,CAAsB1B,EAA4C,CACzF,IAAM2B,EAAe,IAAA,CAAK,cAAA,CAAe,YAAW,CAE9CC,CAAAA,CAAe,CACnB,SAAA,CAAAH,CAAAA,CACA,UAAAC,CAAAA,CACA,UAAA,CAAY1B,EAAakB,CAAAA,CAAUlB,CAAU,EAAI,MAAA,CACjD,SAAA,CAAW,IAAI,IAAA,EAAK,CAAE,WAAA,GACtB,OAAA,CAAS2B,CACX,EAEA,IAAA,CAAK,aAAA,CAAc,KAAKC,CAAK,EAC/B,CACF,CAAA,CCrBO,IAAMC,EAAN,KAAe,CAAf,cACL,IAAA,CAAQ,WAAA,CAAc,MAEtB,IAAA,CAAiB,cAAA,CAAiB,IAAI/B,CAAAA,CA6BtC,IAAA,CAAA,QAAA,CAAW,CAACC,EAAgBC,CAAAA,GAA+C,CACzE,KAAK,iBAAA,EAAkB,CACvB,KAAK,cAAA,CAAe,OAAA,CAAQD,EAAQC,CAAU,EAChD,EAEA,IAAA,CAAA,KAAA,CAAQ,IAAY,CAClB,IAAA,CAAK,iBAAA,GACL,IAAA,CAAK,cAAA,CAAe,SAAA,GACtB,CAAA,CAEA,IAAA,CAAA,KAAA,CAAQ,CAACyB,CAAAA,CAAmBC,CAAAA,CAAsB1B,IAA+C,CAC/F,IAAA,CAAK,mBAAkB,CACvB,IAAA,CAAK,eAAc,CACnB,IAAA,CAAK,QAAS,KAAA,CAAMyB,CAAAA,CAAWC,EAAW1B,CAAU,EACtD,EAEA,IAAA,CAAA,UAAA,CAAa,CAACyB,CAAAA,CAAmBzB,CAAAA,GAA+C,CAC9E,IAAA,CAAK,mBAAkB,CACvB,IAAA,CAAK,eAAc,CACnB,IAAA,CAAK,QAAS,KAAA,CAAMyB,CAAAA,CAAWlB,EAAU,KAAA,CAAOP,CAAU,EAC5D,CAAA,CAEA,IAAA,CAAA,aAAA,CAAgB,CAACyB,CAAAA,CAAmBzB,CAAAA,GAA+C,CACjF,IAAA,CAAK,iBAAA,EAAkB,CACvB,IAAA,CAAK,aAAA,EAAc,CACnB,KAAK,OAAA,CAAS,KAAA,CAAMyB,EAAWlB,CAAAA,CAAU,SAAA,CAAWP,CAAU,EAChE,CAAA,CAEA,qBAAkB,CAACyB,CAAAA,CAAmBzB,IAA+C,CACnF,IAAA,CAAK,mBAAkB,CACvB,IAAA,CAAK,eAAc,CACnB,IAAA,CAAK,OAAA,CAAS,KAAA,CAAMyB,CAAAA,CAAWlB,CAAAA,CAAU,WAAYP,CAAU,EACjE,EAEA,IAAA,CAAA,WAAA,CAAc,CAACyB,EAAmBzB,CAAAA,GAA+C,CAC/E,KAAK,iBAAA,EAAkB,CACvB,KAAK,aAAA,EAAc,CACnB,KAAK,OAAA,CAAS,KAAA,CAAMyB,EAAWlB,CAAAA,CAAU,MAAA,CAAQP,CAAU,EAC7D,CAAA,CAEA,IAAA,CAAA,WAAA,CAAc,CAACyB,CAAAA,CAAmBzB,CAAAA,GAA+C,CAC/E,IAAA,CAAK,iBAAA,GACL,IAAA,CAAK,aAAA,GACL,IAAA,CAAK,OAAA,CAAS,MAAMyB,CAAAA,CAAWlB,CAAAA,CAAU,OAAQP,CAAU,EAC7D,EAEA,IAAA,CAAA,UAAA,CAAa,MAAOY,GAA2C,CAC7D,IAAA,CAAK,mBAAkB,CACvB,IAAA,CAAK,yBAAwB,CAE7B,IAAMC,EAAa,IAAA,CAAK,cAAA,CAAe,eAAc,CACrD,OAAO,KAAK,iBAAA,CAAmB,UAAA,CAAWD,EAAcC,CAAU,CACpE,GA9EA,IAAA,CAAKiB,CAAAA,CAAyB,CAC5B,GAAI,CAAA,IAAA,CAAK,WAAA,CAIT,IAAI,CAACA,CAAAA,CAAO,eAAiB,CAACA,CAAAA,CAAO,mBACnC,MAAM,IAAI,MACR,gGACF,CAAA,CAGEA,EAAO,OAAA,EACT,IAAA,CAAK,eAAe,eAAA,CAAgBA,CAAAA,CAAO,OAAO,CAAA,CAGhDA,CAAAA,CAAO,aAAA,GACT,IAAA,CAAK,OAAA,CAAU,IAAIR,EAAoBQ,CAAAA,CAAO,aAAA,CAAe,KAAK,cAAc,CAAA,CAAA,CAG9EA,EAAO,kBAAA,GACT,IAAA,CAAK,kBAAoB,IAAIrB,CAAAA,CAAkBqB,EAAO,kBAAA,CAAoB,IAAA,CAAK,OAAO,CAAA,CAAA,CAGxF,IAAA,CAAK,YAAc,KAAA,CACrB,CAwDQ,iBAAA,EAA0B,CAChC,GAAI,CAAC,KAAK,WAAA,CACR,MAAM,IAAI,KAAA,CAAM,4CAA4C,CAEhE,CAEQ,aAAA,EAAsB,CAC5B,GAAI,CAAC,KAAK,OAAA,CACR,MAAM,IAAI,KAAA,CACR,qGACF,CAEJ,CAEQ,uBAAA,EAAgC,CACtC,GAAI,CAAC,KAAK,iBAAA,CACR,MAAM,IAAI,KAAA,CACR,iHACF,CAEJ,CACF,MC5GaC,CAAAA,CAAN,KAAqD,CAC1D,WAAA,CACUC,CAAAA,CACAC,EAAmB,kCAAA,CAC3B,CAFQ,YAAAD,CAAAA,CACA,IAAA,CAAA,QAAA,CAAAC,CAAAA,CAER,GAAI,CAACD,CAAAA,EAAU,CAACA,CAAAA,CAAO,UAAA,CAAW,SAAS,CAAA,CACzC,MAAM,IAAI,KAAA,CAAM,4CAA4C,CAEhE,CAEA,MAAM,KAAKJ,CAAAA,CAA6B,CACtC,GAAI,CACF,IAAMM,EAAW,MAAM,KAAA,CAAM,IAAA,CAAK,QAAA,CAAU,CAC1C,MAAA,CAAQ,OACR,OAAA,CAAS,CACP,eAAgB,kBAAA,CAChB,aAAA,CAAe,UAAU,IAAA,CAAK,MAAM,EACtC,CAAA,CACA,IAAA,CAAM,KAAK,SAAA,CAAUN,CAAK,CAC5B,CAAC,CAAA,CAED,GAAI,CAACM,CAAAA,CAAS,EAAA,CACZ,MAAM,IAAI,KAAA,CAAM,QAAQA,CAAAA,CAAS,MAAM,KAAKA,CAAAA,CAAS,UAAU,EAAE,CAErE,CAAA,MAASC,EAAO,CAEd,OAAA,CAAQ,MAAM,kCAAA,CAAoCA,CAAK,EACzD,CACF,CACF,EC9BO,IAAMC,CAAAA,CAAN,KAAoD,CACzD,MAAM,KAAKR,CAAAA,CAA6B,CACtC,IAAMS,CAAAA,CAAS,CACb,OAAQ,oCAAA,CACR,KAAA,CAAO,iCACT,CAAA,CAEA,OAAA,CAAQ,MAAM,CAAA,uBAAA,EAAmBT,CAAAA,CAAM,SAAS,CAAA,EAAA,EAAKA,CAAAA,CAAM,SAAS,CAAA,CAAA,CAAA,CAAKS,CAAAA,CAAO,MAAM,CAAA,CAElFT,CAAAA,CAAM,UAAA,EAAc,OAAO,IAAA,CAAKA,CAAAA,CAAM,UAAU,CAAA,CAAE,MAAA,CAAS,GAC7D,OAAA,CAAQ,GAAA,CAAI,gBAAiBS,CAAAA,CAAO,KAAA,CAAOT,EAAM,UAAU,CAAA,CAG7D,QAAQ,GAAA,CAAI,SAAA,CAAWS,EAAO,KAAA,CAAOT,CAAAA,CAAM,OAAA,CAAQ,MAAA,EAAU,WAAW,CAAA,CAExE,QAAQ,GAAA,CAAI,YAAA,CAAcS,EAAO,KAAA,CAAOT,CAAAA,CAAM,QAAQ,SAAS,CAAA,CAE/D,QAAQ,QAAA,GACV,CACF,ECpBO,IAAMU,EAAN,KAAiD,CACtD,MAAM,IAAA,CAAKC,CAAAA,CAA8B,CAEzC,CACF,ECDA,IAAMC,EAAqB,CACzB,SAAA,CAAW,YACX,KAAA,CAAO,OAAA,CACP,eAAgB,gBAAA,CAChB,QAAA,CAAU,UACZ,CAAA,CAIMC,CAAAA,CAAoD,CACxD,CAACD,CAAAA,CAAmB,KAAK,EAAG,EAAA,CAAK,IACjC,CAACA,CAAAA,CAAmB,cAAc,EAAG,EAAA,CAAK,EAAA,CAAK,IAC/C,CAACA,CAAAA,CAAmB,SAAS,EAAG,EAAA,CAAK,GAAK,GAAA,CAC1C,CAACA,EAAmB,QAAQ,EAAG,EAAI,EAAA,CAAK,EAAA,CAAK,GAAK,GACpD,CAAA,CAEaE,EAAN,KAA+D,CAGpE,WAAA,CAAYV,CAAAA,CAAgB,CAC1B,IAAA,CAAK,OAASA,EAChB,CAEA,MAAM,UAAA,CAAWpB,CAAAA,CAAsBC,EAAsC,CAC3E,IAAM8B,EAAa,IAAA,CAAK,UAAA,CAAW/B,EAAcC,CAAU,CAAA,CACrD+B,EAAShD,CAAAA,CAAoB,GAAA,CAA0B+C,CAAU,CAAA,CAEvE,GAAIC,CAAAA,EAAU,CAAC,IAAA,CAAK,SAAA,CAAUA,CAAM,CAAA,CAClC,OAAOA,EAAO,OAAA,CAGhB,GAAI,CACF,IAAMd,CAAAA,CAAS,MAAM,IAAA,CAAK,WAAA,CAAYlB,CAAY,CAAA,CAClD,GAAI,CAACkB,CAAAA,CACH,OAAO,KAAK,cAAA,CACV,CAAE,YAAA,CAAAlB,CAAAA,CAAc,UAAA,CAAAC,CAAW,EAC3B,SAAA,CACA2B,CAAAA,CAAmB,SACrB,CAAA,CAIF,GADoB,KAAK,IAAA,CAAK,CAAA,EAAG5B,CAAY,CAAA,CAAA,EAAIC,CAAU,EAAE,CAAA,CAC3C,GAAA,EAAOiB,EAAO,iBAAA,CAE9B,OAAO,KAAK,cAAA,CACV,CAAE,aAAAlB,CAAAA,CAAc,UAAA,CAAAC,CAAW,CAAA,CAC3B,SAAA,CACA2B,EAAmB,cACrB,CAAA,CAGF,IAAMxB,CAAAA,CAAU,IAAA,CAAK,iBAAiBJ,CAAAA,CAAcC,CAAAA,CAAYiB,CAAM,CAAA,CACtE,OAAO,KAAK,cAAA,CACV,CAAE,aAAAlB,CAAAA,CAAc,UAAA,CAAAC,CAAW,CAAA,CAC3BG,CAAAA,CACAwB,CAAAA,CAAmB,QACrB,CACF,CAAA,KAAQ,CACN,OAAO,IAAA,CAAK,eAAe,CAAE,YAAA,CAAA5B,EAAc,UAAA,CAAAC,CAAW,EAAG,SAAA,CAAW2B,CAAAA,CAAmB,KAAK,CAC9F,CACF,CAEQ,gBAAA,CACN5B,CAAAA,CACAC,CAAAA,CACAiB,CAAAA,CACS,CAET,OADoB,KAAK,IAAA,CAAK,CAAA,EAAGlB,CAAY,CAAA,CAAA,EAAIC,CAAU,UAAU,CAAA,CAChD,GAAA,CAAMiB,EAAO,iBAAA,CAAoB,SAAA,CAAY,SACpE,CAEQ,cAAA,CACNe,EACA7B,CAAAA,CACA8B,CAAAA,CACS,CACT,GAAM,CAAE,YAAA,CAAAlC,CAAAA,CAAc,UAAA,CAAAC,CAAW,EAAIgC,CAAAA,CAC/BE,CAAAA,CAAmC,CACvC,YAAA,CAAAnC,CAAAA,CACA,QAAAI,CAAAA,CACA,UAAA,CAAY,KAAK,GAAA,EAAI,CACrB,UAAW,IAAA,CAAK,GAAA,GAAQyB,CAAAA,CAAgBK,CAAM,CAChD,CAAA,CAEMH,CAAAA,CAAa,KAAK,UAAA,CAAW/B,CAAAA,CAAcC,CAAU,CAAA,CAC3D,OAAAjB,EAAoB,GAAA,CAAI+C,CAAAA,CAAYI,CAAU,CAAA,CACvC/B,CACT,CAEQ,SAAA,CAAU+B,CAAAA,CAA2C,CAC3D,OAAKA,CAAAA,CAAW,UACT,IAAA,CAAK,GAAA,IAASA,CAAAA,CAAW,SAAA,CADE,KAEpC,CAEA,MAAc,WAAA,CAAYnC,EAAwD,CAChF,GAAI,CACF,IAAMsB,CAAAA,CAAW,MAAM,KAAA,CAAM,CAAA,mCAAA,EAAkCtB,CAAY,CAAA,CAAA,CAAI,CAC7E,QAAS,CACP,aAAA,CAAe,UAAU,IAAA,CAAK,MAAM,EACtC,CACF,CAAC,CAAA,CAED,OAAKsB,CAAAA,CAAS,EAAA,CAIPA,EAAS,IAAA,EAAK,CAHZ,IAIX,CAAA,KAAQ,CACN,OAAO,IACT,CACF,CAEQ,IAAA,CAAK1C,CAAAA,CAAqB,CAChC,IAAIC,CAAAA,CAAO,EACX,IAAA,IAASC,CAAAA,CAAI,EAAGA,CAAAA,CAAIF,CAAAA,CAAI,MAAA,CAAQE,CAAAA,EAAAA,CAAK,CACnC,IAAMC,EAAOH,CAAAA,CAAI,UAAA,CAAWE,CAAC,CAAA,CAC7BD,CAAAA,CAAAA,CAAQA,GAAQ,CAAA,EAAKA,CAAAA,CAAOE,EAC5BF,CAAAA,CAAOA,CAAAA,CAAOA,EAChB,CACA,OAAO,KAAK,GAAA,CAAIA,CAAI,CACtB,CAEQ,UAAA,CAAWmB,EAAsBC,CAAAA,CAA4B,CACnE,OAAO,CAAA,WAAA,EAAcD,CAAY,IAAIC,CAAU,CAAA,CACjD,CACF,EC5HO,IAAMmC,EAAN,KAA6D,CAIlE,YAAYC,CAAAA,CAAa,EAAA,CAAK,CAH9B,IAAA,CAAQ,KAAA,CAAQ,IAAI,GAAA,CAIlB,IAAA,CAAK,UAAA,CAAaA,EACpB,CAEA,MAAM,WAAWrC,CAAAA,CAAsBC,CAAAA,CAAsC,CAC3E,IAAMqC,CAAAA,CAAW,GAAGtC,CAAY,CAAA,CAAA,EAAIC,CAAU,CAAA,CAAA,CAExCsC,CAAAA,CAAS,KAAK,KAAA,CAAM,GAAA,CAAID,CAAQ,CAAA,CACtC,GAAIC,EACF,OAAOA,CAAAA,CAIT,IAAMnC,CAAAA,CADO,IAAA,CAAK,QAAA,CAAS,GAAGJ,CAAY,CAAA,CAAA,EAAIC,CAAU,CAAA,CAAE,CAAA,CAClC,IAAO,GAAA,CAAM,IAAA,CAAK,WAAa,SAAA,CAAY,SAAA,CAEnE,YAAK,KAAA,CAAM,GAAA,CAAIqC,EAAUlC,CAAO,CAAA,CACzBA,CACT,CAEQ,QAAA,CAASxB,CAAAA,CAAqB,CACpC,IAAIC,CAAAA,CAAO,EACX,IAAA,IAASC,CAAAA,CAAI,EAAGA,CAAAA,CAAIF,CAAAA,CAAI,OAAQE,CAAAA,EAAAA,CAAK,CACnC,IAAMC,CAAAA,CAAOH,CAAAA,CAAI,WAAWE,CAAC,CAAA,CAC7BD,GAAQA,CAAAA,EAAQ,CAAA,EAAKA,EAAOE,CAAAA,CAC5BF,CAAAA,CAAOA,CAAAA,CAAOA,EAChB,CACA,OAAO,KAAK,GAAA,CAAIA,CAAI,CACtB,CACF,ECtCO,SAAS2D,CAAAA,EAA8B,CAC5C,IAAM/C,CAAAA,CAAY,IAAA,CAAK,KAAI,CAAE,QAAA,CAAS,EAAE,CAAA,CAClCC,CAAAA,CAAS,KAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAA,CAAU,EAAG,CAAC,CAAA,CAExD,OAAO,CAAA,KAAA,EAAQD,CAAS,IAAIC,CAAM,CAAA,CACpC,CCwBO,SAAS+C,CAAAA,CACdC,EAMU,CACV,IAAMC,EAAW,IAAI1B,CAAAA,CAErB,OAAI,OAAOyB,CAAAA,EAAkB,QAAA,CAC3BC,CAAAA,CAAS,IAAA,CAAK,CACZ,cAAe,IAAIxB,CAAAA,CAAsBuB,CAAa,CAAA,CACtD,kBAAA,CAAoB,IAAIZ,CAAAA,CAA2BY,CAAa,CAClE,CAAC,CAAA,CAEDC,EAAS,IAAA,CAAK,CACZ,cAAeD,CAAAA,CAAc,aAAA,CAC7B,mBAAoBA,CAAAA,CAAc,kBACpC,CAAC,CAAA,CAGIC,CACT","file":"index.mjs","sourcesContent":["type StorageType = 'localStorage' | 'sessionStorage';\n\nexport class BrowserStorage {\n private prefix: string;\n private storage: Storage | null;\n\n constructor(type: StorageType, customPrefix?: string) {\n if (typeof window !== 'undefined') {\n this.storage = type === 'localStorage' ? window.localStorage : window.sessionStorage;\n } else {\n this.storage = null;\n }\n\n if (customPrefix) {\n this.prefix = customPrefix;\n } else {\n const origin = typeof window !== 'undefined' ? window.location.origin : 'default';\n const originHash = this.hashString(origin).toString(36).slice(-4);\n this.prefix = `datanova.sdk.browser.${originHash}.`;\n }\n }\n\n get<T>(key: string): T | null {\n if (!this.storage) {\n return null;\n }\n\n try {\n const item = this.storage.getItem(this.prefix + key);\n return item ? JSON.parse(item) : null;\n } catch {\n return null;\n }\n }\n\n set<T>(key: string, value: T): void {\n if (!this.storage) {\n return;\n }\n\n try {\n this.storage.setItem(this.prefix + key, JSON.stringify(value));\n } catch {\n // Ignore storage errors\n }\n }\n\n remove(key: string): void {\n if (!this.storage) {\n return;\n }\n\n try {\n this.storage.removeItem(this.prefix + key);\n } catch {\n // Ignore storage errors\n }\n }\n\n private hashString(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n return Math.abs(hash);\n }\n}\n","import { BrowserStorage } from './base-storage';\n\nexport const browserLocalStorage = new BrowserStorage('localStorage');\n","import { BrowserStorage } from './base-storage';\n\nexport const browserSessionStorage = new BrowserStorage('sessionStorage');\n","import { browserLocalStorage } from '../storage/local-storage';\nimport { browserSessionStorage } from '../storage/session-storage';\nimport { BrowserContext, Context } from '../types';\n\nexport class ContextManager {\n private userId?: string;\n private userProperties?: Record<string, unknown>;\n private sessionId: string;\n private fingerprint: string;\n private contextOverrides?: Partial<Context>;\n\n constructor() {\n this.sessionId = this.getOrCreateSessionId();\n this.fingerprint = this.getOrCreateFingerprint();\n }\n\n setUser(userId: string, properties?: Record<string, unknown>): void {\n this.userId = userId;\n this.userProperties = properties;\n }\n\n clearUser(): void {\n this.userId = undefined;\n this.userProperties = undefined;\n }\n\n overrideContext(contextOverrides: Partial<Context>): void {\n this.contextOverrides = contextOverrides;\n }\n\n getContext(): Context {\n const baseContext: Context = {\n userId: this.userId,\n userProperties: this.userProperties,\n sessionId: this.sessionId,\n browser: this.getBrowserContext(),\n library: {\n name: '@datanova/browser',\n version: '0.1.0',\n },\n };\n\n return {\n ...baseContext,\n ...this.contextOverrides,\n };\n }\n\n getIdentifier(): string {\n return this.userId || this.fingerprint || this.sessionId;\n }\n\n private getBrowserContext(): BrowserContext {\n if (typeof window === 'undefined') {\n return {\n url: '',\n title: '',\n referrer: '',\n path: '',\n search: '',\n userAgent: '',\n };\n }\n\n return {\n url: window.location.href,\n title: document.title,\n referrer: document.referrer,\n path: window.location.pathname,\n search: window.location.search,\n userAgent: navigator.userAgent,\n };\n }\n\n private getOrCreateSessionId(): string {\n const key = 'session_id';\n let sessionId = browserSessionStorage.get<string>(key);\n\n if (!sessionId) {\n sessionId = this.generateId('ss');\n browserSessionStorage.set(key, sessionId);\n }\n\n return sessionId;\n }\n\n private getOrCreateFingerprint(): string {\n const key = 'fingerprint';\n let fingerprint = browserLocalStorage.get<string>(key);\n\n if (!fingerprint) {\n fingerprint = this.generateId('fp');\n browserLocalStorage.set(key, fingerprint);\n }\n\n return fingerprint;\n }\n\n private generateId(prefix: string): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 10);\n return `${prefix}-${timestamp}-${random}`;\n }\n}\n","export interface Event {\n eventName: string;\n eventType: EventType;\n properties?: Record<string, unknown>;\n timestamp: string;\n context: Context;\n}\n\nexport const EventType = {\n CLICK: 'click',\n PAGE_VIEW: 'pageView',\n IMPRESSION: 'impression',\n SUBMIT: 'submit',\n CHANGE: 'change',\n} as const;\n\nexport type EventType = (typeof EventType)[keyof typeof EventType];\n\nexport const InternalEventType = {\n SYSTEM: 'system',\n} as const;\n\nexport type InternalEventType = (typeof InternalEventType)[keyof typeof InternalEventType];\n\nexport interface Context {\n userId?: string;\n userProperties?: Record<string, unknown>;\n sessionId: string;\n browser: BrowserContext;\n library: {\n name: string;\n version: string;\n };\n}\n\nexport interface BrowserContext {\n url: string;\n title: string;\n referrer: string;\n path: string;\n search: string;\n userAgent: string;\n}\n\nexport interface EventsService {\n send(event: Event): Promise<void>;\n}\n\nexport interface Tracker {\n track(eventName: string, eventType: EventType, properties?: Record<string, unknown>): void;\n}\n\nexport interface ExperimentConfig {\n id: number;\n trafficAllocation: number;\n variantAllocation: number;\n}\n\nexport type Variant = 'control' | 'variant';\n\nexport interface ExperimentAssignment {\n experimentId: number;\n variant: Variant;\n assignedAt: number;\n expiresAt?: number;\n}\n\nexport interface ExperimentsService {\n getVariant(experimentId: number, identifier: string): Promise<Variant>;\n}\n\nexport interface SDKConfig {\n eventsService?: EventsService;\n experimentsService?: ExperimentsService;\n /** @internal - Context overrides */\n context?: Partial<Context>;\n}\n","import { browserLocalStorage } from '../storage/local-storage';\nimport { EventType, ExperimentsService, InternalEventType, Tracker, Variant } from '../types';\n\ninterface AssignmentRecord {\n variant: string;\n assignedAt: number;\n}\n\nexport class ExperimentManager {\n constructor(\n private experimentsService: ExperimentsService,\n private tracker: Tracker | undefined\n ) {}\n\n async getVariant(experimentId: number, identifier: string): Promise<Variant> {\n const assignmentKey = this.getAssignmentKey(experimentId, identifier);\n\n const previousAssignment = browserLocalStorage.get<AssignmentRecord>(assignmentKey);\n\n const variant = await this.experimentsService.getVariant(experimentId, identifier);\n\n const shouldTrackAssignment = !previousAssignment || previousAssignment.variant !== variant;\n\n if (shouldTrackAssignment) {\n const assignmentRecord: AssignmentRecord = {\n variant,\n assignedAt: Date.now(),\n };\n browserLocalStorage.set(assignmentKey, assignmentRecord);\n\n this.tracker?.track('$variant_assigned', InternalEventType.SYSTEM as EventType, {\n experiment_id: experimentId,\n variant,\n });\n }\n\n return variant;\n }\n\n private getAssignmentKey(experimentId: number, identifier: string): string {\n return `assignment_${experimentId}_${identifier}`;\n }\n}\n","export function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as unknown as T;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => deepClone(item)) as unknown as T;\n }\n\n if (obj instanceof Set) {\n return new Set(Array.from(obj).map((item) => deepClone(item))) as unknown as T;\n }\n\n if (obj instanceof Map) {\n const clonedMap = new Map();\n obj.forEach((value, key) => {\n clonedMap.set(deepClone(key), deepClone(value));\n });\n\n return clonedMap as unknown as T;\n }\n\n const cloned = {} as T;\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n cloned[key] = deepClone(obj[key]);\n }\n }\n\n return cloned;\n}\n","import { Event, EventType, EventsService, Tracker as ITracker } from '../types';\nimport { deepClone } from '../utils';\nimport { ContextManager } from './context';\n\n/**\n * Internal tracker implementation that automatically injects context\n */\nexport class Tracker implements ITracker {\n constructor(\n private eventsService: EventsService,\n private contextManager: ContextManager\n ) {}\n\n track(eventName: string, eventType: EventType, properties?: Record<string, unknown>): void {\n const eventContext = this.contextManager.getContext();\n\n const event: Event = {\n eventName,\n eventType,\n properties: properties ? deepClone(properties) : undefined,\n timestamp: new Date().toISOString(),\n context: eventContext,\n };\n\n this.eventsService.send(event);\n }\n}\n","import { ContextManager } from './core/context';\nimport { ExperimentManager } from './core/experiment-manager';\nimport { Tracker as ContextAwareTracker } from './core/tracker';\nimport { EventType, SDKConfig, Variant } from './types';\n\nexport class Datanova {\n private initialized = false;\n private tracker?: ContextAwareTracker;\n private readonly contextManager = new ContextManager();\n private experimentManager?: ExperimentManager;\n\n init(config: SDKConfig): void {\n if (this.initialized) {\n return;\n }\n\n if (!config.eventsService && !config.experimentsService) {\n throw new Error(\n \"At least one of 'eventsService' or 'experimentsService' must be provided to initialize the SDK\"\n );\n }\n\n if (config.context) {\n this.contextManager.overrideContext(config.context);\n }\n\n if (config.eventsService) {\n this.tracker = new ContextAwareTracker(config.eventsService, this.contextManager);\n }\n\n if (config.experimentsService) {\n this.experimentManager = new ExperimentManager(config.experimentsService, this.tracker);\n }\n\n this.initialized = true;\n }\n\n identify = (userId: string, properties?: Record<string, unknown>): void => {\n this.assertInitialized();\n this.contextManager.setUser(userId, properties);\n };\n\n reset = (): void => {\n this.assertInitialized();\n this.contextManager.clearUser();\n };\n\n track = (eventName: string, eventType: EventType, properties?: Record<string, unknown>): void => {\n this.assertInitialized();\n this.assertTracker();\n this.tracker!.track(eventName, eventType, properties);\n };\n\n trackClick = (eventName: string, properties?: Record<string, unknown>): void => {\n this.assertInitialized();\n this.assertTracker();\n this.tracker!.track(eventName, EventType.CLICK, properties);\n };\n\n trackPageView = (eventName: string, properties?: Record<string, unknown>): void => {\n this.assertInitialized();\n this.assertTracker();\n this.tracker!.track(eventName, EventType.PAGE_VIEW, properties);\n };\n\n trackImpression = (eventName: string, properties?: Record<string, unknown>): void => {\n this.assertInitialized();\n this.assertTracker();\n this.tracker!.track(eventName, EventType.IMPRESSION, properties);\n };\n\n trackSubmit = (eventName: string, properties?: Record<string, unknown>): void => {\n this.assertInitialized();\n this.assertTracker();\n this.tracker!.track(eventName, EventType.SUBMIT, properties);\n };\n\n trackChange = (eventName: string, properties?: Record<string, unknown>): void => {\n this.assertInitialized();\n this.assertTracker();\n this.tracker!.track(eventName, EventType.CHANGE, properties);\n };\n\n getVariant = async (experimentId: number): Promise<Variant> => {\n this.assertInitialized();\n this.assertExperimentManager();\n\n const identifier = this.contextManager.getIdentifier();\n return this.experimentManager!.getVariant(experimentId, identifier);\n };\n\n private assertInitialized(): void {\n if (!this.initialized) {\n throw new Error('Client not initialized. Call init() first.');\n }\n }\n\n private assertTracker(): void {\n if (!this.tracker) {\n throw new Error(\n 'No events service configured. Initialize the client with an events service to use tracking methods.'\n );\n }\n }\n\n private assertExperimentManager(): void {\n if (!this.experimentManager) {\n throw new Error(\n 'No experiments service configured. Initialize the client with an experiments service to use experiment methods.'\n );\n }\n }\n}\n","import { Event, EventsService } from '../../types';\n\ndeclare const __API_BASE_URL__: string;\n\nexport class DatanovaEventsService implements EventsService {\n constructor(\n private sdkKey: string,\n private endpoint: string = `${__API_BASE_URL__}/api/v1/e`\n ) {\n if (!sdkKey || !sdkKey.startsWith('dn_sdk_')) {\n throw new Error(\"Invalid API key. Must start with 'dn_sdk_'\");\n }\n }\n\n async send(event: Event): Promise<void> {\n try {\n const response = await fetch(this.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.sdkKey}`,\n },\n body: JSON.stringify(event),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n } catch (error) {\n // Silently fail - tracking should not break the app\n console.error('[Datanova] Failed to send event:', error);\n }\n }\n}\n","/* eslint-disable no-console */\nimport { Event, EventsService } from '../../types';\n\nexport class ConsoleEventsService implements EventsService {\n async send(event: Event): Promise<void> {\n const styles = {\n header: 'color: #0080ff; font-weight: bold;',\n label: 'color: #666; font-weight: bold;',\n };\n\n console.group(`%c📊 [Datanova] ${event.eventName} (${event.eventType})`, styles.header);\n\n if (event.properties && Object.keys(event.properties).length > 0) {\n console.log('%cProperties:', styles.label, event.properties);\n }\n\n console.log('%cUser:', styles.label, event.context.userId || 'Anonymous');\n\n console.log('%cSession:', styles.label, event.context.sessionId);\n\n console.groupEnd();\n }\n}\n","import { Event, EventsService } from '../../types';\n\nexport class NoopEventsService implements EventsService {\n async send(_event: Event): Promise<void> {\n // No-op implementation - does nothing\n }\n}\n","import { browserLocalStorage } from '../../storage/local-storage';\nimport { ExperimentAssignment, ExperimentConfig, ExperimentsService, Variant } from '../../types';\n\ndeclare const __API_BASE_URL__: string;\n\nconst ASSIGNMENT_REASONS = {\n NOT_FOUND: 'not-found',\n ERROR: 'error',\n NOT_IN_TRAFFIC: 'not-in-traffic',\n ASSIGNED: 'assigned',\n} as const;\n\ntype AssignmentReason = (typeof ASSIGNMENT_REASONS)[keyof typeof ASSIGNMENT_REASONS];\n\nconst ASSIGNMENT_TTLS: Record<AssignmentReason, number> = {\n [ASSIGNMENT_REASONS.ERROR]: 60 * 1000, // 1 minute\n [ASSIGNMENT_REASONS.NOT_IN_TRAFFIC]: 60 * 60 * 1000, // 1 hour\n [ASSIGNMENT_REASONS.NOT_FOUND]: 15 * 60 * 1000, // 15 minutes\n [ASSIGNMENT_REASONS.ASSIGNED]: 7 * 24 * 60 * 60 * 1000, // 7 days\n};\n\nexport class DatanovaExperimentsService implements ExperimentsService {\n private sdkKey: string;\n\n constructor(sdkKey: string) {\n this.sdkKey = sdkKey;\n }\n\n async getVariant(experimentId: number, identifier: string): Promise<Variant> {\n const storageKey = this.storageKey(experimentId, identifier);\n const stored = browserLocalStorage.get<ExperimentAssignment>(storageKey);\n\n if (stored && !this.isExpired(stored)) {\n return stored.variant as Variant;\n }\n\n try {\n const config = await this.fetchConfig(experimentId);\n if (!config) {\n return this.saveAssignment(\n { experimentId, identifier },\n 'control',\n ASSIGNMENT_REASONS.NOT_FOUND\n );\n }\n\n const trafficHash = this.hash(`${experimentId}:${identifier}`);\n if (trafficHash % 100 >= config.trafficAllocation) {\n // Not in traffic\n return this.saveAssignment(\n { experimentId, identifier },\n 'control',\n ASSIGNMENT_REASONS.NOT_IN_TRAFFIC\n );\n }\n\n const variant = this.determineVariant(experimentId, identifier, config);\n return this.saveAssignment(\n { experimentId, identifier },\n variant,\n ASSIGNMENT_REASONS.ASSIGNED\n );\n } catch {\n return this.saveAssignment({ experimentId, identifier }, 'control', ASSIGNMENT_REASONS.ERROR);\n }\n }\n\n private determineVariant(\n experimentId: number,\n identifier: string,\n config: ExperimentConfig\n ): Variant {\n const variantHash = this.hash(`${experimentId}:${identifier}:variant`);\n return variantHash % 100 < config.variantAllocation ? 'variant' : 'control';\n }\n\n private saveAssignment(\n request: { experimentId: number; identifier: string },\n variant: Variant,\n reason: AssignmentReason\n ): Variant {\n const { experimentId, identifier } = request;\n const assignment: ExperimentAssignment = {\n experimentId,\n variant,\n assignedAt: Date.now(),\n expiresAt: Date.now() + ASSIGNMENT_TTLS[reason],\n };\n\n const storageKey = this.storageKey(experimentId, identifier);\n browserLocalStorage.set(storageKey, assignment);\n return variant;\n }\n\n private isExpired(assignment: ExperimentAssignment): boolean {\n if (!assignment.expiresAt) return false;\n return Date.now() >= assignment.expiresAt;\n }\n\n private async fetchConfig(experimentId: number): Promise<ExperimentConfig | null> {\n try {\n const response = await fetch(`${__API_BASE_URL__}/api/v1/exp/${experimentId}`, {\n headers: {\n Authorization: `Bearer ${this.sdkKey}`,\n },\n });\n\n if (!response.ok) {\n return null;\n }\n\n return response.json();\n } catch {\n return null;\n }\n }\n\n private hash(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n return Math.abs(hash);\n }\n\n private storageKey(experimentId: number, identifier: string): string {\n return `experiment_${experimentId}_${identifier}`;\n }\n}\n","import { ExperimentsService, Variant } from '../../types';\n\n/**\n * Random experiments service that assigns variants based on a hash\n * Useful for client-side experimentation without server calls\n */\nexport class RandomExperimentsService implements ExperimentsService {\n private cache = new Map<string, Variant>();\n private splitRatio: number;\n\n constructor(splitRatio = 0.5) {\n this.splitRatio = splitRatio;\n }\n\n async getVariant(experimentId: number, identifier: string): Promise<Variant> {\n const cacheKey = `${experimentId}:${identifier}`;\n\n const cached = this.cache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n const hash = this.hashCode(`${experimentId}:${identifier}`);\n const variant = (hash % 100) / 100 < this.splitRatio ? 'variant' : 'control';\n\n this.cache.set(cacheKey, variant);\n return variant;\n }\n\n private hashCode(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n return Math.abs(hash);\n }\n}\n","export function generateAnonymousId(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 8);\n\n return `anon-${timestamp}-${random}`;\n}\n\nexport function generateFingerprint(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 10);\n\n return `fp-${timestamp}-${random}`;\n}\n","import { Datanova } from './datanova';\nimport { DatanovaEventsService } from './services/events/datanova';\nimport { DatanovaExperimentsService } from './services/experiments/datanova';\nimport { EventsService, ExperimentsService } from './types';\n\nexport function createDatanova(sdkKey: string): Datanova;\nexport function createDatanova(config: {\n eventsService?: EventsService;\n experimentsService?: ExperimentsService;\n}): Datanova;\n\n/**\n * Create and initialize a Datanova instance\n * @param keyOrServices - Either an SDK key string or configuration object\n * @returns Initialized Datanova instance\n * @example\n * ```javascript\n * import { createDatanova } from '@datanova/browser';\n *\n * // Simple usage with API key\n * const datanova = createDatanova(\"YOUR_SDK_KEY\");\n *\n * // Advanced usage with custom services\n * const datanova = createDatanova({\n * eventsService: new ConsoleEventsService(),\n * experimentsService: new DatanovaExperimentsService(\"YOUR_SDK_KEY\")\n * });\n * ```\n */\nexport function createDatanova(\n keyOrServices:\n | string\n | {\n eventsService?: EventsService;\n experimentsService?: ExperimentsService;\n }\n): Datanova {\n const datanova = new Datanova();\n\n if (typeof keyOrServices === 'string') {\n datanova.init({\n eventsService: new DatanovaEventsService(keyOrServices),\n experimentsService: new DatanovaExperimentsService(keyOrServices),\n });\n } else {\n datanova.init({\n eventsService: keyOrServices.eventsService,\n experimentsService: keyOrServices.experimentsService,\n });\n }\n\n return datanova;\n}\n"]}