@fogalytics/sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fog.esm.js +1 -0
- package/dist/fog.iife.js +1 -0
- package/dist/hash.d.ts +10 -0
- package/dist/index.d.ts +20 -0
- package/dist/types.d.ts +26 -0
- package/package.json +20 -0
package/dist/fog.esm.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var u="",p="",c={},n="pending",d=null,l=null;function I(){return n}function w(){u="",p="",c={},n="pending",l=null,d&&(d(),d=null)}function y(){if(typeof window>"u")return()=>{};let e=window;e.dataLayer||(e.dataLayer=[]);let t=e.dataLayer,o=t.push.bind(t);return t.push=(...a)=>{for(let s of a)if(s.event==="purchase"){let r=s.ecommerce,i=typeof r?.value=="number"?r.value:void 0;for(let f of Object.keys(c))v("conversion",{experimentId:f,value:i})}return o(...a)},()=>{t.push=o}}function m(e,t){typeof navigator<"u"&&navigator.sendBeacon?navigator.sendBeacon(e,new Blob([t],{type:"application/json"})):fetch(e,{method:"POST",body:t,headers:{"Content-Type":"application/json"}}).catch(()=>{})}async function b(e){u=e.endpoint,n="pending";let t=e.timeout??5e3,o=new AbortController,a=setTimeout(()=>o.abort(),t),s=e.visitorId?`${e.endpoint}/init?visitorId=${encodeURIComponent(e.visitorId)}`:`${e.endpoint}/init`;try{let r=await fetch(s,{signal:o.signal});if(clearTimeout(a),!r.ok)return n="error",{status:"error",error:`HTTP ${r.status}`};let i=await r.json();return p=i.visitorId,c=i.assignments,n=Object.keys(i.assignments).length===0?"excluded":"ready",e.autoRevenue&&n==="ready"&&(d=y()),{status:n}}catch(r){clearTimeout(a);let i=r instanceof Error&&r.name==="AbortError";return n="error",{status:"error",error:i?"timeout":String(r)}}}function g(e){return n!=="ready"?-1:c[e]??-1}function h(e){return g(e)===1}function v(e,t){n==="ready"&&m(u+"/track",JSON.stringify({visitorId:p,experimentId:t.experimentId,event:e,eventName:t.eventName,value:t.value}))}function k(e){let t=l??(n==="ready"?u:null);if(!t)return;let o=e??(typeof window<"u"?window.location.pathname:"/");m(t+"/track",JSON.stringify({event:"pageview",experimentId:"",eventName:o}))}export{I as getStatus,g as getVariant,b as init,h as isEnabled,k as page,w as reset,v as track};
|
package/dist/fog.iife.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var Fog=(()=>{var p=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var k=(e,t)=>{for(var n in t)p(e,n,{get:t[n],enumerable:!0})},L=(e,t,n,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of b(t))!h.call(e,o)&&o!==n&&p(e,o,{get:()=>t[o],enumerable:!(a=w(t,o))||a.enumerable});return e};var S=e=>L(p({},"__esModule",{value:!0}),e);var O={};k(O,{getStatus:()=>x,getVariant:()=>y,init:()=>R,isEnabled:()=>D,page:()=>v,reset:()=>_,track:()=>g});var u="",l="",c={},r="pending",d=null,m=null;function x(){return r}function _(){u="",l="",c={},r="pending",m=null,d&&(d(),d=null)}function T(){if(typeof window>"u")return()=>{};let e=window;e.dataLayer||(e.dataLayer=[]);let t=e.dataLayer,n=t.push.bind(t);return t.push=(...a)=>{for(let o of a)if(o.event==="purchase"){let i=o.ecommerce,s=typeof i?.value=="number"?i.value:void 0;for(let I of Object.keys(c))g("conversion",{experimentId:I,value:s})}return n(...a)},()=>{t.push=n}}function f(e,t){typeof navigator<"u"&&navigator.sendBeacon?navigator.sendBeacon(e,new Blob([t],{type:"application/json"})):fetch(e,{method:"POST",body:t,headers:{"Content-Type":"application/json"}}).catch(()=>{})}async function R(e){u=e.endpoint,r="pending";let t=e.timeout??5e3,n=new AbortController,a=setTimeout(()=>n.abort(),t),o=e.visitorId?`${e.endpoint}/init?visitorId=${encodeURIComponent(e.visitorId)}`:`${e.endpoint}/init`;try{let i=await fetch(o,{signal:n.signal});if(clearTimeout(a),!i.ok)return r="error",{status:"error",error:`HTTP ${i.status}`};let s=await i.json();return l=s.visitorId,c=s.assignments,r=Object.keys(s.assignments).length===0?"excluded":"ready",e.autoRevenue&&r==="ready"&&(d=T()),{status:r}}catch(i){clearTimeout(a);let s=i instanceof Error&&i.name==="AbortError";return r="error",{status:"error",error:s?"timeout":String(i)}}}function y(e){return r!=="ready"?-1:c[e]??-1}function D(e){return y(e)===1}function g(e,t){r==="ready"&&f(u+"/track",JSON.stringify({visitorId:l,experimentId:t.experimentId,event:e,eventName:t.eventName,value:t.value}))}function v(e){let t=m??(r==="ready"?u:null);if(!t)return;let n=e??(typeof window<"u"?window.location.pathname:"/");f(t+"/track",JSON.stringify({event:"pageview",experimentId:"",eventName:n}))}if(typeof document<"u"){let e=document.currentScript;if(e?.src){let t=e.src;m=t.endsWith("/t.js")?t.slice(0,-5):t.replace(/\/[^/]*$/,"");let n=()=>v(window.location.pathname+window.location.search);document.readyState==="loading"?document.addEventListener("DOMContentLoaded",n,{once:!0}):n()}}return S(O);})();
|
package/dist/hash.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FNV-1a hash - same algorithm used by GrowthBook for experiment bucketing.
|
|
3
|
+
* Returns a float in [0, 1) for traffic allocation.
|
|
4
|
+
*/
|
|
5
|
+
export declare function fnv1a(str: string): number;
|
|
6
|
+
/** Returns the variant index for a visitor in an experiment, or -1 if excluded by traffic.
|
|
7
|
+
* type "flag": threshold check only (ramp-stable - visitors on at 10% stay on at 50%)
|
|
8
|
+
* type "experiment": rescale within traffic window to distribute across variants (default)
|
|
9
|
+
*/
|
|
10
|
+
export declare function bucket(visitorId: string, experimentId: string, variantCount: number, trafficPercent: number, type?: "experiment" | "flag"): number;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type { FogConfig, InitResponse, TrackOptions, SdkStatus, InitResult } from "./types.js";
|
|
2
|
+
import type { FogConfig, TrackOptions, InitResult, SdkStatus } from "./types.js";
|
|
3
|
+
/** FEAT-2: Current SDK lifecycle status */
|
|
4
|
+
export declare function getStatus(): SdkStatus;
|
|
5
|
+
/** FEAT-6: Clear all module-level state. Required for SSR and test environments. */
|
|
6
|
+
export declare function reset(): void;
|
|
7
|
+
/** FEAT-1: init with configurable timeout (default 5s). Never throws - resolves with error status on failure. */
|
|
8
|
+
export declare function init(config: FogConfig): Promise<InitResult>;
|
|
9
|
+
/** Returns variant index, or -1 if not assigned (not initialized, excluded, or error) */
|
|
10
|
+
export declare function getVariant(experimentId: string): number;
|
|
11
|
+
/** Feature flag convenience API - returns true if variant is 1 (enabled) */
|
|
12
|
+
export declare function isEnabled(experimentId: string): boolean;
|
|
13
|
+
export declare function track(event: "impression" | "conversion", options: TrackOptions): void;
|
|
14
|
+
/**
|
|
15
|
+
* Manually track a pageview - for SPA route changes.
|
|
16
|
+
* In IIFE/script-tag mode: works immediately (no init() needed).
|
|
17
|
+
* In npm mode: works after init() resolves.
|
|
18
|
+
* @param path - URL path to record. Defaults to window.location.pathname.
|
|
19
|
+
*/
|
|
20
|
+
export declare function page(path?: string): void;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface FogConfig {
|
|
2
|
+
endpoint: string;
|
|
3
|
+
visitorId?: string;
|
|
4
|
+
/** Fetch timeout in ms. Defaults to 5000. On timeout, SDK resolves with empty config. */
|
|
5
|
+
timeout?: number;
|
|
6
|
+
/**
|
|
7
|
+
* When true, intercepts window.dataLayer.push to detect GA4 `purchase` events
|
|
8
|
+
* and auto-fire conversion tracks for all active experiments.
|
|
9
|
+
*/
|
|
10
|
+
autoRevenue?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export type SdkStatus = "pending" | "ready" | "excluded" | "error";
|
|
13
|
+
export interface InitResult {
|
|
14
|
+
status: "ready" | "excluded" | "error";
|
|
15
|
+
/** Present when status is 'error' */
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface InitResponse {
|
|
19
|
+
visitorId: string;
|
|
20
|
+
assignments: Record<string, number>;
|
|
21
|
+
}
|
|
22
|
+
export interface TrackOptions {
|
|
23
|
+
experimentId: string;
|
|
24
|
+
eventName?: string;
|
|
25
|
+
value?: number;
|
|
26
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fogalytics/sdk",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/fog.esm.js",
|
|
6
|
+
"browser": "dist/fog.iife.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": ["dist"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "node build.mjs",
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"prepublishOnly": "npm run build && npm run typecheck"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"esbuild": "^0.27.0",
|
|
17
|
+
"typescript": "^5.7.0",
|
|
18
|
+
"vitest": "^4.0.0"
|
|
19
|
+
}
|
|
20
|
+
}
|