@gradual-so/sdk 0.8.7 → 0.8.8
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/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';function I(n){let e=0;for(let t=0;t<n.length;t++){let a=n.charCodeAt(t);e=(e<<5)-e+a,e|=0;}return Math.abs(e)}function g(n,e,t,a){a.add(`${t.bucketContextKind}.${t.bucketAttributeKey}`);let i=e[t.bucketContextKind]?.[t.bucketAttributeKey],o=t.seed??"",r=`${n}:${o}:${String(i??"anonymous")}`;return I(r)%1e5}function m(n,e){if(!(n.schedule&&n.startedAt))return {variations:n.variations,stepIndex:-1};let t=new Date(n.startedAt).getTime(),i=(e.getTime()-t)/6e4;if(i<0)return {variations:n.schedule[0]?.variations??n.variations,stepIndex:0};let o=0;for(let s=0;s<n.schedule.length;s++){let u=n.schedule[s];if(u.durationMinutes===0)return {variations:u.variations,stepIndex:s};if(o+=u.durationMinutes,i<o)return {variations:u.variations,stepIndex:s}}return {variations:n.schedule.at(-1)?.variations??n.variations,stepIndex:n.schedule.length-1}}function b(n,e,t,a){let i=0,o;for(let s of n)if(i+=s.weight,e<i){o=s;break}if(o||(o=n.at(-1)),!o)return;let r=t[o.variationKey];if(r)return {variation:r,variationKey:o.variationKey,matchedWeight:o.weight,bucketValue:e,scheduleStepIndex:a}}function R(n,e,t){let{contextKind:a,attributeKey:i,operator:o,value:r}=n;t.add(`${a}.${i}`);let s=e[a]?.[i];switch(o){case "equals":return s===r;case "not_equals":return s!==r;case "contains":return typeof s=="string"&&typeof r=="string"||Array.isArray(s)?s.includes(r):false;case "not_contains":return typeof s=="string"&&typeof r=="string"||Array.isArray(s)?!s.includes(r):true;case "starts_with":return typeof s=="string"&&typeof r=="string"?s.startsWith(r):false;case "ends_with":return typeof s=="string"&&typeof r=="string"?s.endsWith(r):false;case "greater_than":return typeof s=="number"&&typeof r=="number"?s>r:false;case "less_than":return typeof s=="number"&&typeof r=="number"?s<r:false;case "greater_than_or_equal":return typeof s=="number"&&typeof r=="number"?s>=r:false;case "less_than_or_equal":return typeof s=="number"&&typeof r=="number"?s<=r:false;case "in":return Array.isArray(r)?r.includes(s):false;case "not_in":return Array.isArray(r)?!r.includes(s):true;case "exists":return s!=null;case "not_exists":return s==null;default:return false}}function S(n,e,t){return n.every(a=>R(a,e,t))}function f(n,e,t){for(let a of n)if(t.add(`${a.contextKind}.${a.attributeKey}`),e[a.contextKind]?.[a.attributeKey]===a.attributeValue)return true;return false}function T(n,e,t){return n.excluded?.length&&f(n.excluded,e,t)?false:n.included?.length&&f(n.included,e,t)?true:n.conditions.length===0?false:S(n.conditions,e,t)}function K(n,e,t,a){switch(n.type){case "individual":return n.contextKind&&n.attributeKey&&n.attributeValue!==void 0?(a.add(`${n.contextKind}.${n.attributeKey}`),e[n.contextKind]?.[n.attributeKey]===n.attributeValue):false;case "rule":return n.conditions?S(n.conditions,e,a):false;case "segment":if(n.segmentKey){let i=t[n.segmentKey];if(i)return T(i,e,a)}return false;default:return false}}function w(n,e,t,a,i,o){if(n.rollout){let r=m(n.rollout,o),s=g(e,t,n.rollout,i);return b(r.variations,s,a,r.stepIndex)}if(n.variationKey){let r=a[n.variationKey];if(r)return {variation:r,variationKey:n.variationKey,matchedWeight:1e5,bucketValue:0,scheduleStepIndex:-1}}}function k(n,e,t,a){if(n.defaultRollout){let i=m(n.defaultRollout,a),o=g(n.key,e,n.defaultRollout,t);return b(i.variations,o,n.variations,i.stepIndex)}if(n.defaultVariationKey){let i=n.variations[n.defaultVariationKey];if(i)return {variation:i,variationKey:n.defaultVariationKey,matchedWeight:1e5,bucketValue:0,scheduleStepIndex:-1}}}function V(n){return {type:"rule_match",ruleId:n.id??"",ruleName:n.name}}function y(n){return n.scheduleStepIndex>=0?{type:"gradual_rollout",stepIndex:n.scheduleStepIndex,percentage:n.matchedWeight/1e3,bucket:n.bucketValue}:{type:"percentage_rollout",percentage:n.matchedWeight/1e3,bucket:n.bucketValue}}function v(n,e,t,a){if(!n.enabled)return {value:n.variations[n.offVariationKey]?.value,variationKey:n.offVariationKey,reasons:[{type:"off"}],inputsUsed:[]};let i=a?.now??new Date,o=new Set,r=[...n.targets].sort((u,l)=>u.sortOrder-l.sortOrder);for(let u of r)if(K(u,e,t,o)){let l=w(u,n.key,e,n.variations,o,i);if(l){let d=[V(u)];return u.rollout&&d.push(y(l)),{value:l.variation.value,variationKey:l.variationKey,reasons:d,matchedTargetName:u.name,inputsUsed:[...o]}}}let s=k(n,e,o,i);if(s){let u=[];return n.defaultRollout&&u.push(y(s)),u.push({type:"default"}),{value:s.variation.value,variationKey:s.variationKey,reasons:u,inputsUsed:[...o]}}return {value:void 0,variationKey:void 0,reasons:[{type:"default"}],inputsUsed:[...o]}}var U="0.8.7",C=globalThis,c=C.document,h=class{events=[];timer=null;options;onVisibilityChange=null;constructor(e){this.options=e,this.timer=setInterval(()=>this.flush(),this.options.flushIntervalMs),c?.addEventListener&&(this.onVisibilityChange=()=>{c.visibilityState==="hidden"&&this.flushBeacon();},c.addEventListener("visibilitychange",this.onVisibilityChange));}push(e){this.events.push(e),this.events.length>=this.options.maxBatchSize&&this.flush();}buildPayload(e){return {meta:{...this.options.meta,sdkVersion:U},events:e}}flush(){if(this.events.length===0)return;let e=this.events.splice(0,this.options.maxBatchSize),t=this.buildPayload(e);fetch(`${this.options.baseUrl}/sdk/evaluations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:JSON.stringify(t)}).catch(()=>{});}flushBeacon(){if(this.events.length===0)return;let e=this.events.splice(0,this.options.maxBatchSize),t=this.buildPayload(e);fetch(`${this.options.baseUrl}/sdk/evaluations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:JSON.stringify(t),keepalive:true}).catch(()=>{});}destroy(){this.timer&&(clearInterval(this.timer),this.timer=null),this.onVisibilityChange&&c?.removeEventListener&&c.removeEventListener("visibilitychange",this.onVisibilityChange),this.flush();}};var O="https://worker.gradual.so/api/v1";function _(){try{let n=globalThis,e=n.navigator;if(e&&e.product==="ReactNative")return "react-native";let t=n.window;if(t&&typeof t.document<"u")return "browser";if(n.process?.versions?.node)return "node";if(typeof globalThis<"u")return "edge"}catch{}return "unknown"}var A=_(),E=globalThis.process,D=typeof E?.hrtime?.bigint=="function";function x(){return D?E.hrtime.bigint():typeof performance<"u"?performance.now():Date.now()}function P(n){let e=x();return typeof n=="bigint"&&typeof e=="bigint"?Number((e-n)/1000n):Math.round((e-n)*1e3)}var p=class{apiKey;environment;baseUrl;initPromise;snapshot=null;identifiedContext={};updateListeners=new Set;eventBuffer=null;etag=null;eventsEnabled;eventsFlushIntervalMs;eventsMaxBatchSize;sync;constructor(e){this.apiKey=e.apiKey,this.environment=e.environment,this.baseUrl=e.baseUrl??O,this.eventsEnabled=e.events?.enabled??true,this.eventsFlushIntervalMs=e.events?.flushIntervalMs??3e4,this.eventsMaxBatchSize=e.events?.maxBatchSize??100,this.initPromise=this.init(),this.sync={isEnabled:this.isEnabledSync.bind(this),get:this.getSync.bind(this),evaluate:this.evaluateSync.bind(this),track:this.trackSync.bind(this)};let t=e.polling?.enabled??true,a=e.polling?.intervalMs??1e4;t&&this.initPromise.then(()=>{setInterval(async()=>{try{let i=this.snapshot?.version;if(await this.refresh(),this.snapshot&&this.snapshot.version!==i)for(let o of this.updateListeners)o();}catch(i){console.warn("Gradual: Polling refresh failed",i);}},a);});}async init(){let e=await fetch(`${this.baseUrl}/sdk/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:this.apiKey})});if(!e.ok){let o=await e.json().catch(()=>({}));throw new Error(`Gradual: Failed to initialize - ${o.error??e.statusText}`)}let t=await e.json();if(!t.valid)throw new Error(`Gradual: Invalid API key - ${t.error??"Unknown error"}`);let a=await fetch(`${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,{headers:{Authorization:`Bearer ${this.apiKey}`}});if(!a.ok){let o=await a.json().catch(()=>({}));throw new Error(`Gradual: Failed to fetch snapshot - ${o.error??a.statusText}`)}let i=a.headers.get("ETag");i&&(this.etag=i),this.snapshot=await a.json(),this.eventsEnabled&&this.snapshot.meta&&(this.eventBuffer=new h({baseUrl:this.baseUrl,apiKey:this.apiKey,meta:{projectId:this.snapshot.meta.projectId,organizationId:this.snapshot.meta.organizationId,environmentId:this.snapshot.meta.environmentId,sdkPlatform:A},flushIntervalMs:this.eventsFlushIntervalMs,maxBatchSize:this.eventsMaxBatchSize}));}ensureReady(){if(!this.snapshot)throw new Error("Gradual: SDK not ready. Use await ready() or async methods.");return this.snapshot}mergeContext(e){let t={},a=new Set([...Object.keys(this.identifiedContext),...Object.keys(e?.context??{})]);for(let i of a)t[i]={...this.identifiedContext[i],...e?.context?.[i]};return t}evaluateRaw(e,t){let a=this.ensureReady();if(!a.flags)return {output:null,snapshot:a,durationUs:0};let i=a.flags[e];if(!i)return {output:null,snapshot:a,durationUs:0};let o=x(),r;try{r=v(i,t,a.segments??{});}catch(s){let u=s instanceof Error?s.message:String(s);r={value:void 0,variationKey:void 0,reasons:[{type:"error",detail:u}],errorDetail:u};}return {output:r,snapshot:a,durationUs:P(o)}}buildResult(e,t,a,i){let o=t.reasons.find(r=>r.type==="rule_match");return {schemaVersion:1,key:e,value:t.value,variationKey:t.variationKey,reasons:t.reasons,ruleId:o?.ruleId,flagVersion:a,evaluatedAt:new Date().toISOString(),evaluationDurationUs:i,inputsUsed:t.inputsUsed,traceId:crypto.randomUUID()}}evaluateAndTrack(e,t){let{output:a,snapshot:i,durationUs:o}=this.evaluateRaw(e,t),r=new Date().toISOString(),s=crypto.randomUUID();if(!a){this.trackEvent({key:e,variationKey:void 0,value:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],context:t,flagVersion:i.version,schemaVersion:1,evaluatedAt:r,traceId:s});return}return this.trackEvent({key:e,variationKey:a.variationKey,value:a.value,reasons:a.reasons,context:t,matchedTargetName:a.matchedTargetName,flagVersion:i.version,errorDetail:a.errorDetail,evaluationDurationUs:o,schemaVersion:1,evaluatedAt:r,inputsUsed:a.inputsUsed,traceId:s}),a.value}trackEvent(e){if(!this.eventBuffer)return;let{context:t}=e,a=Object.keys(t),i={};for(let r of a)i[r]=Object.keys(t[r]??{});let o=a.length===0||a.every(r=>Object.keys(t[r]??{}).length===0);this.eventBuffer.push({schemaVersion:e.schemaVersion??1,key:e.key,variationKey:e.variationKey,value:e.value,reasons:e.reasons,evaluatedAt:e.evaluatedAt??new Date().toISOString(),ruleId:e.ruleId,flagVersion:e.flagVersion??0,policyVersion:e.policyVersion,inputsUsed:e.inputsUsed,traceId:e.traceId,contextKinds:a,contextKeys:i,timestamp:Date.now(),matchedTargetName:e.matchedTargetName,errorDetail:e.errorDetail,evaluationDurationUs:e.evaluationDurationUs,isAnonymous:o});}async ready(){await this.initPromise;}isReady(){return this.snapshot!==null}async isEnabled(e,t){await this.initPromise;let a=this.evaluateAndTrack(e,this.mergeContext(t));return typeof a=="boolean"?a:false}async get(e,t){await this.initPromise;let a=this.evaluateAndTrack(e,this.mergeContext(t));return a??t.fallback}async evaluate(e,t){await this.initPromise;let a=this.mergeContext(t),{output:i,snapshot:o,durationUs:r}=this.evaluateRaw(e,a);if(!i){let u=crypto.randomUUID(),l=new Date().toISOString(),d={schemaVersion:1,key:e,value:void 0,variationKey:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],flagVersion:o.version,evaluatedAt:l,traceId:u};return this.trackEvent({key:e,variationKey:void 0,value:void 0,reasons:d.reasons,evaluatedAt:l,context:a,flagVersion:o.version,schemaVersion:1,traceId:u}),d}let s=this.buildResult(e,i,o.version,r);return this.trackEvent({key:e,variationKey:i.variationKey,value:i.value,reasons:i.reasons,evaluatedAt:s.evaluatedAt,ruleId:s.ruleId,context:a,matchedTargetName:i.matchedTargetName,flagVersion:o.version,errorDetail:i.errorDetail,evaluationDurationUs:r,schemaVersion:1,inputsUsed:i.inputsUsed,traceId:s.traceId}),s}isEnabledSync(e,t){let a=this.evaluateAndTrack(e,this.mergeContext(t));return typeof a=="boolean"?a:false}getSync(e,t){let a=this.evaluateAndTrack(e,this.mergeContext(t));return a??t.fallback}evaluateSync(e,t){let a=this.mergeContext(t),{output:i,snapshot:o,durationUs:r}=this.evaluateRaw(e,a);return i?this.buildResult(e,i,o.version,r):{schemaVersion:1,key:e,value:void 0,variationKey:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],flagVersion:o.version,evaluatedAt:new Date().toISOString(),evaluationDurationUs:r,traceId:crypto.randomUUID()}}trackSync(e,t,a){let i=t.reasons.find(o=>o.type==="rule_match");this.trackEvent({key:e,variationKey:t.variationKey,value:t.value,reasons:t.reasons,evaluatedAt:t.evaluatedAt,ruleId:t.ruleId,context:this.mergeContext({context:a}),matchedTargetName:i?.ruleName,flagVersion:t.flagVersion,evaluationDurationUs:t.evaluationDurationUs,schemaVersion:t.schemaVersion,policyVersion:t.policyVersion,inputsUsed:t.inputsUsed,traceId:t.traceId});}identify(e){this.identifiedContext={...e};}reset(){this.identifiedContext={};}async refresh(){let e={Authorization:`Bearer ${this.apiKey}`};this.etag&&(e["If-None-Match"]=this.etag);let t=await fetch(`${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,{headers:e});if(t.status===304)return;if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(`Gradual: Failed to refresh - ${i.error??t.statusText}`)}let a=t.headers.get("ETag");a&&(this.etag=a),this.snapshot=await t.json();}getSnapshot(){return this.snapshot}onUpdate(e){return this.updateListeners.add(e),()=>this.updateListeners.delete(e)}close(){this.eventBuffer&&(this.eventBuffer.destroy(),this.eventBuffer=null);}};function B(n){return new p(n)}
|
|
2
|
-
exports.createGradual=
|
|
1
|
+
'use strict';function R(n){let e=0;for(let t=0;t<n.length;t++){let i=n.charCodeAt(t);e=(e<<5)-e+i,e|=0;}return Math.abs(e)}function m(n,e,t,i){i.add(`${t.bucketContextKind}.${t.bucketAttributeKey}`);let o=e[t.bucketContextKind]?.[t.bucketAttributeKey],r=t.seed??"",a=`${n}:${r}:${String(o??"anonymous")}`;return R(a)%1e5}function g(n,e){if(!(n.schedule&&n.startedAt))return {variations:n.variations,stepIndex:-1};let t=new Date(n.startedAt).getTime(),o=(e.getTime()-t)/6e4;if(o<0)return {variations:n.schedule[0]?.variations??n.variations,stepIndex:0};let r=0;for(let s=0;s<n.schedule.length;s++){let l=n.schedule[s];if(l.durationMinutes===0)return {variations:l.variations,stepIndex:s};if(r+=l.durationMinutes,o<r)return {variations:l.variations,stepIndex:s}}return {variations:n.schedule.at(-1)?.variations??n.variations,stepIndex:n.schedule.length-1}}function b(n,e,t,i){let o=0,r;for(let s of n)if(o+=s.weight,e<o){r=s;break}if(r||(r=n.at(-1)),!r)return;let a=t[r.variationKey];if(a)return {variation:a,variationKey:r.variationKey,matchedWeight:r.weight,bucketValue:e,scheduleStepIndex:i}}function I(n,e,t){let{contextKind:i,attributeKey:o,operator:r,value:a}=n;t.add(`${i}.${o}`);let s=e[i]?.[o];switch(r){case "equals":return s===a;case "not_equals":return s!==a;case "contains":return typeof s=="string"&&typeof a=="string"||Array.isArray(s)?s.includes(a):false;case "not_contains":return typeof s=="string"&&typeof a=="string"||Array.isArray(s)?!s.includes(a):true;case "starts_with":return typeof s=="string"&&typeof a=="string"?s.startsWith(a):false;case "ends_with":return typeof s=="string"&&typeof a=="string"?s.endsWith(a):false;case "greater_than":return typeof s=="number"&&typeof a=="number"?s>a:false;case "less_than":return typeof s=="number"&&typeof a=="number"?s<a:false;case "greater_than_or_equal":return typeof s=="number"&&typeof a=="number"?s>=a:false;case "less_than_or_equal":return typeof s=="number"&&typeof a=="number"?s<=a:false;case "in":return Array.isArray(a)?a.includes(s):false;case "not_in":return Array.isArray(a)?!a.includes(s):true;case "exists":return s!=null;case "not_exists":return s==null;default:return false}}function S(n,e,t){return n.every(i=>I(i,e,t))}function f(n,e,t){for(let i of n)if(t.add(`${i.contextKind}.${i.attributeKey}`),e[i.contextKind]?.[i.attributeKey]===i.attributeValue)return true;return false}function k(n,e,t){return n.excluded?.length&&f(n.excluded,e,t)?false:n.included?.length&&f(n.included,e,t)?true:n.conditions.length===0?false:S(n.conditions,e,t)}function K(n,e,t,i){switch(n.type){case "individual":return n.contextKind&&n.attributeKey&&n.attributeValue!==void 0?(i.add(`${n.contextKind}.${n.attributeKey}`),e[n.contextKind]?.[n.attributeKey]===n.attributeValue):false;case "rule":return n.conditions?S(n.conditions,e,i):false;case "segment":if(n.segmentKey){let o=t[n.segmentKey];if(o)return k(o,e,i)}return false;default:return false}}function V(n,e,t,i,o,r){if(n.rollout){let a=g(n.rollout,r),s=m(e,t,n.rollout,o);return b(a.variations,s,i,a.stepIndex)}if(n.variationKey){let a=i[n.variationKey];if(a)return {variation:a,variationKey:n.variationKey,matchedWeight:1e5,bucketValue:0,scheduleStepIndex:-1}}}function U(n,e,t,i){if(n.defaultRollout){let o=g(n.defaultRollout,i),r=m(n.key,e,n.defaultRollout,t);return b(o.variations,r,n.variations,o.stepIndex)}if(n.defaultVariationKey){let o=n.variations[n.defaultVariationKey];if(o)return {variation:o,variationKey:n.defaultVariationKey,matchedWeight:1e5,bucketValue:0,scheduleStepIndex:-1}}}function C(n){return {type:"rule_match",ruleId:n.id??"",ruleName:n.name}}function y(n){return n.scheduleStepIndex>=0?{type:"gradual_rollout",stepIndex:n.scheduleStepIndex,percentage:n.matchedWeight/1e3,bucket:n.bucketValue}:{type:"percentage_rollout",percentage:n.matchedWeight/1e3,bucket:n.bucketValue}}function v(n,e,t,i){if(!n.enabled)return {value:n.variations[n.offVariationKey]?.value,variationKey:n.offVariationKey,reasons:[{type:"off"}],inputsUsed:[]};let o=i?.now??new Date,r=new Set,a=[...n.targets].sort((l,u)=>l.sortOrder-u.sortOrder);for(let l of a)if(K(l,e,t,r)){let u=V(l,n.key,e,n.variations,r,o);if(u){let d=[C(l)];return l.rollout&&d.push(y(u)),{value:u.variation.value,variationKey:u.variationKey,reasons:d,matchedTargetName:l.name,inputsUsed:[...r]}}}let s=U(n,e,r,o);if(s){let l=[];return n.defaultRollout&&l.push(y(s)),l.push({type:"default"}),{value:s.variation.value,variationKey:s.variationKey,reasons:l,inputsUsed:[...r]}}return {value:void 0,variationKey:void 0,reasons:[{type:"default"}],inputsUsed:[...r]}}var O="0.8.8",A=globalThis,c=A.document,h=class{events=[];timer=null;options;onVisibilityChange=null;constructor(e){this.options=e,this.timer=setInterval(()=>this.flush(),this.options.flushIntervalMs),c?.addEventListener&&(this.onVisibilityChange=()=>{c.visibilityState==="hidden"&&this.flushBeacon();},c.addEventListener("visibilitychange",this.onVisibilityChange));}push(e){this.events.push(e),this.events.length>=this.options.maxBatchSize&&this.flush();}buildPayload(e){return {meta:{...this.options.meta,sdkVersion:O},events:e}}flush(){if(this.events.length===0)return;let e=this.events.splice(0,this.options.maxBatchSize),t=this.buildPayload(e);fetch(`${this.options.baseUrl}/sdk/evaluations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:JSON.stringify(t)}).catch(()=>{});}flushBeacon(){if(this.events.length===0)return;let e=this.events.splice(0,this.options.maxBatchSize),t=this.buildPayload(e);fetch(`${this.options.baseUrl}/sdk/evaluations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:JSON.stringify(t),keepalive:true}).catch(()=>{});}destroy(){this.timer&&(clearInterval(this.timer),this.timer=null),this.onVisibilityChange&&c?.removeEventListener&&c.removeEventListener("visibilitychange",this.onVisibilityChange),this.flush();}};var _="https://worker.gradual.so/api/v1",E=/^https:\/\//,w=/^http:\/\//;function P(){try{let n=globalThis,e=n.navigator;if(e&&e.product==="ReactNative")return "react-native";let t=n.window;if(t&&typeof t.document<"u")return "browser";if(n.process?.versions?.node)return "node";if(typeof globalThis<"u")return "edge"}catch{}return "unknown"}var D=P(),T=globalThis.process,B=typeof T?.hrtime?.bigint=="function";function x(){return B?T.hrtime.bigint():typeof performance<"u"?performance.now():Date.now()}function M(n){let e=x();return typeof n=="bigint"&&typeof e=="bigint"?Number((e-n)/1000n):Math.round((e-n)*1e3)}var p=class{apiKey;environment;baseUrl;initPromise;snapshot=null;identifiedContext={};updateListeners=new Set;eventBuffer=null;etag=null;eventsEnabled;eventsFlushIntervalMs;eventsMaxBatchSize;realtimeEnabled;pollingEnabled;pollingIntervalMs;pollingTimer=null;ws=null;reconnectTimer=null;reconnectAttempts=0;sync;constructor(e){this.apiKey=e.apiKey,this.environment=e.environment,this.baseUrl=e.baseUrl??_,this.eventsEnabled=e.events?.enabled??true,this.eventsFlushIntervalMs=e.events?.flushIntervalMs??3e4,this.eventsMaxBatchSize=e.events?.maxBatchSize??100;let t=typeof globalThis.WebSocket<"u";this.realtimeEnabled=e.realtime?.enabled??t,this.pollingEnabled=e.polling?.enabled??true,this.pollingIntervalMs=e.polling?.intervalMs??1e4,this.initPromise=this.init(),this.sync={isEnabled:this.isEnabledSync.bind(this),get:this.getSync.bind(this),evaluate:this.evaluateSync.bind(this),track:this.trackSync.bind(this)};}async init(){let e=await fetch(`${this.baseUrl}/sdk/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:this.apiKey})});if(!e.ok){let i=await e.json().catch(()=>({}));throw new Error(`Gradual: Failed to initialize - ${i.error??e.statusText}`)}let t=await e.json();if(!t.valid)throw new Error(`Gradual: Invalid API key - ${t.error??"Unknown error"}`);this.realtimeEnabled?await this.connectWebSocket():(await this.fetchSnapshot(),this.startPolling()),this.initializeEventBuffer();}initializeEventBuffer(){this.eventsEnabled&&this.snapshot?.meta&&(this.eventBuffer=new h({baseUrl:this.baseUrl,apiKey:this.apiKey,meta:{projectId:this.snapshot.meta.projectId,organizationId:this.snapshot.meta.organizationId,environmentId:this.snapshot.meta.environmentId,sdkPlatform:D},flushIntervalMs:this.eventsFlushIntervalMs,maxBatchSize:this.eventsMaxBatchSize}));}async fetchSnapshot(){let e={Authorization:`Bearer ${this.apiKey}`};this.etag&&(e["If-None-Match"]=this.etag);let t=await fetch(`${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,{headers:e});if(t.status===304)return;if(!t.ok){let o=await t.json().catch(()=>({}));throw new Error(`Gradual: Failed to fetch snapshot - ${o.error??t.statusText}`)}let i=t.headers.get("ETag");i&&(this.etag=i),this.snapshot=await t.json();}startPolling(){this.pollingEnabled&&(this.pollingTimer=setInterval(async()=>{try{let e=this.snapshot?.version;if(await this.fetchSnapshot(),this.snapshot&&this.snapshot.version!==e)for(let t of this.updateListeners)t();}catch(e){console.warn("Gradual: Polling refresh failed",e);}},this.pollingIntervalMs));}connectWebSocket(){return new Promise((e,t)=>{let o=`${this.baseUrl.replace(E,"wss://").replace(w,"ws://")}/sdk/connect?apiKey=${encodeURIComponent(this.apiKey)}&environment=${encodeURIComponent(this.environment)}`,r=new WebSocket(o);this.ws=r;let a=false;r.onmessage=s=>{try{let l=JSON.parse(typeof s.data=="string"?s.data:""),u=this.snapshot?.version;if(this.snapshot=l,l.version&&(this.etag=`"${l.version}"`),!a)a=!0,this.reconnectAttempts=0,e();else if(l.version!==u)for(let d of this.updateListeners)d();}catch(l){console.warn("Gradual: Failed to parse WebSocket message",l),a||(a=true,this.fallbackToPolling(e,t));}},r.onerror=()=>{a||(a=true,r.close(),this.ws=null,this.fallbackToPolling(e,t));},r.onclose=()=>{if(!a){a=true,this.ws=null,this.fallbackToPolling(e,t);return}this.ws=null,this.scheduleReconnect();};})}fallbackToPolling(e,t){console.warn("Gradual: WebSocket failed, falling back to polling"),this.fetchSnapshot().then(()=>{this.startPolling(),e();}).catch(t);}scheduleReconnect(){if(this.reconnectTimer)return;let e=Math.min(1e3*2**this.reconnectAttempts,3e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.reconnectWebSocket();},e);}reconnectWebSocket(){let t=`${this.baseUrl.replace(E,"wss://").replace(w,"ws://")}/sdk/connect?apiKey=${encodeURIComponent(this.apiKey)}&environment=${encodeURIComponent(this.environment)}`,i=new WebSocket(t);this.ws=i,i.onmessage=o=>{try{let r=JSON.parse(typeof o.data=="string"?o.data:""),a=this.snapshot?.version;if(this.snapshot=r,this.reconnectAttempts=0,r.version!==a)for(let s of this.updateListeners)s();}catch(r){console.warn("Gradual: Failed to parse WebSocket message",r);}},i.onerror=()=>{},i.onclose=()=>{this.ws=null,this.scheduleReconnect();};}ensureReady(){if(!this.snapshot)throw new Error("Gradual: SDK not ready. Use await ready() or async methods.");return this.snapshot}mergeContext(e){let t={},i=new Set([...Object.keys(this.identifiedContext),...Object.keys(e?.context??{})]);for(let o of i)t[o]={...this.identifiedContext[o],...e?.context?.[o]};return t}evaluateRaw(e,t){let i=this.ensureReady();if(!i.flags)return {output:null,snapshot:i,durationUs:0};let o=i.flags[e];if(!o)return {output:null,snapshot:i,durationUs:0};let r=x(),a;try{a=v(o,t,i.segments??{});}catch(s){let l=s instanceof Error?s.message:String(s);a={value:void 0,variationKey:void 0,reasons:[{type:"error",detail:l}],errorDetail:l};}return {output:a,snapshot:i,durationUs:M(r)}}buildResult(e,t,i,o){let r=t.reasons.find(a=>a.type==="rule_match");return {schemaVersion:1,key:e,value:t.value,variationKey:t.variationKey,reasons:t.reasons,ruleId:r?.ruleId,flagVersion:i,evaluatedAt:new Date().toISOString(),evaluationDurationUs:o,inputsUsed:t.inputsUsed,traceId:crypto.randomUUID()}}evaluateAndTrack(e,t){let{output:i,snapshot:o,durationUs:r}=this.evaluateRaw(e,t),a=new Date().toISOString(),s=crypto.randomUUID();if(!i){this.trackEvent({key:e,variationKey:void 0,value:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],context:t,flagVersion:o.version,schemaVersion:1,evaluatedAt:a,traceId:s});return}return this.trackEvent({key:e,variationKey:i.variationKey,value:i.value,reasons:i.reasons,context:t,matchedTargetName:i.matchedTargetName,flagVersion:o.version,errorDetail:i.errorDetail,evaluationDurationUs:r,schemaVersion:1,evaluatedAt:a,inputsUsed:i.inputsUsed,traceId:s}),i.value}trackEvent(e){if(!this.eventBuffer)return;let{context:t}=e,i=Object.keys(t),o={};for(let a of i)o[a]=Object.keys(t[a]??{});let r=i.length===0||i.every(a=>Object.keys(t[a]??{}).length===0);this.eventBuffer.push({schemaVersion:e.schemaVersion??1,key:e.key,variationKey:e.variationKey,value:e.value,reasons:e.reasons,evaluatedAt:e.evaluatedAt??new Date().toISOString(),ruleId:e.ruleId,flagVersion:e.flagVersion??0,policyVersion:e.policyVersion,inputsUsed:e.inputsUsed,traceId:e.traceId,contextKinds:i,contextKeys:o,timestamp:Date.now(),matchedTargetName:e.matchedTargetName,errorDetail:e.errorDetail,evaluationDurationUs:e.evaluationDurationUs,isAnonymous:r});}async ready(){await this.initPromise;}isReady(){return this.snapshot!==null}async isEnabled(e,t){await this.initPromise;let i=this.evaluateAndTrack(e,this.mergeContext(t));return typeof i=="boolean"?i:false}async get(e,t){await this.initPromise;let i=this.evaluateAndTrack(e,this.mergeContext(t));return i??t.fallback}async evaluate(e,t){await this.initPromise;let i=this.mergeContext(t),{output:o,snapshot:r,durationUs:a}=this.evaluateRaw(e,i);if(!o){let l=crypto.randomUUID(),u=new Date().toISOString(),d={schemaVersion:1,key:e,value:void 0,variationKey:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],flagVersion:r.version,evaluatedAt:u,traceId:l};return this.trackEvent({key:e,variationKey:void 0,value:void 0,reasons:d.reasons,evaluatedAt:u,context:i,flagVersion:r.version,schemaVersion:1,traceId:l}),d}let s=this.buildResult(e,o,r.version,a);return this.trackEvent({key:e,variationKey:o.variationKey,value:o.value,reasons:o.reasons,evaluatedAt:s.evaluatedAt,ruleId:s.ruleId,context:i,matchedTargetName:o.matchedTargetName,flagVersion:r.version,errorDetail:o.errorDetail,evaluationDurationUs:a,schemaVersion:1,inputsUsed:o.inputsUsed,traceId:s.traceId}),s}isEnabledSync(e,t){let i=this.evaluateAndTrack(e,this.mergeContext(t));return typeof i=="boolean"?i:false}getSync(e,t){let i=this.evaluateAndTrack(e,this.mergeContext(t));return i??t.fallback}evaluateSync(e,t){let i=this.mergeContext(t),{output:o,snapshot:r,durationUs:a}=this.evaluateRaw(e,i);return o?this.buildResult(e,o,r.version,a):{schemaVersion:1,key:e,value:void 0,variationKey:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],flagVersion:r.version,evaluatedAt:new Date().toISOString(),evaluationDurationUs:a,traceId:crypto.randomUUID()}}trackSync(e,t,i){let o=t.reasons.find(r=>r.type==="rule_match");this.trackEvent({key:e,variationKey:t.variationKey,value:t.value,reasons:t.reasons,evaluatedAt:t.evaluatedAt,ruleId:t.ruleId,context:this.mergeContext({context:i}),matchedTargetName:o?.ruleName,flagVersion:t.flagVersion,evaluationDurationUs:t.evaluationDurationUs,schemaVersion:t.schemaVersion,policyVersion:t.policyVersion,inputsUsed:t.inputsUsed,traceId:t.traceId});}identify(e){this.identifiedContext={...e};}reset(){this.identifiedContext={};}async refresh(){await this.fetchSnapshot();}getSnapshot(){return this.snapshot}onUpdate(e){return this.updateListeners.add(e),()=>this.updateListeners.delete(e)}close(){this.ws&&(this.ws.close(),this.ws=null),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.pollingTimer&&(clearInterval(this.pollingTimer),this.pollingTimer=null),this.eventBuffer&&(this.eventBuffer.destroy(),this.eventBuffer=null);}};function F(n){return new p(n)}
|
|
2
|
+
exports.createGradual=F;exports.evaluateFlag=v;//# sourceMappingURL=index.cjs.map
|
|
3
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/evaluator.ts","../src/event-buffer.ts","../src/client.ts"],"names":["hashString","str","hash","i","char","getBucketValue","flagKey","context","rollout","inputsUsed","bucketKey","seed","hashInput","resolveActiveRollout","now","startedAt","elapsedMinutes","cumulativeMinutes","step","selectVariationFromRollout","activeVariations","bucketValue","variations","scheduleStepIndex","cumulative","matchedRv","rv","variation","evaluateCondition","condition","contextKind","attributeKey","operator","value","contextValue","evaluateConditions","conditions","matchesIndividual","entries","entry","evaluateSegment","segment","evaluateTarget","target","segments","resolveTargetVariation","active","resolveDefaultVariation","flag","buildRuleMatchReason","buildRolloutReason","rolloutResult","evaluateFlag","options","sortedTargets","a","b","resolved","reasons","SDK_VERSION","g","doc","EventBuffer","event","batch","payload","DEFAULT_BASE_URL","detectPlatform","nav","win","SDK_PLATFORM","proc","hasHrtime","nowNs","elapsedUs","start","end","GradualClient","pollingEnabled","pollingIntervalMs","previousVersion","cb","error","initResponse","initData","snapshotResponse","initialEtag","merged","allKinds","kind","key","snapshot","startTime","output","err","errorDetail","flagVersion","durationUs","ruleMatch","evaluatedAt","traceId","params","contextKinds","contextKeys","isAnonymous","result","r","headers","response","etag","callback","createGradual"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n EvalOutput,\n EvaluationContext,\n Reason,\n SnapshotFlag,\n SnapshotIndividualEntry,\n SnapshotRollout,\n SnapshotRolloutVariation,\n SnapshotRuleCondition,\n SnapshotScheduleStep,\n SnapshotSegment,\n SnapshotTarget,\n SnapshotVariation,\n} from \"./types\";\n\nfunction hashString(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n // biome-ignore lint/suspicious/noBitwiseOperators: intentional hash algorithm using bitwise shift\n hash = (hash << 5) - hash + char;\n // biome-ignore lint/suspicious/noBitwiseOperators: converting to 32-bit integer\n hash |= 0;\n }\n return Math.abs(hash);\n}\n\nfunction getBucketValue(\n flagKey: string,\n context: EvaluationContext,\n rollout: SnapshotRollout,\n inputsUsed: Set<string>\n): number {\n inputsUsed.add(`${rollout.bucketContextKind}.${rollout.bucketAttributeKey}`);\n const bucketKey =\n context[rollout.bucketContextKind]?.[rollout.bucketAttributeKey];\n const seed = rollout.seed ?? \"\";\n const hashInput = `${flagKey}:${seed}:${String(bucketKey ?? \"anonymous\")}`;\n return hashString(hashInput) % 100_000;\n}\n\ninterface ActiveRollout {\n variations: SnapshotRolloutVariation[];\n stepIndex: number;\n}\n\nfunction resolveActiveRollout(\n rollout: SnapshotRollout,\n now: Date\n): ActiveRollout {\n if (!(rollout.schedule && rollout.startedAt)) {\n return { variations: rollout.variations, stepIndex: -1 };\n }\n\n const startedAt = new Date(rollout.startedAt).getTime();\n const elapsedMs = now.getTime() - startedAt;\n const elapsedMinutes = elapsedMs / 60_000;\n\n if (elapsedMinutes < 0) {\n return {\n variations: rollout.schedule[0]?.variations ?? rollout.variations,\n stepIndex: 0,\n };\n }\n\n let cumulativeMinutes = 0;\n for (let i = 0; i < rollout.schedule.length; i++) {\n const step = rollout.schedule[i] as SnapshotScheduleStep;\n if (step.durationMinutes === 0) {\n return { variations: step.variations, stepIndex: i };\n }\n cumulativeMinutes += step.durationMinutes;\n if (elapsedMinutes < cumulativeMinutes) {\n return { variations: step.variations, stepIndex: i };\n }\n }\n\n const lastStep = rollout.schedule.at(-1);\n return {\n variations: lastStep?.variations ?? rollout.variations,\n stepIndex: rollout.schedule.length - 1,\n };\n}\n\ninterface RolloutResult {\n variation: SnapshotVariation;\n variationKey: string;\n matchedWeight: number;\n bucketValue: number;\n scheduleStepIndex: number;\n}\n\nfunction selectVariationFromRollout(\n activeVariations: SnapshotRolloutVariation[],\n bucketValue: number,\n variations: Record<string, SnapshotVariation>,\n scheduleStepIndex: number\n): RolloutResult | undefined {\n let cumulative = 0;\n let matchedRv: SnapshotRolloutVariation | undefined;\n\n for (const rv of activeVariations) {\n cumulative += rv.weight;\n if (bucketValue < cumulative) {\n matchedRv = rv;\n break;\n }\n }\n\n if (!matchedRv) {\n matchedRv = activeVariations.at(-1);\n }\n\n if (!matchedRv) {\n return undefined;\n }\n\n const variation = variations[matchedRv.variationKey];\n if (!variation) {\n return undefined;\n }\n\n return {\n variation,\n variationKey: matchedRv.variationKey,\n matchedWeight: matchedRv.weight,\n bucketValue,\n scheduleStepIndex,\n };\n}\n\nfunction evaluateCondition(\n condition: SnapshotRuleCondition,\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n const { contextKind, attributeKey, operator, value } = condition;\n inputsUsed.add(`${contextKind}.${attributeKey}`);\n const contextValue = context[contextKind]?.[attributeKey];\n\n switch (operator) {\n case \"equals\":\n return contextValue === value;\n\n case \"not_equals\":\n return contextValue !== value;\n\n case \"contains\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.includes(value);\n }\n if (Array.isArray(contextValue)) {\n return contextValue.includes(value);\n }\n return false;\n\n case \"not_contains\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return !contextValue.includes(value);\n }\n if (Array.isArray(contextValue)) {\n return !contextValue.includes(value);\n }\n return true;\n\n case \"starts_with\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.startsWith(value);\n }\n return false;\n\n case \"ends_with\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.endsWith(value);\n }\n return false;\n\n case \"greater_than\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue > value;\n }\n return false;\n\n case \"less_than\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue < value;\n }\n return false;\n\n case \"greater_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue >= value;\n }\n return false;\n\n case \"less_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue <= value;\n }\n return false;\n\n case \"in\":\n if (Array.isArray(value)) {\n return value.includes(contextValue);\n }\n return false;\n\n case \"not_in\":\n if (Array.isArray(value)) {\n return !value.includes(contextValue);\n }\n return true;\n\n case \"exists\":\n return contextValue !== undefined && contextValue !== null;\n\n case \"not_exists\":\n return contextValue === undefined || contextValue === null;\n\n default:\n return false;\n }\n}\n\nfunction evaluateConditions(\n conditions: SnapshotRuleCondition[],\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n return conditions.every((condition) =>\n evaluateCondition(condition, context, inputsUsed)\n );\n}\n\nfunction matchesIndividual(\n entries: SnapshotIndividualEntry[],\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n for (const entry of entries) {\n inputsUsed.add(`${entry.contextKind}.${entry.attributeKey}`);\n if (\n context[entry.contextKind]?.[entry.attributeKey] === entry.attributeValue\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction evaluateSegment(\n segment: SnapshotSegment,\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n // Priority 1: Excluded individuals never match\n if (\n segment.excluded?.length &&\n matchesIndividual(segment.excluded, context, inputsUsed)\n ) {\n return false;\n }\n\n // Priority 2: Included individuals always match\n if (\n segment.included?.length &&\n matchesIndividual(segment.included, context, inputsUsed)\n ) {\n return true;\n }\n\n // Priority 3: Evaluate conditions (empty conditions = no match)\n if (segment.conditions.length === 0) {\n return false;\n }\n return evaluateConditions(segment.conditions, context, inputsUsed);\n}\n\nfunction evaluateTarget(\n target: SnapshotTarget,\n context: EvaluationContext,\n segments: Record<string, SnapshotSegment>,\n inputsUsed: Set<string>\n): boolean {\n switch (target.type) {\n case \"individual\":\n if (\n target.contextKind &&\n target.attributeKey &&\n target.attributeValue !== undefined\n ) {\n inputsUsed.add(`${target.contextKind}.${target.attributeKey}`);\n return (\n context[target.contextKind]?.[target.attributeKey] ===\n target.attributeValue\n );\n }\n return false;\n\n case \"rule\":\n if (target.conditions) {\n return evaluateConditions(target.conditions, context, inputsUsed);\n }\n return false;\n\n case \"segment\":\n if (target.segmentKey) {\n const segment = segments[target.segmentKey];\n if (segment) {\n return evaluateSegment(segment, context, inputsUsed);\n }\n }\n return false;\n\n default:\n return false;\n }\n}\n\nfunction resolveTargetVariation(\n target: SnapshotTarget,\n flagKey: string,\n context: EvaluationContext,\n variations: Record<string, SnapshotVariation>,\n inputsUsed: Set<string>,\n now: Date\n): RolloutResult | undefined {\n if (target.rollout) {\n const active = resolveActiveRollout(target.rollout, now);\n const bucketValue = getBucketValue(\n flagKey,\n context,\n target.rollout,\n inputsUsed\n );\n return selectVariationFromRollout(\n active.variations,\n bucketValue,\n variations,\n active.stepIndex\n );\n }\n\n if (target.variationKey) {\n const variation = variations[target.variationKey];\n if (variation) {\n return {\n variation,\n variationKey: target.variationKey,\n matchedWeight: 100_000,\n bucketValue: 0,\n scheduleStepIndex: -1,\n };\n }\n }\n\n return undefined;\n}\n\nfunction resolveDefaultVariation(\n flag: SnapshotFlag,\n context: EvaluationContext,\n inputsUsed: Set<string>,\n now: Date\n): RolloutResult | undefined {\n if (flag.defaultRollout) {\n const active = resolveActiveRollout(flag.defaultRollout, now);\n const bucketValue = getBucketValue(\n flag.key,\n context,\n flag.defaultRollout,\n inputsUsed\n );\n return selectVariationFromRollout(\n active.variations,\n bucketValue,\n flag.variations,\n active.stepIndex\n );\n }\n\n if (flag.defaultVariationKey) {\n const variation = flag.variations[flag.defaultVariationKey];\n if (variation) {\n return {\n variation,\n variationKey: flag.defaultVariationKey,\n matchedWeight: 100_000,\n bucketValue: 0,\n scheduleStepIndex: -1,\n };\n }\n }\n\n return undefined;\n}\n\nfunction buildRuleMatchReason(target: SnapshotTarget): Reason {\n return {\n type: \"rule_match\",\n ruleId: target.id ?? \"\",\n ruleName: target.name,\n };\n}\n\nfunction buildRolloutReason(rolloutResult: RolloutResult): Reason {\n if (rolloutResult.scheduleStepIndex >= 0) {\n return {\n type: \"gradual_rollout\",\n stepIndex: rolloutResult.scheduleStepIndex,\n percentage: rolloutResult.matchedWeight / 1000,\n bucket: rolloutResult.bucketValue,\n };\n }\n return {\n type: \"percentage_rollout\",\n percentage: rolloutResult.matchedWeight / 1000,\n bucket: rolloutResult.bucketValue,\n };\n}\n\nexport function evaluateFlag(\n flag: SnapshotFlag,\n context: EvaluationContext,\n segments: Record<string, SnapshotSegment>,\n options?: { now?: Date }\n): EvalOutput {\n if (!flag.enabled) {\n const offVariation = flag.variations[flag.offVariationKey];\n return {\n value: offVariation?.value,\n variationKey: flag.offVariationKey,\n reasons: [{ type: \"off\" }],\n inputsUsed: [],\n };\n }\n\n const now = options?.now ?? new Date();\n const inputsUsed = new Set<string>();\n\n const sortedTargets = [...flag.targets].sort(\n (a, b) => a.sortOrder - b.sortOrder\n );\n\n for (const target of sortedTargets) {\n if (evaluateTarget(target, context, segments, inputsUsed)) {\n const resolved = resolveTargetVariation(\n target,\n flag.key,\n context,\n flag.variations,\n inputsUsed,\n now\n );\n if (resolved) {\n const reasons: Reason[] = [buildRuleMatchReason(target)];\n if (target.rollout) {\n reasons.push(buildRolloutReason(resolved));\n }\n\n return {\n value: resolved.variation.value,\n variationKey: resolved.variationKey,\n reasons,\n matchedTargetName: target.name,\n inputsUsed: [...inputsUsed],\n };\n }\n }\n }\n\n const resolved = resolveDefaultVariation(flag, context, inputsUsed, now);\n if (resolved) {\n const reasons: Reason[] = [];\n if (flag.defaultRollout) {\n reasons.push(buildRolloutReason(resolved));\n }\n reasons.push({ type: \"default\" });\n\n return {\n value: resolved.variation.value,\n variationKey: resolved.variationKey,\n reasons,\n inputsUsed: [...inputsUsed],\n };\n }\n\n return {\n value: undefined,\n variationKey: undefined,\n reasons: [{ type: \"default\" }],\n inputsUsed: [...inputsUsed],\n };\n}\n","import type { EvaluationBatchPayload, EvaluationEvent } from \"./types\";\n\ndeclare const __SDK_VERSION__: string;\nexport const SDK_VERSION = __SDK_VERSION__;\n\ninterface EventBufferOptions {\n baseUrl: string;\n apiKey: string;\n meta: {\n projectId: string;\n organizationId: string;\n environmentId: string;\n sdkPlatform?: string;\n };\n flushIntervalMs: number;\n maxBatchSize: number;\n}\n\nconst g = globalThis as Record<string, unknown>;\nconst doc = g.document as\n | {\n visibilityState?: string;\n addEventListener?: (event: string, handler: () => void) => void;\n removeEventListener?: (event: string, handler: () => void) => void;\n }\n | undefined;\nexport class EventBuffer {\n private readonly events: EvaluationEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly options: EventBufferOptions;\n private readonly onVisibilityChange: (() => void) | null = null;\n\n constructor(options: EventBufferOptions) {\n this.options = options;\n this.timer = setInterval(() => this.flush(), this.options.flushIntervalMs);\n\n if (doc?.addEventListener) {\n this.onVisibilityChange = () => {\n if (doc.visibilityState === \"hidden\") {\n this.flushBeacon();\n }\n };\n doc.addEventListener(\"visibilitychange\", this.onVisibilityChange);\n }\n }\n\n push(event: EvaluationEvent): void {\n this.events.push(event);\n if (this.events.length >= this.options.maxBatchSize) {\n this.flush();\n }\n }\n\n private buildPayload(batch: EvaluationEvent[]): EvaluationBatchPayload {\n return {\n meta: {\n ...this.options.meta,\n sdkVersion: SDK_VERSION,\n },\n events: batch,\n };\n }\n\n flush(): void {\n if (this.events.length === 0) {\n return;\n }\n const batch = this.events.splice(0, this.options.maxBatchSize);\n const payload = this.buildPayload(batch);\n\n fetch(`${this.options.baseUrl}/sdk/evaluations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify(payload),\n }).catch(() => {\n // Fire-and-forget: silently drop failed events to prevent unbounded growth\n });\n }\n\n /**\n * Flush with keepalive flag for reliable delivery during page unload.\n * keepalive fetch survives page navigation like sendBeacon but supports headers.\n */\n private flushBeacon(): void {\n if (this.events.length === 0) {\n return;\n }\n\n const batch = this.events.splice(0, this.options.maxBatchSize);\n const payload = this.buildPayload(batch);\n\n fetch(`${this.options.baseUrl}/sdk/evaluations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify(payload),\n keepalive: true,\n }).catch(() => {\n // Fire-and-forget\n });\n }\n\n destroy(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n if (this.onVisibilityChange && doc?.removeEventListener) {\n doc.removeEventListener(\"visibilitychange\", this.onVisibilityChange);\n }\n this.flush();\n }\n}\n","import { evaluateFlag } from \"./evaluator\";\nimport { EventBuffer } from \"./event-buffer\";\nimport type {\n EnvironmentSnapshot,\n EvalOutput,\n EvaluationContext,\n EvaluationResult,\n FlagOptions,\n GradualOptions,\n IsEnabledOptions,\n Reason,\n} from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://worker.gradual.so/api/v1\";\n\ntype SdkPlatform = \"browser\" | \"node\" | \"react-native\" | \"edge\" | \"unknown\";\n\nfunction detectPlatform(): SdkPlatform {\n try {\n const g = globalThis as Record<string, unknown>;\n const nav = g.navigator as\n | { product?: string; userAgent?: string }\n | undefined;\n if (nav && nav.product === \"ReactNative\") {\n return \"react-native\";\n }\n const win = g.window as { document?: unknown } | undefined;\n if (win && typeof win.document !== \"undefined\") {\n return \"browser\";\n }\n const proc = g.process as { versions?: { node?: string } } | undefined;\n if (proc?.versions?.node) {\n return \"node\";\n }\n if (typeof globalThis !== \"undefined\") {\n return \"edge\";\n }\n } catch {\n // Ignore detection errors\n }\n return \"unknown\";\n}\n\nconst SDK_PLATFORM = detectPlatform();\n\nconst proc = (globalThis as Record<string, unknown>).process as\n | { hrtime?: { bigint?: () => bigint } }\n | undefined;\nconst hasHrtime = typeof proc?.hrtime?.bigint === \"function\";\n\nfunction nowNs(): bigint | number {\n if (hasHrtime) {\n // biome-ignore lint/style/noNonNullAssertion: guarded by hasHrtime check\n return proc!.hrtime!.bigint!();\n }\n if (typeof performance !== \"undefined\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction elapsedUs(start: bigint | number): number {\n const end = nowNs();\n if (typeof start === \"bigint\" && typeof end === \"bigint\") {\n // hrtime bigint: nanoseconds → microseconds\n return Number((end - start) / 1000n);\n }\n // performance.now() ms or Date.now() ms → microseconds\n return Math.round(((end as number) - (start as number)) * 1000);\n}\n\nexport interface Gradual {\n /** Wait for the SDK to be ready (snapshot fetched) */\n ready(): Promise<void>;\n\n /** Check if the SDK is ready for sync access */\n isReady(): boolean;\n\n /** Check if a boolean flag is enabled */\n isEnabled(key: string, options?: IsEnabledOptions): Promise<boolean>;\n\n /** Get a flag value with type inference from fallback */\n get<T>(key: string, options: FlagOptions<T>): Promise<T>;\n\n /** Evaluate a flag and return the full structured result (also tracks the evaluation) */\n evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): Promise<EvaluationResult<T>>;\n\n /** Set persistent user context for all evaluations */\n identify(context: EvaluationContext): void;\n\n /** Clear the identified user context */\n reset(): void;\n\n /** Refresh the snapshot from the server */\n refresh(): Promise<void>;\n\n /** Get the current snapshot (for debugging) */\n getSnapshot(): EnvironmentSnapshot | null;\n\n /** Subscribe to snapshot updates from polling (returns unsubscribe function) */\n onUpdate(callback: () => void): () => void;\n\n /** Flush pending evaluation events and stop the event buffer */\n close(): void;\n\n /** Sync methods (throw if not ready) */\n sync: GradualSync;\n}\n\nexport interface GradualSync {\n /** Sync version of isEnabled (throws if not ready) */\n isEnabled(key: string, options?: IsEnabledOptions): boolean;\n\n /** Sync version of get (throws if not ready) */\n get<T>(key: string, options: FlagOptions<T>): T;\n\n /** Evaluate a flag without tracking. Use with track() for React-safe evaluation. */\n evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): EvaluationResult<T>;\n\n /** Manually track an evaluation that was produced by evaluate(). */\n track(\n key: string,\n result: EvaluationResult,\n context?: EvaluationContext\n ): void;\n}\n\nclass GradualClient implements Gradual {\n private readonly apiKey: string;\n private readonly environment: string;\n private readonly baseUrl: string;\n private readonly initPromise: Promise<void>;\n private snapshot: EnvironmentSnapshot | null = null;\n private identifiedContext: EvaluationContext = {};\n private readonly updateListeners: Set<() => void> = new Set();\n private eventBuffer: EventBuffer | null = null;\n private etag: string | null = null;\n private readonly eventsEnabled: boolean;\n private readonly eventsFlushIntervalMs: number;\n private readonly eventsMaxBatchSize: number;\n\n readonly sync: GradualSync;\n\n constructor(options: GradualOptions) {\n this.apiKey = options.apiKey;\n this.environment = options.environment;\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n this.eventsEnabled = options.events?.enabled ?? true;\n this.eventsFlushIntervalMs = options.events?.flushIntervalMs ?? 30_000;\n this.eventsMaxBatchSize = options.events?.maxBatchSize ?? 100;\n this.initPromise = this.init();\n\n this.sync = {\n isEnabled: this.isEnabledSync.bind(this),\n get: this.getSync.bind(this),\n evaluate: this.evaluateSync.bind(this),\n track: this.trackSync.bind(this),\n };\n\n const pollingEnabled = options.polling?.enabled ?? true;\n const pollingIntervalMs = options.polling?.intervalMs ?? 10_000;\n\n if (pollingEnabled) {\n this.initPromise.then(() => {\n setInterval(async () => {\n try {\n const previousVersion = this.snapshot?.version;\n await this.refresh();\n if (this.snapshot && this.snapshot.version !== previousVersion) {\n for (const cb of this.updateListeners) {\n cb();\n }\n }\n } catch (error) {\n console.warn(\"Gradual: Polling refresh failed\", error);\n }\n }, pollingIntervalMs);\n });\n }\n }\n\n private async init(): Promise<void> {\n const initResponse = await fetch(`${this.baseUrl}/sdk/init`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ apiKey: this.apiKey }),\n });\n\n if (!initResponse.ok) {\n const error = await initResponse.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to initialize - ${(error as { error?: string }).error ?? initResponse.statusText}`\n );\n }\n\n const initData = (await initResponse.json()) as {\n valid: boolean;\n error?: string;\n };\n\n if (!initData.valid) {\n throw new Error(\n `Gradual: Invalid API key - ${initData.error ?? \"Unknown error\"}`\n );\n }\n\n const snapshotResponse = await fetch(\n `${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,\n { headers: { Authorization: `Bearer ${this.apiKey}` } }\n );\n\n if (!snapshotResponse.ok) {\n const error = await snapshotResponse.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to fetch snapshot - ${(error as { error?: string }).error ?? snapshotResponse.statusText}`\n );\n }\n\n const initialEtag = snapshotResponse.headers.get(\"ETag\");\n if (initialEtag) {\n this.etag = initialEtag;\n }\n this.snapshot = (await snapshotResponse.json()) as EnvironmentSnapshot;\n\n if (this.eventsEnabled && this.snapshot.meta) {\n this.eventBuffer = new EventBuffer({\n baseUrl: this.baseUrl,\n apiKey: this.apiKey,\n meta: {\n projectId: this.snapshot.meta.projectId,\n organizationId: this.snapshot.meta.organizationId,\n environmentId: this.snapshot.meta.environmentId,\n sdkPlatform: SDK_PLATFORM,\n },\n flushIntervalMs: this.eventsFlushIntervalMs,\n maxBatchSize: this.eventsMaxBatchSize,\n });\n }\n }\n\n private ensureReady(): EnvironmentSnapshot {\n if (!this.snapshot) {\n throw new Error(\n \"Gradual: SDK not ready. Use await ready() or async methods.\"\n );\n }\n return this.snapshot;\n }\n\n private mergeContext(options?: {\n context?: EvaluationContext;\n }): EvaluationContext {\n const merged: EvaluationContext = {};\n const allKinds = new Set([\n ...Object.keys(this.identifiedContext),\n ...Object.keys(options?.context ?? {}),\n ]);\n for (const kind of allKinds) {\n merged[kind] = {\n ...this.identifiedContext[kind],\n ...options?.context?.[kind],\n };\n }\n return merged;\n }\n\n private evaluateRaw(\n key: string,\n context: EvaluationContext\n ): {\n output: EvalOutput | null;\n snapshot: EnvironmentSnapshot;\n durationUs: number;\n } {\n const snapshot = this.ensureReady();\n if (!snapshot.flags) {\n return { output: null, snapshot, durationUs: 0 };\n }\n const flag = snapshot.flags[key];\n if (!flag) {\n return { output: null, snapshot, durationUs: 0 };\n }\n\n const startTime = nowNs();\n let output: EvalOutput;\n try {\n output = evaluateFlag(flag, context, snapshot.segments ?? {});\n } catch (err) {\n const errorDetail = err instanceof Error ? err.message : String(err);\n output = {\n value: undefined,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: errorDetail }],\n errorDetail,\n };\n }\n\n return { output, snapshot, durationUs: elapsedUs(startTime) };\n }\n\n private buildResult<T>(\n key: string,\n output: EvalOutput,\n flagVersion: number,\n durationUs?: number\n ): EvaluationResult<T> {\n const ruleMatch = output.reasons.find(\n (r): r is Extract<Reason, { type: \"rule_match\" }> =>\n r.type === \"rule_match\"\n );\n\n return {\n schemaVersion: 1,\n key,\n value: output.value as T,\n variationKey: output.variationKey,\n reasons: output.reasons,\n ruleId: ruleMatch?.ruleId,\n flagVersion,\n evaluatedAt: new Date().toISOString(),\n evaluationDurationUs: durationUs,\n inputsUsed: output.inputsUsed,\n traceId: crypto.randomUUID(),\n };\n }\n\n private evaluateAndTrack(key: string, context: EvaluationContext): unknown {\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n const evaluatedAt = new Date().toISOString();\n const traceId = crypto.randomUUID();\n\n if (!output) {\n this.trackEvent({\n key,\n variationKey: undefined,\n value: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n context,\n flagVersion: snapshot.version,\n schemaVersion: 1,\n evaluatedAt,\n traceId,\n });\n return undefined;\n }\n\n this.trackEvent({\n key,\n variationKey: output.variationKey,\n value: output.value,\n reasons: output.reasons,\n context,\n matchedTargetName: output.matchedTargetName,\n flagVersion: snapshot.version,\n errorDetail: output.errorDetail,\n evaluationDurationUs: durationUs,\n schemaVersion: 1,\n evaluatedAt,\n inputsUsed: output.inputsUsed,\n traceId,\n });\n\n return output.value;\n }\n\n private trackEvent(params: {\n key: string;\n variationKey: string | undefined;\n value: unknown;\n reasons: Reason[];\n evaluatedAt?: string;\n ruleId?: string;\n context: EvaluationContext;\n matchedTargetName?: string;\n flagVersion?: number;\n errorDetail?: string;\n evaluationDurationUs?: number;\n schemaVersion?: 1;\n policyVersion?: number;\n inputsUsed?: string[];\n traceId?: string;\n }): void {\n if (!this.eventBuffer) {\n return;\n }\n const { context } = params;\n const contextKinds = Object.keys(context);\n const contextKeys: Record<string, string[]> = {};\n for (const kind of contextKinds) {\n contextKeys[kind] = Object.keys(context[kind] ?? {});\n }\n\n const isAnonymous =\n contextKinds.length === 0 ||\n contextKinds.every(\n (kind) => Object.keys(context[kind] ?? {}).length === 0\n );\n\n this.eventBuffer.push({\n schemaVersion: params.schemaVersion ?? 1,\n key: params.key,\n variationKey: params.variationKey,\n value: params.value,\n reasons: params.reasons,\n evaluatedAt: params.evaluatedAt ?? new Date().toISOString(),\n ruleId: params.ruleId,\n flagVersion: params.flagVersion ?? 0,\n policyVersion: params.policyVersion,\n inputsUsed: params.inputsUsed,\n traceId: params.traceId,\n contextKinds,\n contextKeys,\n timestamp: Date.now(),\n matchedTargetName: params.matchedTargetName,\n errorDetail: params.errorDetail,\n evaluationDurationUs: params.evaluationDurationUs,\n isAnonymous,\n });\n }\n\n async ready(): Promise<void> {\n await this.initPromise;\n }\n\n isReady(): boolean {\n return this.snapshot !== null;\n }\n\n async isEnabled(key: string, options?: IsEnabledOptions): Promise<boolean> {\n await this.initPromise;\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return typeof value === \"boolean\" ? value : false;\n }\n\n async get<T>(key: string, options: FlagOptions<T>): Promise<T> {\n await this.initPromise;\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return value !== undefined && value !== null\n ? (value as T)\n : options.fallback;\n }\n\n async evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): Promise<EvaluationResult<T>> {\n await this.initPromise;\n const context = this.mergeContext(options);\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n\n if (!output) {\n const traceId = crypto.randomUUID();\n const evaluatedAt = new Date().toISOString();\n const result: EvaluationResult<T> = {\n schemaVersion: 1,\n key,\n value: undefined as T,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n flagVersion: snapshot.version,\n evaluatedAt,\n traceId,\n };\n this.trackEvent({\n key,\n variationKey: undefined,\n value: undefined,\n reasons: result.reasons,\n evaluatedAt,\n context,\n flagVersion: snapshot.version,\n schemaVersion: 1,\n traceId,\n });\n return result;\n }\n\n const result = this.buildResult<T>(\n key,\n output,\n snapshot.version,\n durationUs\n );\n\n this.trackEvent({\n key,\n variationKey: output.variationKey,\n value: output.value,\n reasons: output.reasons,\n evaluatedAt: result.evaluatedAt,\n ruleId: result.ruleId,\n context,\n matchedTargetName: output.matchedTargetName,\n flagVersion: snapshot.version,\n errorDetail: output.errorDetail,\n evaluationDurationUs: durationUs,\n schemaVersion: 1,\n inputsUsed: output.inputsUsed,\n traceId: result.traceId,\n });\n\n return result;\n }\n\n private isEnabledSync(key: string, options?: IsEnabledOptions): boolean {\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return typeof value === \"boolean\" ? value : false;\n }\n\n private getSync<T>(key: string, options: FlagOptions<T>): T {\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return value !== undefined && value !== null\n ? (value as T)\n : options.fallback;\n }\n\n private evaluateSync<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): EvaluationResult<T> {\n const context = this.mergeContext(options);\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n\n if (!output) {\n return {\n schemaVersion: 1,\n key,\n value: undefined as T,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n flagVersion: snapshot.version,\n evaluatedAt: new Date().toISOString(),\n evaluationDurationUs: durationUs,\n traceId: crypto.randomUUID(),\n };\n }\n\n return this.buildResult<T>(key, output, snapshot.version, durationUs);\n }\n\n private trackSync(\n key: string,\n result: EvaluationResult,\n context?: EvaluationContext\n ): void {\n const ruleMatch = result.reasons.find(\n (r): r is Extract<Reason, { type: \"rule_match\" }> =>\n r.type === \"rule_match\"\n );\n\n this.trackEvent({\n key,\n variationKey: result.variationKey,\n value: result.value,\n reasons: result.reasons,\n evaluatedAt: result.evaluatedAt,\n ruleId: result.ruleId,\n context: this.mergeContext({ context }),\n matchedTargetName: ruleMatch?.ruleName,\n flagVersion: result.flagVersion,\n evaluationDurationUs: result.evaluationDurationUs,\n schemaVersion: result.schemaVersion,\n policyVersion: result.policyVersion,\n inputsUsed: result.inputsUsed,\n traceId: result.traceId,\n });\n }\n\n identify(context: EvaluationContext): void {\n this.identifiedContext = { ...context };\n }\n\n reset(): void {\n this.identifiedContext = {};\n }\n\n async refresh(): Promise<void> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n };\n if (this.etag) {\n headers[\"If-None-Match\"] = this.etag;\n }\n\n const response = await fetch(\n `${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,\n { headers }\n );\n\n if (response.status === 304) {\n return;\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to refresh - ${(error as { error?: string }).error ?? response.statusText}`\n );\n }\n\n const etag = response.headers.get(\"ETag\");\n if (etag) {\n this.etag = etag;\n }\n this.snapshot = (await response.json()) as EnvironmentSnapshot;\n }\n\n getSnapshot(): EnvironmentSnapshot | null {\n return this.snapshot;\n }\n\n onUpdate(callback: () => void): () => void {\n this.updateListeners.add(callback);\n return () => this.updateListeners.delete(callback);\n }\n\n close(): void {\n if (this.eventBuffer) {\n this.eventBuffer.destroy();\n this.eventBuffer = null;\n }\n }\n}\n\n/**\n * Create a Gradual feature flag client\n *\n * @example\n * ```ts\n * const gradual = createGradual({\n * apiKey: 'gra_xxx',\n * environment: 'production'\n * })\n *\n * // Boolean flags\n * const enabled = await gradual.isEnabled('new-feature')\n *\n * // Typed values (inferred from fallback)\n * const theme = await gradual.get('theme', { fallback: 'dark' })\n *\n * // Full structured result\n * const result = await gradual.evaluate('new-feature')\n * // result.value, result.reasons, result.ruleId, result.flagVersion\n *\n * // With user context\n * gradual.identify({ userId: '123', plan: 'pro' })\n * const proFeature = await gradual.isEnabled('pro-feature')\n * ```\n */\nexport function createGradual(options: GradualOptions): Gradual {\n return new GradualClient(options);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/evaluator.ts","../src/event-buffer.ts","../src/client.ts"],"names":["hashString","str","hash","i","char","getBucketValue","flagKey","context","rollout","inputsUsed","bucketKey","seed","hashInput","resolveActiveRollout","now","startedAt","elapsedMinutes","cumulativeMinutes","step","selectVariationFromRollout","activeVariations","bucketValue","variations","scheduleStepIndex","cumulative","matchedRv","rv","variation","evaluateCondition","condition","contextKind","attributeKey","operator","value","contextValue","evaluateConditions","conditions","matchesIndividual","entries","entry","evaluateSegment","segment","evaluateTarget","target","segments","resolveTargetVariation","active","resolveDefaultVariation","flag","buildRuleMatchReason","buildRolloutReason","rolloutResult","evaluateFlag","options","sortedTargets","a","b","resolved","reasons","SDK_VERSION","g","doc","EventBuffer","event","batch","payload","DEFAULT_BASE_URL","HTTPS_RE","HTTP_RE","detectPlatform","nav","win","SDK_PLATFORM","proc","hasHrtime","nowNs","elapsedUs","start","end","GradualClient","hasWebSocket","initResponse","error","initData","headers","response","etag","previousVersion","cb","resolve","reject","wsUrl","ws","newSnapshot","err","delay","merged","allKinds","kind","key","snapshot","startTime","output","errorDetail","flagVersion","durationUs","ruleMatch","r","evaluatedAt","traceId","params","contextKinds","contextKeys","isAnonymous","result","callback","createGradual"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n EvalOutput,\n EvaluationContext,\n Reason,\n SnapshotFlag,\n SnapshotIndividualEntry,\n SnapshotRollout,\n SnapshotRolloutVariation,\n SnapshotRuleCondition,\n SnapshotScheduleStep,\n SnapshotSegment,\n SnapshotTarget,\n SnapshotVariation,\n} from \"./types\";\n\nfunction hashString(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n // biome-ignore lint/suspicious/noBitwiseOperators: intentional hash algorithm using bitwise shift\n hash = (hash << 5) - hash + char;\n // biome-ignore lint/suspicious/noBitwiseOperators: converting to 32-bit integer\n hash |= 0;\n }\n return Math.abs(hash);\n}\n\nfunction getBucketValue(\n flagKey: string,\n context: EvaluationContext,\n rollout: SnapshotRollout,\n inputsUsed: Set<string>\n): number {\n inputsUsed.add(`${rollout.bucketContextKind}.${rollout.bucketAttributeKey}`);\n const bucketKey =\n context[rollout.bucketContextKind]?.[rollout.bucketAttributeKey];\n const seed = rollout.seed ?? \"\";\n const hashInput = `${flagKey}:${seed}:${String(bucketKey ?? \"anonymous\")}`;\n return hashString(hashInput) % 100_000;\n}\n\ninterface ActiveRollout {\n variations: SnapshotRolloutVariation[];\n stepIndex: number;\n}\n\nfunction resolveActiveRollout(\n rollout: SnapshotRollout,\n now: Date\n): ActiveRollout {\n if (!(rollout.schedule && rollout.startedAt)) {\n return { variations: rollout.variations, stepIndex: -1 };\n }\n\n const startedAt = new Date(rollout.startedAt).getTime();\n const elapsedMs = now.getTime() - startedAt;\n const elapsedMinutes = elapsedMs / 60_000;\n\n if (elapsedMinutes < 0) {\n return {\n variations: rollout.schedule[0]?.variations ?? rollout.variations,\n stepIndex: 0,\n };\n }\n\n let cumulativeMinutes = 0;\n for (let i = 0; i < rollout.schedule.length; i++) {\n const step = rollout.schedule[i] as SnapshotScheduleStep;\n if (step.durationMinutes === 0) {\n return { variations: step.variations, stepIndex: i };\n }\n cumulativeMinutes += step.durationMinutes;\n if (elapsedMinutes < cumulativeMinutes) {\n return { variations: step.variations, stepIndex: i };\n }\n }\n\n const lastStep = rollout.schedule.at(-1);\n return {\n variations: lastStep?.variations ?? rollout.variations,\n stepIndex: rollout.schedule.length - 1,\n };\n}\n\ninterface RolloutResult {\n variation: SnapshotVariation;\n variationKey: string;\n matchedWeight: number;\n bucketValue: number;\n scheduleStepIndex: number;\n}\n\nfunction selectVariationFromRollout(\n activeVariations: SnapshotRolloutVariation[],\n bucketValue: number,\n variations: Record<string, SnapshotVariation>,\n scheduleStepIndex: number\n): RolloutResult | undefined {\n let cumulative = 0;\n let matchedRv: SnapshotRolloutVariation | undefined;\n\n for (const rv of activeVariations) {\n cumulative += rv.weight;\n if (bucketValue < cumulative) {\n matchedRv = rv;\n break;\n }\n }\n\n if (!matchedRv) {\n matchedRv = activeVariations.at(-1);\n }\n\n if (!matchedRv) {\n return undefined;\n }\n\n const variation = variations[matchedRv.variationKey];\n if (!variation) {\n return undefined;\n }\n\n return {\n variation,\n variationKey: matchedRv.variationKey,\n matchedWeight: matchedRv.weight,\n bucketValue,\n scheduleStepIndex,\n };\n}\n\nfunction evaluateCondition(\n condition: SnapshotRuleCondition,\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n const { contextKind, attributeKey, operator, value } = condition;\n inputsUsed.add(`${contextKind}.${attributeKey}`);\n const contextValue = context[contextKind]?.[attributeKey];\n\n switch (operator) {\n case \"equals\":\n return contextValue === value;\n\n case \"not_equals\":\n return contextValue !== value;\n\n case \"contains\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.includes(value);\n }\n if (Array.isArray(contextValue)) {\n return contextValue.includes(value);\n }\n return false;\n\n case \"not_contains\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return !contextValue.includes(value);\n }\n if (Array.isArray(contextValue)) {\n return !contextValue.includes(value);\n }\n return true;\n\n case \"starts_with\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.startsWith(value);\n }\n return false;\n\n case \"ends_with\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.endsWith(value);\n }\n return false;\n\n case \"greater_than\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue > value;\n }\n return false;\n\n case \"less_than\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue < value;\n }\n return false;\n\n case \"greater_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue >= value;\n }\n return false;\n\n case \"less_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue <= value;\n }\n return false;\n\n case \"in\":\n if (Array.isArray(value)) {\n return value.includes(contextValue);\n }\n return false;\n\n case \"not_in\":\n if (Array.isArray(value)) {\n return !value.includes(contextValue);\n }\n return true;\n\n case \"exists\":\n return contextValue !== undefined && contextValue !== null;\n\n case \"not_exists\":\n return contextValue === undefined || contextValue === null;\n\n default:\n return false;\n }\n}\n\nfunction evaluateConditions(\n conditions: SnapshotRuleCondition[],\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n return conditions.every((condition) =>\n evaluateCondition(condition, context, inputsUsed)\n );\n}\n\nfunction matchesIndividual(\n entries: SnapshotIndividualEntry[],\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n for (const entry of entries) {\n inputsUsed.add(`${entry.contextKind}.${entry.attributeKey}`);\n if (\n context[entry.contextKind]?.[entry.attributeKey] === entry.attributeValue\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction evaluateSegment(\n segment: SnapshotSegment,\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n // Priority 1: Excluded individuals never match\n if (\n segment.excluded?.length &&\n matchesIndividual(segment.excluded, context, inputsUsed)\n ) {\n return false;\n }\n\n // Priority 2: Included individuals always match\n if (\n segment.included?.length &&\n matchesIndividual(segment.included, context, inputsUsed)\n ) {\n return true;\n }\n\n // Priority 3: Evaluate conditions (empty conditions = no match)\n if (segment.conditions.length === 0) {\n return false;\n }\n return evaluateConditions(segment.conditions, context, inputsUsed);\n}\n\nfunction evaluateTarget(\n target: SnapshotTarget,\n context: EvaluationContext,\n segments: Record<string, SnapshotSegment>,\n inputsUsed: Set<string>\n): boolean {\n switch (target.type) {\n case \"individual\":\n if (\n target.contextKind &&\n target.attributeKey &&\n target.attributeValue !== undefined\n ) {\n inputsUsed.add(`${target.contextKind}.${target.attributeKey}`);\n return (\n context[target.contextKind]?.[target.attributeKey] ===\n target.attributeValue\n );\n }\n return false;\n\n case \"rule\":\n if (target.conditions) {\n return evaluateConditions(target.conditions, context, inputsUsed);\n }\n return false;\n\n case \"segment\":\n if (target.segmentKey) {\n const segment = segments[target.segmentKey];\n if (segment) {\n return evaluateSegment(segment, context, inputsUsed);\n }\n }\n return false;\n\n default:\n return false;\n }\n}\n\nfunction resolveTargetVariation(\n target: SnapshotTarget,\n flagKey: string,\n context: EvaluationContext,\n variations: Record<string, SnapshotVariation>,\n inputsUsed: Set<string>,\n now: Date\n): RolloutResult | undefined {\n if (target.rollout) {\n const active = resolveActiveRollout(target.rollout, now);\n const bucketValue = getBucketValue(\n flagKey,\n context,\n target.rollout,\n inputsUsed\n );\n return selectVariationFromRollout(\n active.variations,\n bucketValue,\n variations,\n active.stepIndex\n );\n }\n\n if (target.variationKey) {\n const variation = variations[target.variationKey];\n if (variation) {\n return {\n variation,\n variationKey: target.variationKey,\n matchedWeight: 100_000,\n bucketValue: 0,\n scheduleStepIndex: -1,\n };\n }\n }\n\n return undefined;\n}\n\nfunction resolveDefaultVariation(\n flag: SnapshotFlag,\n context: EvaluationContext,\n inputsUsed: Set<string>,\n now: Date\n): RolloutResult | undefined {\n if (flag.defaultRollout) {\n const active = resolveActiveRollout(flag.defaultRollout, now);\n const bucketValue = getBucketValue(\n flag.key,\n context,\n flag.defaultRollout,\n inputsUsed\n );\n return selectVariationFromRollout(\n active.variations,\n bucketValue,\n flag.variations,\n active.stepIndex\n );\n }\n\n if (flag.defaultVariationKey) {\n const variation = flag.variations[flag.defaultVariationKey];\n if (variation) {\n return {\n variation,\n variationKey: flag.defaultVariationKey,\n matchedWeight: 100_000,\n bucketValue: 0,\n scheduleStepIndex: -1,\n };\n }\n }\n\n return undefined;\n}\n\nfunction buildRuleMatchReason(target: SnapshotTarget): Reason {\n return {\n type: \"rule_match\",\n ruleId: target.id ?? \"\",\n ruleName: target.name,\n };\n}\n\nfunction buildRolloutReason(rolloutResult: RolloutResult): Reason {\n if (rolloutResult.scheduleStepIndex >= 0) {\n return {\n type: \"gradual_rollout\",\n stepIndex: rolloutResult.scheduleStepIndex,\n percentage: rolloutResult.matchedWeight / 1000,\n bucket: rolloutResult.bucketValue,\n };\n }\n return {\n type: \"percentage_rollout\",\n percentage: rolloutResult.matchedWeight / 1000,\n bucket: rolloutResult.bucketValue,\n };\n}\n\nexport function evaluateFlag(\n flag: SnapshotFlag,\n context: EvaluationContext,\n segments: Record<string, SnapshotSegment>,\n options?: { now?: Date }\n): EvalOutput {\n if (!flag.enabled) {\n const offVariation = flag.variations[flag.offVariationKey];\n return {\n value: offVariation?.value,\n variationKey: flag.offVariationKey,\n reasons: [{ type: \"off\" }],\n inputsUsed: [],\n };\n }\n\n const now = options?.now ?? new Date();\n const inputsUsed = new Set<string>();\n\n const sortedTargets = [...flag.targets].sort(\n (a, b) => a.sortOrder - b.sortOrder\n );\n\n for (const target of sortedTargets) {\n if (evaluateTarget(target, context, segments, inputsUsed)) {\n const resolved = resolveTargetVariation(\n target,\n flag.key,\n context,\n flag.variations,\n inputsUsed,\n now\n );\n if (resolved) {\n const reasons: Reason[] = [buildRuleMatchReason(target)];\n if (target.rollout) {\n reasons.push(buildRolloutReason(resolved));\n }\n\n return {\n value: resolved.variation.value,\n variationKey: resolved.variationKey,\n reasons,\n matchedTargetName: target.name,\n inputsUsed: [...inputsUsed],\n };\n }\n }\n }\n\n const resolved = resolveDefaultVariation(flag, context, inputsUsed, now);\n if (resolved) {\n const reasons: Reason[] = [];\n if (flag.defaultRollout) {\n reasons.push(buildRolloutReason(resolved));\n }\n reasons.push({ type: \"default\" });\n\n return {\n value: resolved.variation.value,\n variationKey: resolved.variationKey,\n reasons,\n inputsUsed: [...inputsUsed],\n };\n }\n\n return {\n value: undefined,\n variationKey: undefined,\n reasons: [{ type: \"default\" }],\n inputsUsed: [...inputsUsed],\n };\n}\n","import type { EvaluationBatchPayload, EvaluationEvent } from \"./types\";\n\ndeclare const __SDK_VERSION__: string;\nexport const SDK_VERSION = __SDK_VERSION__;\n\ninterface EventBufferOptions {\n baseUrl: string;\n apiKey: string;\n meta: {\n projectId: string;\n organizationId: string;\n environmentId: string;\n sdkPlatform?: string;\n };\n flushIntervalMs: number;\n maxBatchSize: number;\n}\n\nconst g = globalThis as Record<string, unknown>;\nconst doc = g.document as\n | {\n visibilityState?: string;\n addEventListener?: (event: string, handler: () => void) => void;\n removeEventListener?: (event: string, handler: () => void) => void;\n }\n | undefined;\nexport class EventBuffer {\n private readonly events: EvaluationEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly options: EventBufferOptions;\n private readonly onVisibilityChange: (() => void) | null = null;\n\n constructor(options: EventBufferOptions) {\n this.options = options;\n this.timer = setInterval(() => this.flush(), this.options.flushIntervalMs);\n\n if (doc?.addEventListener) {\n this.onVisibilityChange = () => {\n if (doc.visibilityState === \"hidden\") {\n this.flushBeacon();\n }\n };\n doc.addEventListener(\"visibilitychange\", this.onVisibilityChange);\n }\n }\n\n push(event: EvaluationEvent): void {\n this.events.push(event);\n if (this.events.length >= this.options.maxBatchSize) {\n this.flush();\n }\n }\n\n private buildPayload(batch: EvaluationEvent[]): EvaluationBatchPayload {\n return {\n meta: {\n ...this.options.meta,\n sdkVersion: SDK_VERSION,\n },\n events: batch,\n };\n }\n\n flush(): void {\n if (this.events.length === 0) {\n return;\n }\n const batch = this.events.splice(0, this.options.maxBatchSize);\n const payload = this.buildPayload(batch);\n\n fetch(`${this.options.baseUrl}/sdk/evaluations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify(payload),\n }).catch(() => {\n // Fire-and-forget: silently drop failed events to prevent unbounded growth\n });\n }\n\n /**\n * Flush with keepalive flag for reliable delivery during page unload.\n * keepalive fetch survives page navigation like sendBeacon but supports headers.\n */\n private flushBeacon(): void {\n if (this.events.length === 0) {\n return;\n }\n\n const batch = this.events.splice(0, this.options.maxBatchSize);\n const payload = this.buildPayload(batch);\n\n fetch(`${this.options.baseUrl}/sdk/evaluations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify(payload),\n keepalive: true,\n }).catch(() => {\n // Fire-and-forget\n });\n }\n\n destroy(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n if (this.onVisibilityChange && doc?.removeEventListener) {\n doc.removeEventListener(\"visibilitychange\", this.onVisibilityChange);\n }\n this.flush();\n }\n}\n","import { evaluateFlag } from \"./evaluator\";\nimport { EventBuffer } from \"./event-buffer\";\nimport type {\n EnvironmentSnapshot,\n EvalOutput,\n EvaluationContext,\n EvaluationResult,\n FlagOptions,\n GradualOptions,\n IsEnabledOptions,\n Reason,\n} from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://worker.gradual.so/api/v1\";\nconst HTTPS_RE = /^https:\\/\\//;\nconst HTTP_RE = /^http:\\/\\//;\n\ntype SdkPlatform = \"browser\" | \"node\" | \"react-native\" | \"edge\" | \"unknown\";\n\nfunction detectPlatform(): SdkPlatform {\n try {\n const g = globalThis as Record<string, unknown>;\n const nav = g.navigator as\n | { product?: string; userAgent?: string }\n | undefined;\n if (nav && nav.product === \"ReactNative\") {\n return \"react-native\";\n }\n const win = g.window as { document?: unknown } | undefined;\n if (win && typeof win.document !== \"undefined\") {\n return \"browser\";\n }\n const proc = g.process as { versions?: { node?: string } } | undefined;\n if (proc?.versions?.node) {\n return \"node\";\n }\n if (typeof globalThis !== \"undefined\") {\n return \"edge\";\n }\n } catch {\n // Ignore detection errors\n }\n return \"unknown\";\n}\n\nconst SDK_PLATFORM = detectPlatform();\n\nconst proc = (globalThis as Record<string, unknown>).process as\n | { hrtime?: { bigint?: () => bigint } }\n | undefined;\nconst hasHrtime = typeof proc?.hrtime?.bigint === \"function\";\n\nfunction nowNs(): bigint | number {\n if (hasHrtime) {\n // biome-ignore lint/style/noNonNullAssertion: guarded by hasHrtime check\n return proc!.hrtime!.bigint!();\n }\n if (typeof performance !== \"undefined\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction elapsedUs(start: bigint | number): number {\n const end = nowNs();\n if (typeof start === \"bigint\" && typeof end === \"bigint\") {\n // hrtime bigint: nanoseconds → microseconds\n return Number((end - start) / 1000n);\n }\n // performance.now() ms or Date.now() ms → microseconds\n return Math.round(((end as number) - (start as number)) * 1000);\n}\n\nexport interface Gradual {\n /** Wait for the SDK to be ready (snapshot fetched) */\n ready(): Promise<void>;\n\n /** Check if the SDK is ready for sync access */\n isReady(): boolean;\n\n /** Check if a boolean flag is enabled */\n isEnabled(key: string, options?: IsEnabledOptions): Promise<boolean>;\n\n /** Get a flag value with type inference from fallback */\n get<T>(key: string, options: FlagOptions<T>): Promise<T>;\n\n /** Evaluate a flag and return the full structured result (also tracks the evaluation) */\n evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): Promise<EvaluationResult<T>>;\n\n /** Set persistent user context for all evaluations */\n identify(context: EvaluationContext): void;\n\n /** Clear the identified user context */\n reset(): void;\n\n /** Refresh the snapshot from the server */\n refresh(): Promise<void>;\n\n /** Get the current snapshot (for debugging) */\n getSnapshot(): EnvironmentSnapshot | null;\n\n /** Subscribe to snapshot updates from polling (returns unsubscribe function) */\n onUpdate(callback: () => void): () => void;\n\n /** Flush pending evaluation events and stop the event buffer */\n close(): void;\n\n /** Sync methods (throw if not ready) */\n sync: GradualSync;\n}\n\nexport interface GradualSync {\n /** Sync version of isEnabled (throws if not ready) */\n isEnabled(key: string, options?: IsEnabledOptions): boolean;\n\n /** Sync version of get (throws if not ready) */\n get<T>(key: string, options: FlagOptions<T>): T;\n\n /** Evaluate a flag without tracking. Use with track() for React-safe evaluation. */\n evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): EvaluationResult<T>;\n\n /** Manually track an evaluation that was produced by evaluate(). */\n track(\n key: string,\n result: EvaluationResult,\n context?: EvaluationContext\n ): void;\n}\n\nclass GradualClient implements Gradual {\n private readonly apiKey: string;\n private readonly environment: string;\n private readonly baseUrl: string;\n private readonly initPromise: Promise<void>;\n private snapshot: EnvironmentSnapshot | null = null;\n private identifiedContext: EvaluationContext = {};\n private readonly updateListeners: Set<() => void> = new Set();\n private eventBuffer: EventBuffer | null = null;\n private etag: string | null = null;\n private readonly eventsEnabled: boolean;\n private readonly eventsFlushIntervalMs: number;\n private readonly eventsMaxBatchSize: number;\n private readonly realtimeEnabled: boolean;\n private readonly pollingEnabled: boolean;\n private readonly pollingIntervalMs: number;\n private pollingTimer: ReturnType<typeof setInterval> | null = null;\n private ws: WebSocket | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectAttempts = 0;\n\n readonly sync: GradualSync;\n\n constructor(options: GradualOptions) {\n this.apiKey = options.apiKey;\n this.environment = options.environment;\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n this.eventsEnabled = options.events?.enabled ?? true;\n this.eventsFlushIntervalMs = options.events?.flushIntervalMs ?? 30_000;\n this.eventsMaxBatchSize = options.events?.maxBatchSize ?? 100;\n\n const hasWebSocket = typeof globalThis.WebSocket !== \"undefined\";\n this.realtimeEnabled = options.realtime?.enabled ?? hasWebSocket;\n this.pollingEnabled = options.polling?.enabled ?? true;\n this.pollingIntervalMs = options.polling?.intervalMs ?? 10_000;\n\n this.initPromise = this.init();\n\n this.sync = {\n isEnabled: this.isEnabledSync.bind(this),\n get: this.getSync.bind(this),\n evaluate: this.evaluateSync.bind(this),\n track: this.trackSync.bind(this),\n };\n }\n\n private async init(): Promise<void> {\n const initResponse = await fetch(`${this.baseUrl}/sdk/init`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ apiKey: this.apiKey }),\n });\n\n if (!initResponse.ok) {\n const error = await initResponse.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to initialize - ${(error as { error?: string }).error ?? initResponse.statusText}`\n );\n }\n\n const initData = (await initResponse.json()) as {\n valid: boolean;\n error?: string;\n };\n\n if (!initData.valid) {\n throw new Error(\n `Gradual: Invalid API key - ${initData.error ?? \"Unknown error\"}`\n );\n }\n\n if (this.realtimeEnabled) {\n await this.connectWebSocket();\n } else {\n await this.fetchSnapshot();\n this.startPolling();\n }\n\n this.initializeEventBuffer();\n }\n\n private initializeEventBuffer(): void {\n if (this.eventsEnabled && this.snapshot?.meta) {\n this.eventBuffer = new EventBuffer({\n baseUrl: this.baseUrl,\n apiKey: this.apiKey,\n meta: {\n projectId: this.snapshot.meta.projectId,\n organizationId: this.snapshot.meta.organizationId,\n environmentId: this.snapshot.meta.environmentId,\n sdkPlatform: SDK_PLATFORM,\n },\n flushIntervalMs: this.eventsFlushIntervalMs,\n maxBatchSize: this.eventsMaxBatchSize,\n });\n }\n }\n\n private async fetchSnapshot(): Promise<void> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n };\n if (this.etag) {\n headers[\"If-None-Match\"] = this.etag;\n }\n\n const response = await fetch(\n `${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,\n { headers }\n );\n\n if (response.status === 304) {\n return;\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to fetch snapshot - ${(error as { error?: string }).error ?? response.statusText}`\n );\n }\n\n const etag = response.headers.get(\"ETag\");\n if (etag) {\n this.etag = etag;\n }\n this.snapshot = (await response.json()) as EnvironmentSnapshot;\n }\n\n private startPolling(): void {\n if (!this.pollingEnabled) {\n return;\n }\n this.pollingTimer = setInterval(async () => {\n try {\n const previousVersion = this.snapshot?.version;\n await this.fetchSnapshot();\n if (this.snapshot && this.snapshot.version !== previousVersion) {\n for (const cb of this.updateListeners) {\n cb();\n }\n }\n } catch (error) {\n console.warn(\"Gradual: Polling refresh failed\", error);\n }\n }, this.pollingIntervalMs);\n }\n\n private connectWebSocket(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const wsBase = this.baseUrl\n .replace(HTTPS_RE, \"wss://\")\n .replace(HTTP_RE, \"ws://\");\n const wsUrl = `${wsBase}/sdk/connect?apiKey=${encodeURIComponent(this.apiKey)}&environment=${encodeURIComponent(this.environment)}`;\n\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n let resolved = false;\n\n ws.onmessage = (event: MessageEvent) => {\n try {\n const newSnapshot = JSON.parse(\n typeof event.data === \"string\" ? event.data : \"\"\n ) as EnvironmentSnapshot;\n const previousVersion = this.snapshot?.version;\n this.snapshot = newSnapshot;\n\n if (newSnapshot.version) {\n this.etag = `\"${newSnapshot.version}\"`;\n }\n\n if (!resolved) {\n resolved = true;\n this.reconnectAttempts = 0;\n resolve();\n } else if (newSnapshot.version !== previousVersion) {\n for (const cb of this.updateListeners) {\n cb();\n }\n }\n } catch (err) {\n console.warn(\"Gradual: Failed to parse WebSocket message\", err);\n if (!resolved) {\n resolved = true;\n this.fallbackToPolling(resolve, reject);\n }\n }\n };\n\n ws.onerror = () => {\n if (!resolved) {\n resolved = true;\n ws.close();\n this.ws = null;\n this.fallbackToPolling(resolve, reject);\n }\n };\n\n ws.onclose = () => {\n if (!resolved) {\n resolved = true;\n this.ws = null;\n this.fallbackToPolling(resolve, reject);\n return;\n }\n // Already connected — schedule reconnect\n this.ws = null;\n this.scheduleReconnect();\n };\n });\n }\n\n private fallbackToPolling(\n resolve: () => void,\n reject: (err: Error) => void\n ): void {\n console.warn(\"Gradual: WebSocket failed, falling back to polling\");\n this.fetchSnapshot()\n .then(() => {\n this.startPolling();\n resolve();\n })\n .catch(reject);\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) {\n return;\n }\n const delay = Math.min(1000 * 2 ** this.reconnectAttempts, 30_000);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.reconnectWebSocket();\n }, delay);\n }\n\n private reconnectWebSocket(): void {\n const wsBase = this.baseUrl\n .replace(HTTPS_RE, \"wss://\")\n .replace(HTTP_RE, \"ws://\");\n const wsUrl = `${wsBase}/sdk/connect?apiKey=${encodeURIComponent(this.apiKey)}&environment=${encodeURIComponent(this.environment)}`;\n\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n\n ws.onmessage = (event: MessageEvent) => {\n try {\n const newSnapshot = JSON.parse(\n typeof event.data === \"string\" ? event.data : \"\"\n ) as EnvironmentSnapshot;\n const previousVersion = this.snapshot?.version;\n this.snapshot = newSnapshot;\n this.reconnectAttempts = 0;\n\n if (newSnapshot.version !== previousVersion) {\n for (const cb of this.updateListeners) {\n cb();\n }\n }\n } catch (err) {\n console.warn(\"Gradual: Failed to parse WebSocket message\", err);\n }\n };\n\n ws.onerror = () => {\n // onclose will fire after this\n };\n\n ws.onclose = () => {\n this.ws = null;\n this.scheduleReconnect();\n };\n }\n\n private ensureReady(): EnvironmentSnapshot {\n if (!this.snapshot) {\n throw new Error(\n \"Gradual: SDK not ready. Use await ready() or async methods.\"\n );\n }\n return this.snapshot;\n }\n\n private mergeContext(options?: {\n context?: EvaluationContext;\n }): EvaluationContext {\n const merged: EvaluationContext = {};\n const allKinds = new Set([\n ...Object.keys(this.identifiedContext),\n ...Object.keys(options?.context ?? {}),\n ]);\n for (const kind of allKinds) {\n merged[kind] = {\n ...this.identifiedContext[kind],\n ...options?.context?.[kind],\n };\n }\n return merged;\n }\n\n private evaluateRaw(\n key: string,\n context: EvaluationContext\n ): {\n output: EvalOutput | null;\n snapshot: EnvironmentSnapshot;\n durationUs: number;\n } {\n const snapshot = this.ensureReady();\n if (!snapshot.flags) {\n return { output: null, snapshot, durationUs: 0 };\n }\n const flag = snapshot.flags[key];\n if (!flag) {\n return { output: null, snapshot, durationUs: 0 };\n }\n\n const startTime = nowNs();\n let output: EvalOutput;\n try {\n output = evaluateFlag(flag, context, snapshot.segments ?? {});\n } catch (err) {\n const errorDetail = err instanceof Error ? err.message : String(err);\n output = {\n value: undefined,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: errorDetail }],\n errorDetail,\n };\n }\n\n return { output, snapshot, durationUs: elapsedUs(startTime) };\n }\n\n private buildResult<T>(\n key: string,\n output: EvalOutput,\n flagVersion: number,\n durationUs?: number\n ): EvaluationResult<T> {\n const ruleMatch = output.reasons.find(\n (r): r is Extract<Reason, { type: \"rule_match\" }> =>\n r.type === \"rule_match\"\n );\n\n return {\n schemaVersion: 1,\n key,\n value: output.value as T,\n variationKey: output.variationKey,\n reasons: output.reasons,\n ruleId: ruleMatch?.ruleId,\n flagVersion,\n evaluatedAt: new Date().toISOString(),\n evaluationDurationUs: durationUs,\n inputsUsed: output.inputsUsed,\n traceId: crypto.randomUUID(),\n };\n }\n\n private evaluateAndTrack(key: string, context: EvaluationContext): unknown {\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n const evaluatedAt = new Date().toISOString();\n const traceId = crypto.randomUUID();\n\n if (!output) {\n this.trackEvent({\n key,\n variationKey: undefined,\n value: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n context,\n flagVersion: snapshot.version,\n schemaVersion: 1,\n evaluatedAt,\n traceId,\n });\n return undefined;\n }\n\n this.trackEvent({\n key,\n variationKey: output.variationKey,\n value: output.value,\n reasons: output.reasons,\n context,\n matchedTargetName: output.matchedTargetName,\n flagVersion: snapshot.version,\n errorDetail: output.errorDetail,\n evaluationDurationUs: durationUs,\n schemaVersion: 1,\n evaluatedAt,\n inputsUsed: output.inputsUsed,\n traceId,\n });\n\n return output.value;\n }\n\n private trackEvent(params: {\n key: string;\n variationKey: string | undefined;\n value: unknown;\n reasons: Reason[];\n evaluatedAt?: string;\n ruleId?: string;\n context: EvaluationContext;\n matchedTargetName?: string;\n flagVersion?: number;\n errorDetail?: string;\n evaluationDurationUs?: number;\n schemaVersion?: 1;\n policyVersion?: number;\n inputsUsed?: string[];\n traceId?: string;\n }): void {\n if (!this.eventBuffer) {\n return;\n }\n const { context } = params;\n const contextKinds = Object.keys(context);\n const contextKeys: Record<string, string[]> = {};\n for (const kind of contextKinds) {\n contextKeys[kind] = Object.keys(context[kind] ?? {});\n }\n\n const isAnonymous =\n contextKinds.length === 0 ||\n contextKinds.every(\n (kind) => Object.keys(context[kind] ?? {}).length === 0\n );\n\n this.eventBuffer.push({\n schemaVersion: params.schemaVersion ?? 1,\n key: params.key,\n variationKey: params.variationKey,\n value: params.value,\n reasons: params.reasons,\n evaluatedAt: params.evaluatedAt ?? new Date().toISOString(),\n ruleId: params.ruleId,\n flagVersion: params.flagVersion ?? 0,\n policyVersion: params.policyVersion,\n inputsUsed: params.inputsUsed,\n traceId: params.traceId,\n contextKinds,\n contextKeys,\n timestamp: Date.now(),\n matchedTargetName: params.matchedTargetName,\n errorDetail: params.errorDetail,\n evaluationDurationUs: params.evaluationDurationUs,\n isAnonymous,\n });\n }\n\n async ready(): Promise<void> {\n await this.initPromise;\n }\n\n isReady(): boolean {\n return this.snapshot !== null;\n }\n\n async isEnabled(key: string, options?: IsEnabledOptions): Promise<boolean> {\n await this.initPromise;\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return typeof value === \"boolean\" ? value : false;\n }\n\n async get<T>(key: string, options: FlagOptions<T>): Promise<T> {\n await this.initPromise;\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return value !== undefined && value !== null\n ? (value as T)\n : options.fallback;\n }\n\n async evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): Promise<EvaluationResult<T>> {\n await this.initPromise;\n const context = this.mergeContext(options);\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n\n if (!output) {\n const traceId = crypto.randomUUID();\n const evaluatedAt = new Date().toISOString();\n const result: EvaluationResult<T> = {\n schemaVersion: 1,\n key,\n value: undefined as T,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n flagVersion: snapshot.version,\n evaluatedAt,\n traceId,\n };\n this.trackEvent({\n key,\n variationKey: undefined,\n value: undefined,\n reasons: result.reasons,\n evaluatedAt,\n context,\n flagVersion: snapshot.version,\n schemaVersion: 1,\n traceId,\n });\n return result;\n }\n\n const result = this.buildResult<T>(\n key,\n output,\n snapshot.version,\n durationUs\n );\n\n this.trackEvent({\n key,\n variationKey: output.variationKey,\n value: output.value,\n reasons: output.reasons,\n evaluatedAt: result.evaluatedAt,\n ruleId: result.ruleId,\n context,\n matchedTargetName: output.matchedTargetName,\n flagVersion: snapshot.version,\n errorDetail: output.errorDetail,\n evaluationDurationUs: durationUs,\n schemaVersion: 1,\n inputsUsed: output.inputsUsed,\n traceId: result.traceId,\n });\n\n return result;\n }\n\n private isEnabledSync(key: string, options?: IsEnabledOptions): boolean {\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return typeof value === \"boolean\" ? value : false;\n }\n\n private getSync<T>(key: string, options: FlagOptions<T>): T {\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return value !== undefined && value !== null\n ? (value as T)\n : options.fallback;\n }\n\n private evaluateSync<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): EvaluationResult<T> {\n const context = this.mergeContext(options);\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n\n if (!output) {\n return {\n schemaVersion: 1,\n key,\n value: undefined as T,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n flagVersion: snapshot.version,\n evaluatedAt: new Date().toISOString(),\n evaluationDurationUs: durationUs,\n traceId: crypto.randomUUID(),\n };\n }\n\n return this.buildResult<T>(key, output, snapshot.version, durationUs);\n }\n\n private trackSync(\n key: string,\n result: EvaluationResult,\n context?: EvaluationContext\n ): void {\n const ruleMatch = result.reasons.find(\n (r): r is Extract<Reason, { type: \"rule_match\" }> =>\n r.type === \"rule_match\"\n );\n\n this.trackEvent({\n key,\n variationKey: result.variationKey,\n value: result.value,\n reasons: result.reasons,\n evaluatedAt: result.evaluatedAt,\n ruleId: result.ruleId,\n context: this.mergeContext({ context }),\n matchedTargetName: ruleMatch?.ruleName,\n flagVersion: result.flagVersion,\n evaluationDurationUs: result.evaluationDurationUs,\n schemaVersion: result.schemaVersion,\n policyVersion: result.policyVersion,\n inputsUsed: result.inputsUsed,\n traceId: result.traceId,\n });\n }\n\n identify(context: EvaluationContext): void {\n this.identifiedContext = { ...context };\n }\n\n reset(): void {\n this.identifiedContext = {};\n }\n\n async refresh(): Promise<void> {\n await this.fetchSnapshot();\n }\n\n getSnapshot(): EnvironmentSnapshot | null {\n return this.snapshot;\n }\n\n onUpdate(callback: () => void): () => void {\n this.updateListeners.add(callback);\n return () => this.updateListeners.delete(callback);\n }\n\n close(): void {\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.pollingTimer) {\n clearInterval(this.pollingTimer);\n this.pollingTimer = null;\n }\n if (this.eventBuffer) {\n this.eventBuffer.destroy();\n this.eventBuffer = null;\n }\n }\n}\n\n/**\n * Create a Gradual feature flag client\n *\n * @example\n * ```ts\n * const gradual = createGradual({\n * apiKey: 'gra_xxx',\n * environment: 'production'\n * })\n *\n * // Boolean flags\n * const enabled = await gradual.isEnabled('new-feature')\n *\n * // Typed values (inferred from fallback)\n * const theme = await gradual.get('theme', { fallback: 'dark' })\n *\n * // Full structured result\n * const result = await gradual.evaluate('new-feature')\n * // result.value, result.reasons, result.ruleId, result.flagVersion\n *\n * // With user context\n * gradual.identify({ userId: '123', plan: 'pro' })\n * const proFeature = await gradual.isEnabled('pro-feature')\n * ```\n */\nexport function createGradual(options: GradualOptions): Gradual {\n return new GradualClient(options);\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -78,11 +78,15 @@ interface PollingOptions {
|
|
|
78
78
|
enabled?: boolean;
|
|
79
79
|
intervalMs?: number;
|
|
80
80
|
}
|
|
81
|
+
interface RealtimeOptions {
|
|
82
|
+
enabled?: boolean;
|
|
83
|
+
}
|
|
81
84
|
interface GradualOptions {
|
|
82
85
|
apiKey: string;
|
|
83
86
|
environment: string;
|
|
84
87
|
baseUrl?: string;
|
|
85
88
|
polling?: PollingOptions;
|
|
89
|
+
realtime?: RealtimeOptions;
|
|
86
90
|
events?: EventsOptions;
|
|
87
91
|
}
|
|
88
92
|
interface FlagOptions<T> {
|
|
@@ -231,4 +235,4 @@ declare function evaluateFlag(flag: SnapshotFlag, context: EvaluationContext, se
|
|
|
231
235
|
now?: Date;
|
|
232
236
|
}): EvalOutput;
|
|
233
237
|
|
|
234
|
-
export { type EnvironmentSnapshot, type EvalOutput, type EvaluationBatchPayload, type EvaluationContext, type EvaluationEvent, type EvaluationResult, type EventsOptions, type FlagOptions, type Gradual, type GradualOptions, type GradualSync, type IsEnabledOptions, type PollingOptions, type Reason, type SnapshotFlag, type SnapshotRollout, type SnapshotRolloutVariation, type SnapshotRuleCondition, type SnapshotScheduleStep, type SnapshotSegment, type SnapshotTarget, type SnapshotVariation, type TargetingOperator, createGradual, evaluateFlag };
|
|
238
|
+
export { type EnvironmentSnapshot, type EvalOutput, type EvaluationBatchPayload, type EvaluationContext, type EvaluationEvent, type EvaluationResult, type EventsOptions, type FlagOptions, type Gradual, type GradualOptions, type GradualSync, type IsEnabledOptions, type PollingOptions, type RealtimeOptions, type Reason, type SnapshotFlag, type SnapshotRollout, type SnapshotRolloutVariation, type SnapshotRuleCondition, type SnapshotScheduleStep, type SnapshotSegment, type SnapshotTarget, type SnapshotVariation, type TargetingOperator, createGradual, evaluateFlag };
|
package/dist/index.d.ts
CHANGED
|
@@ -78,11 +78,15 @@ interface PollingOptions {
|
|
|
78
78
|
enabled?: boolean;
|
|
79
79
|
intervalMs?: number;
|
|
80
80
|
}
|
|
81
|
+
interface RealtimeOptions {
|
|
82
|
+
enabled?: boolean;
|
|
83
|
+
}
|
|
81
84
|
interface GradualOptions {
|
|
82
85
|
apiKey: string;
|
|
83
86
|
environment: string;
|
|
84
87
|
baseUrl?: string;
|
|
85
88
|
polling?: PollingOptions;
|
|
89
|
+
realtime?: RealtimeOptions;
|
|
86
90
|
events?: EventsOptions;
|
|
87
91
|
}
|
|
88
92
|
interface FlagOptions<T> {
|
|
@@ -231,4 +235,4 @@ declare function evaluateFlag(flag: SnapshotFlag, context: EvaluationContext, se
|
|
|
231
235
|
now?: Date;
|
|
232
236
|
}): EvalOutput;
|
|
233
237
|
|
|
234
|
-
export { type EnvironmentSnapshot, type EvalOutput, type EvaluationBatchPayload, type EvaluationContext, type EvaluationEvent, type EvaluationResult, type EventsOptions, type FlagOptions, type Gradual, type GradualOptions, type GradualSync, type IsEnabledOptions, type PollingOptions, type Reason, type SnapshotFlag, type SnapshotRollout, type SnapshotRolloutVariation, type SnapshotRuleCondition, type SnapshotScheduleStep, type SnapshotSegment, type SnapshotTarget, type SnapshotVariation, type TargetingOperator, createGradual, evaluateFlag };
|
|
238
|
+
export { type EnvironmentSnapshot, type EvalOutput, type EvaluationBatchPayload, type EvaluationContext, type EvaluationEvent, type EvaluationResult, type EventsOptions, type FlagOptions, type Gradual, type GradualOptions, type GradualSync, type IsEnabledOptions, type PollingOptions, type RealtimeOptions, type Reason, type SnapshotFlag, type SnapshotRollout, type SnapshotRolloutVariation, type SnapshotRuleCondition, type SnapshotScheduleStep, type SnapshotSegment, type SnapshotTarget, type SnapshotVariation, type TargetingOperator, createGradual, evaluateFlag };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
function I(n){let e=0;for(let t=0;t<n.length;t++){let a=n.charCodeAt(t);e=(e<<5)-e+a,e|=0;}return Math.abs(e)}function g(n,e,t,a){a.add(`${t.bucketContextKind}.${t.bucketAttributeKey}`);let i=e[t.bucketContextKind]?.[t.bucketAttributeKey],o=t.seed??"",r=`${n}:${o}:${String(i??"anonymous")}`;return I(r)%1e5}function m(n,e){if(!(n.schedule&&n.startedAt))return {variations:n.variations,stepIndex:-1};let t=new Date(n.startedAt).getTime(),i=(e.getTime()-t)/6e4;if(i<0)return {variations:n.schedule[0]?.variations??n.variations,stepIndex:0};let o=0;for(let s=0;s<n.schedule.length;s++){let u=n.schedule[s];if(u.durationMinutes===0)return {variations:u.variations,stepIndex:s};if(o+=u.durationMinutes,i<o)return {variations:u.variations,stepIndex:s}}return {variations:n.schedule.at(-1)?.variations??n.variations,stepIndex:n.schedule.length-1}}function b(n,e,t,a){let i=0,o;for(let s of n)if(i+=s.weight,e<i){o=s;break}if(o||(o=n.at(-1)),!o)return;let r=t[o.variationKey];if(r)return {variation:r,variationKey:o.variationKey,matchedWeight:o.weight,bucketValue:e,scheduleStepIndex:a}}function R(n,e,t){let{contextKind:a,attributeKey:i,operator:o,value:r}=n;t.add(`${a}.${i}`);let s=e[a]?.[i];switch(o){case "equals":return s===r;case "not_equals":return s!==r;case "contains":return typeof s=="string"&&typeof r=="string"||Array.isArray(s)?s.includes(r):false;case "not_contains":return typeof s=="string"&&typeof r=="string"||Array.isArray(s)?!s.includes(r):true;case "starts_with":return typeof s=="string"&&typeof r=="string"?s.startsWith(r):false;case "ends_with":return typeof s=="string"&&typeof r=="string"?s.endsWith(r):false;case "greater_than":return typeof s=="number"&&typeof r=="number"?s>r:false;case "less_than":return typeof s=="number"&&typeof r=="number"?s<r:false;case "greater_than_or_equal":return typeof s=="number"&&typeof r=="number"?s>=r:false;case "less_than_or_equal":return typeof s=="number"&&typeof r=="number"?s<=r:false;case "in":return Array.isArray(r)?r.includes(s):false;case "not_in":return Array.isArray(r)?!r.includes(s):true;case "exists":return s!=null;case "not_exists":return s==null;default:return false}}function S(n,e,t){return n.every(a=>R(a,e,t))}function f(n,e,t){for(let a of n)if(t.add(`${a.contextKind}.${a.attributeKey}`),e[a.contextKind]?.[a.attributeKey]===a.attributeValue)return true;return false}function T(n,e,t){return n.excluded?.length&&f(n.excluded,e,t)?false:n.included?.length&&f(n.included,e,t)?true:n.conditions.length===0?false:S(n.conditions,e,t)}function K(n,e,t,a){switch(n.type){case "individual":return n.contextKind&&n.attributeKey&&n.attributeValue!==void 0?(a.add(`${n.contextKind}.${n.attributeKey}`),e[n.contextKind]?.[n.attributeKey]===n.attributeValue):false;case "rule":return n.conditions?S(n.conditions,e,a):false;case "segment":if(n.segmentKey){let i=t[n.segmentKey];if(i)return T(i,e,a)}return false;default:return false}}function w(n,e,t,a,i,o){if(n.rollout){let r=m(n.rollout,o),s=g(e,t,n.rollout,i);return b(r.variations,s,a,r.stepIndex)}if(n.variationKey){let r=a[n.variationKey];if(r)return {variation:r,variationKey:n.variationKey,matchedWeight:1e5,bucketValue:0,scheduleStepIndex:-1}}}function k(n,e,t,a){if(n.defaultRollout){let i=m(n.defaultRollout,a),o=g(n.key,e,n.defaultRollout,t);return b(i.variations,o,n.variations,i.stepIndex)}if(n.defaultVariationKey){let i=n.variations[n.defaultVariationKey];if(i)return {variation:i,variationKey:n.defaultVariationKey,matchedWeight:1e5,bucketValue:0,scheduleStepIndex:-1}}}function V(n){return {type:"rule_match",ruleId:n.id??"",ruleName:n.name}}function y(n){return n.scheduleStepIndex>=0?{type:"gradual_rollout",stepIndex:n.scheduleStepIndex,percentage:n.matchedWeight/1e3,bucket:n.bucketValue}:{type:"percentage_rollout",percentage:n.matchedWeight/1e3,bucket:n.bucketValue}}function v(n,e,t,a){if(!n.enabled)return {value:n.variations[n.offVariationKey]?.value,variationKey:n.offVariationKey,reasons:[{type:"off"}],inputsUsed:[]};let i=a?.now??new Date,o=new Set,r=[...n.targets].sort((u,l)=>u.sortOrder-l.sortOrder);for(let u of r)if(K(u,e,t,o)){let l=w(u,n.key,e,n.variations,o,i);if(l){let d=[V(u)];return u.rollout&&d.push(y(l)),{value:l.variation.value,variationKey:l.variationKey,reasons:d,matchedTargetName:u.name,inputsUsed:[...o]}}}let s=k(n,e,o,i);if(s){let u=[];return n.defaultRollout&&u.push(y(s)),u.push({type:"default"}),{value:s.variation.value,variationKey:s.variationKey,reasons:u,inputsUsed:[...o]}}return {value:void 0,variationKey:void 0,reasons:[{type:"default"}],inputsUsed:[...o]}}var U="0.8.7",C=globalThis,c=C.document,h=class{events=[];timer=null;options;onVisibilityChange=null;constructor(e){this.options=e,this.timer=setInterval(()=>this.flush(),this.options.flushIntervalMs),c?.addEventListener&&(this.onVisibilityChange=()=>{c.visibilityState==="hidden"&&this.flushBeacon();},c.addEventListener("visibilitychange",this.onVisibilityChange));}push(e){this.events.push(e),this.events.length>=this.options.maxBatchSize&&this.flush();}buildPayload(e){return {meta:{...this.options.meta,sdkVersion:U},events:e}}flush(){if(this.events.length===0)return;let e=this.events.splice(0,this.options.maxBatchSize),t=this.buildPayload(e);fetch(`${this.options.baseUrl}/sdk/evaluations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:JSON.stringify(t)}).catch(()=>{});}flushBeacon(){if(this.events.length===0)return;let e=this.events.splice(0,this.options.maxBatchSize),t=this.buildPayload(e);fetch(`${this.options.baseUrl}/sdk/evaluations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:JSON.stringify(t),keepalive:true}).catch(()=>{});}destroy(){this.timer&&(clearInterval(this.timer),this.timer=null),this.onVisibilityChange&&c?.removeEventListener&&c.removeEventListener("visibilitychange",this.onVisibilityChange),this.flush();}};var O="https://worker.gradual.so/api/v1";function _(){try{let n=globalThis,e=n.navigator;if(e&&e.product==="ReactNative")return "react-native";let t=n.window;if(t&&typeof t.document<"u")return "browser";if(n.process?.versions?.node)return "node";if(typeof globalThis<"u")return "edge"}catch{}return "unknown"}var A=_(),E=globalThis.process,D=typeof E?.hrtime?.bigint=="function";function x(){return D?E.hrtime.bigint():typeof performance<"u"?performance.now():Date.now()}function P(n){let e=x();return typeof n=="bigint"&&typeof e=="bigint"?Number((e-n)/1000n):Math.round((e-n)*1e3)}var p=class{apiKey;environment;baseUrl;initPromise;snapshot=null;identifiedContext={};updateListeners=new Set;eventBuffer=null;etag=null;eventsEnabled;eventsFlushIntervalMs;eventsMaxBatchSize;sync;constructor(e){this.apiKey=e.apiKey,this.environment=e.environment,this.baseUrl=e.baseUrl??O,this.eventsEnabled=e.events?.enabled??true,this.eventsFlushIntervalMs=e.events?.flushIntervalMs??3e4,this.eventsMaxBatchSize=e.events?.maxBatchSize??100,this.initPromise=this.init(),this.sync={isEnabled:this.isEnabledSync.bind(this),get:this.getSync.bind(this),evaluate:this.evaluateSync.bind(this),track:this.trackSync.bind(this)};let t=e.polling?.enabled??true,a=e.polling?.intervalMs??1e4;t&&this.initPromise.then(()=>{setInterval(async()=>{try{let i=this.snapshot?.version;if(await this.refresh(),this.snapshot&&this.snapshot.version!==i)for(let o of this.updateListeners)o();}catch(i){console.warn("Gradual: Polling refresh failed",i);}},a);});}async init(){let e=await fetch(`${this.baseUrl}/sdk/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:this.apiKey})});if(!e.ok){let o=await e.json().catch(()=>({}));throw new Error(`Gradual: Failed to initialize - ${o.error??e.statusText}`)}let t=await e.json();if(!t.valid)throw new Error(`Gradual: Invalid API key - ${t.error??"Unknown error"}`);let a=await fetch(`${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,{headers:{Authorization:`Bearer ${this.apiKey}`}});if(!a.ok){let o=await a.json().catch(()=>({}));throw new Error(`Gradual: Failed to fetch snapshot - ${o.error??a.statusText}`)}let i=a.headers.get("ETag");i&&(this.etag=i),this.snapshot=await a.json(),this.eventsEnabled&&this.snapshot.meta&&(this.eventBuffer=new h({baseUrl:this.baseUrl,apiKey:this.apiKey,meta:{projectId:this.snapshot.meta.projectId,organizationId:this.snapshot.meta.organizationId,environmentId:this.snapshot.meta.environmentId,sdkPlatform:A},flushIntervalMs:this.eventsFlushIntervalMs,maxBatchSize:this.eventsMaxBatchSize}));}ensureReady(){if(!this.snapshot)throw new Error("Gradual: SDK not ready. Use await ready() or async methods.");return this.snapshot}mergeContext(e){let t={},a=new Set([...Object.keys(this.identifiedContext),...Object.keys(e?.context??{})]);for(let i of a)t[i]={...this.identifiedContext[i],...e?.context?.[i]};return t}evaluateRaw(e,t){let a=this.ensureReady();if(!a.flags)return {output:null,snapshot:a,durationUs:0};let i=a.flags[e];if(!i)return {output:null,snapshot:a,durationUs:0};let o=x(),r;try{r=v(i,t,a.segments??{});}catch(s){let u=s instanceof Error?s.message:String(s);r={value:void 0,variationKey:void 0,reasons:[{type:"error",detail:u}],errorDetail:u};}return {output:r,snapshot:a,durationUs:P(o)}}buildResult(e,t,a,i){let o=t.reasons.find(r=>r.type==="rule_match");return {schemaVersion:1,key:e,value:t.value,variationKey:t.variationKey,reasons:t.reasons,ruleId:o?.ruleId,flagVersion:a,evaluatedAt:new Date().toISOString(),evaluationDurationUs:i,inputsUsed:t.inputsUsed,traceId:crypto.randomUUID()}}evaluateAndTrack(e,t){let{output:a,snapshot:i,durationUs:o}=this.evaluateRaw(e,t),r=new Date().toISOString(),s=crypto.randomUUID();if(!a){this.trackEvent({key:e,variationKey:void 0,value:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],context:t,flagVersion:i.version,schemaVersion:1,evaluatedAt:r,traceId:s});return}return this.trackEvent({key:e,variationKey:a.variationKey,value:a.value,reasons:a.reasons,context:t,matchedTargetName:a.matchedTargetName,flagVersion:i.version,errorDetail:a.errorDetail,evaluationDurationUs:o,schemaVersion:1,evaluatedAt:r,inputsUsed:a.inputsUsed,traceId:s}),a.value}trackEvent(e){if(!this.eventBuffer)return;let{context:t}=e,a=Object.keys(t),i={};for(let r of a)i[r]=Object.keys(t[r]??{});let o=a.length===0||a.every(r=>Object.keys(t[r]??{}).length===0);this.eventBuffer.push({schemaVersion:e.schemaVersion??1,key:e.key,variationKey:e.variationKey,value:e.value,reasons:e.reasons,evaluatedAt:e.evaluatedAt??new Date().toISOString(),ruleId:e.ruleId,flagVersion:e.flagVersion??0,policyVersion:e.policyVersion,inputsUsed:e.inputsUsed,traceId:e.traceId,contextKinds:a,contextKeys:i,timestamp:Date.now(),matchedTargetName:e.matchedTargetName,errorDetail:e.errorDetail,evaluationDurationUs:e.evaluationDurationUs,isAnonymous:o});}async ready(){await this.initPromise;}isReady(){return this.snapshot!==null}async isEnabled(e,t){await this.initPromise;let a=this.evaluateAndTrack(e,this.mergeContext(t));return typeof a=="boolean"?a:false}async get(e,t){await this.initPromise;let a=this.evaluateAndTrack(e,this.mergeContext(t));return a??t.fallback}async evaluate(e,t){await this.initPromise;let a=this.mergeContext(t),{output:i,snapshot:o,durationUs:r}=this.evaluateRaw(e,a);if(!i){let u=crypto.randomUUID(),l=new Date().toISOString(),d={schemaVersion:1,key:e,value:void 0,variationKey:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],flagVersion:o.version,evaluatedAt:l,traceId:u};return this.trackEvent({key:e,variationKey:void 0,value:void 0,reasons:d.reasons,evaluatedAt:l,context:a,flagVersion:o.version,schemaVersion:1,traceId:u}),d}let s=this.buildResult(e,i,o.version,r);return this.trackEvent({key:e,variationKey:i.variationKey,value:i.value,reasons:i.reasons,evaluatedAt:s.evaluatedAt,ruleId:s.ruleId,context:a,matchedTargetName:i.matchedTargetName,flagVersion:o.version,errorDetail:i.errorDetail,evaluationDurationUs:r,schemaVersion:1,inputsUsed:i.inputsUsed,traceId:s.traceId}),s}isEnabledSync(e,t){let a=this.evaluateAndTrack(e,this.mergeContext(t));return typeof a=="boolean"?a:false}getSync(e,t){let a=this.evaluateAndTrack(e,this.mergeContext(t));return a??t.fallback}evaluateSync(e,t){let a=this.mergeContext(t),{output:i,snapshot:o,durationUs:r}=this.evaluateRaw(e,a);return i?this.buildResult(e,i,o.version,r):{schemaVersion:1,key:e,value:void 0,variationKey:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],flagVersion:o.version,evaluatedAt:new Date().toISOString(),evaluationDurationUs:r,traceId:crypto.randomUUID()}}trackSync(e,t,a){let i=t.reasons.find(o=>o.type==="rule_match");this.trackEvent({key:e,variationKey:t.variationKey,value:t.value,reasons:t.reasons,evaluatedAt:t.evaluatedAt,ruleId:t.ruleId,context:this.mergeContext({context:a}),matchedTargetName:i?.ruleName,flagVersion:t.flagVersion,evaluationDurationUs:t.evaluationDurationUs,schemaVersion:t.schemaVersion,policyVersion:t.policyVersion,inputsUsed:t.inputsUsed,traceId:t.traceId});}identify(e){this.identifiedContext={...e};}reset(){this.identifiedContext={};}async refresh(){let e={Authorization:`Bearer ${this.apiKey}`};this.etag&&(e["If-None-Match"]=this.etag);let t=await fetch(`${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,{headers:e});if(t.status===304)return;if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(`Gradual: Failed to refresh - ${i.error??t.statusText}`)}let a=t.headers.get("ETag");a&&(this.etag=a),this.snapshot=await t.json();}getSnapshot(){return this.snapshot}onUpdate(e){return this.updateListeners.add(e),()=>this.updateListeners.delete(e)}close(){this.eventBuffer&&(this.eventBuffer.destroy(),this.eventBuffer=null);}};function B(n){return new p(n)}
|
|
2
|
-
export{
|
|
1
|
+
function R(n){let e=0;for(let t=0;t<n.length;t++){let i=n.charCodeAt(t);e=(e<<5)-e+i,e|=0;}return Math.abs(e)}function m(n,e,t,i){i.add(`${t.bucketContextKind}.${t.bucketAttributeKey}`);let o=e[t.bucketContextKind]?.[t.bucketAttributeKey],r=t.seed??"",a=`${n}:${r}:${String(o??"anonymous")}`;return R(a)%1e5}function g(n,e){if(!(n.schedule&&n.startedAt))return {variations:n.variations,stepIndex:-1};let t=new Date(n.startedAt).getTime(),o=(e.getTime()-t)/6e4;if(o<0)return {variations:n.schedule[0]?.variations??n.variations,stepIndex:0};let r=0;for(let s=0;s<n.schedule.length;s++){let l=n.schedule[s];if(l.durationMinutes===0)return {variations:l.variations,stepIndex:s};if(r+=l.durationMinutes,o<r)return {variations:l.variations,stepIndex:s}}return {variations:n.schedule.at(-1)?.variations??n.variations,stepIndex:n.schedule.length-1}}function b(n,e,t,i){let o=0,r;for(let s of n)if(o+=s.weight,e<o){r=s;break}if(r||(r=n.at(-1)),!r)return;let a=t[r.variationKey];if(a)return {variation:a,variationKey:r.variationKey,matchedWeight:r.weight,bucketValue:e,scheduleStepIndex:i}}function I(n,e,t){let{contextKind:i,attributeKey:o,operator:r,value:a}=n;t.add(`${i}.${o}`);let s=e[i]?.[o];switch(r){case "equals":return s===a;case "not_equals":return s!==a;case "contains":return typeof s=="string"&&typeof a=="string"||Array.isArray(s)?s.includes(a):false;case "not_contains":return typeof s=="string"&&typeof a=="string"||Array.isArray(s)?!s.includes(a):true;case "starts_with":return typeof s=="string"&&typeof a=="string"?s.startsWith(a):false;case "ends_with":return typeof s=="string"&&typeof a=="string"?s.endsWith(a):false;case "greater_than":return typeof s=="number"&&typeof a=="number"?s>a:false;case "less_than":return typeof s=="number"&&typeof a=="number"?s<a:false;case "greater_than_or_equal":return typeof s=="number"&&typeof a=="number"?s>=a:false;case "less_than_or_equal":return typeof s=="number"&&typeof a=="number"?s<=a:false;case "in":return Array.isArray(a)?a.includes(s):false;case "not_in":return Array.isArray(a)?!a.includes(s):true;case "exists":return s!=null;case "not_exists":return s==null;default:return false}}function S(n,e,t){return n.every(i=>I(i,e,t))}function f(n,e,t){for(let i of n)if(t.add(`${i.contextKind}.${i.attributeKey}`),e[i.contextKind]?.[i.attributeKey]===i.attributeValue)return true;return false}function k(n,e,t){return n.excluded?.length&&f(n.excluded,e,t)?false:n.included?.length&&f(n.included,e,t)?true:n.conditions.length===0?false:S(n.conditions,e,t)}function K(n,e,t,i){switch(n.type){case "individual":return n.contextKind&&n.attributeKey&&n.attributeValue!==void 0?(i.add(`${n.contextKind}.${n.attributeKey}`),e[n.contextKind]?.[n.attributeKey]===n.attributeValue):false;case "rule":return n.conditions?S(n.conditions,e,i):false;case "segment":if(n.segmentKey){let o=t[n.segmentKey];if(o)return k(o,e,i)}return false;default:return false}}function V(n,e,t,i,o,r){if(n.rollout){let a=g(n.rollout,r),s=m(e,t,n.rollout,o);return b(a.variations,s,i,a.stepIndex)}if(n.variationKey){let a=i[n.variationKey];if(a)return {variation:a,variationKey:n.variationKey,matchedWeight:1e5,bucketValue:0,scheduleStepIndex:-1}}}function U(n,e,t,i){if(n.defaultRollout){let o=g(n.defaultRollout,i),r=m(n.key,e,n.defaultRollout,t);return b(o.variations,r,n.variations,o.stepIndex)}if(n.defaultVariationKey){let o=n.variations[n.defaultVariationKey];if(o)return {variation:o,variationKey:n.defaultVariationKey,matchedWeight:1e5,bucketValue:0,scheduleStepIndex:-1}}}function C(n){return {type:"rule_match",ruleId:n.id??"",ruleName:n.name}}function y(n){return n.scheduleStepIndex>=0?{type:"gradual_rollout",stepIndex:n.scheduleStepIndex,percentage:n.matchedWeight/1e3,bucket:n.bucketValue}:{type:"percentage_rollout",percentage:n.matchedWeight/1e3,bucket:n.bucketValue}}function v(n,e,t,i){if(!n.enabled)return {value:n.variations[n.offVariationKey]?.value,variationKey:n.offVariationKey,reasons:[{type:"off"}],inputsUsed:[]};let o=i?.now??new Date,r=new Set,a=[...n.targets].sort((l,u)=>l.sortOrder-u.sortOrder);for(let l of a)if(K(l,e,t,r)){let u=V(l,n.key,e,n.variations,r,o);if(u){let d=[C(l)];return l.rollout&&d.push(y(u)),{value:u.variation.value,variationKey:u.variationKey,reasons:d,matchedTargetName:l.name,inputsUsed:[...r]}}}let s=U(n,e,r,o);if(s){let l=[];return n.defaultRollout&&l.push(y(s)),l.push({type:"default"}),{value:s.variation.value,variationKey:s.variationKey,reasons:l,inputsUsed:[...r]}}return {value:void 0,variationKey:void 0,reasons:[{type:"default"}],inputsUsed:[...r]}}var O="0.8.8",A=globalThis,c=A.document,h=class{events=[];timer=null;options;onVisibilityChange=null;constructor(e){this.options=e,this.timer=setInterval(()=>this.flush(),this.options.flushIntervalMs),c?.addEventListener&&(this.onVisibilityChange=()=>{c.visibilityState==="hidden"&&this.flushBeacon();},c.addEventListener("visibilitychange",this.onVisibilityChange));}push(e){this.events.push(e),this.events.length>=this.options.maxBatchSize&&this.flush();}buildPayload(e){return {meta:{...this.options.meta,sdkVersion:O},events:e}}flush(){if(this.events.length===0)return;let e=this.events.splice(0,this.options.maxBatchSize),t=this.buildPayload(e);fetch(`${this.options.baseUrl}/sdk/evaluations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:JSON.stringify(t)}).catch(()=>{});}flushBeacon(){if(this.events.length===0)return;let e=this.events.splice(0,this.options.maxBatchSize),t=this.buildPayload(e);fetch(`${this.options.baseUrl}/sdk/evaluations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`},body:JSON.stringify(t),keepalive:true}).catch(()=>{});}destroy(){this.timer&&(clearInterval(this.timer),this.timer=null),this.onVisibilityChange&&c?.removeEventListener&&c.removeEventListener("visibilitychange",this.onVisibilityChange),this.flush();}};var _="https://worker.gradual.so/api/v1",E=/^https:\/\//,w=/^http:\/\//;function P(){try{let n=globalThis,e=n.navigator;if(e&&e.product==="ReactNative")return "react-native";let t=n.window;if(t&&typeof t.document<"u")return "browser";if(n.process?.versions?.node)return "node";if(typeof globalThis<"u")return "edge"}catch{}return "unknown"}var D=P(),T=globalThis.process,B=typeof T?.hrtime?.bigint=="function";function x(){return B?T.hrtime.bigint():typeof performance<"u"?performance.now():Date.now()}function M(n){let e=x();return typeof n=="bigint"&&typeof e=="bigint"?Number((e-n)/1000n):Math.round((e-n)*1e3)}var p=class{apiKey;environment;baseUrl;initPromise;snapshot=null;identifiedContext={};updateListeners=new Set;eventBuffer=null;etag=null;eventsEnabled;eventsFlushIntervalMs;eventsMaxBatchSize;realtimeEnabled;pollingEnabled;pollingIntervalMs;pollingTimer=null;ws=null;reconnectTimer=null;reconnectAttempts=0;sync;constructor(e){this.apiKey=e.apiKey,this.environment=e.environment,this.baseUrl=e.baseUrl??_,this.eventsEnabled=e.events?.enabled??true,this.eventsFlushIntervalMs=e.events?.flushIntervalMs??3e4,this.eventsMaxBatchSize=e.events?.maxBatchSize??100;let t=typeof globalThis.WebSocket<"u";this.realtimeEnabled=e.realtime?.enabled??t,this.pollingEnabled=e.polling?.enabled??true,this.pollingIntervalMs=e.polling?.intervalMs??1e4,this.initPromise=this.init(),this.sync={isEnabled:this.isEnabledSync.bind(this),get:this.getSync.bind(this),evaluate:this.evaluateSync.bind(this),track:this.trackSync.bind(this)};}async init(){let e=await fetch(`${this.baseUrl}/sdk/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:this.apiKey})});if(!e.ok){let i=await e.json().catch(()=>({}));throw new Error(`Gradual: Failed to initialize - ${i.error??e.statusText}`)}let t=await e.json();if(!t.valid)throw new Error(`Gradual: Invalid API key - ${t.error??"Unknown error"}`);this.realtimeEnabled?await this.connectWebSocket():(await this.fetchSnapshot(),this.startPolling()),this.initializeEventBuffer();}initializeEventBuffer(){this.eventsEnabled&&this.snapshot?.meta&&(this.eventBuffer=new h({baseUrl:this.baseUrl,apiKey:this.apiKey,meta:{projectId:this.snapshot.meta.projectId,organizationId:this.snapshot.meta.organizationId,environmentId:this.snapshot.meta.environmentId,sdkPlatform:D},flushIntervalMs:this.eventsFlushIntervalMs,maxBatchSize:this.eventsMaxBatchSize}));}async fetchSnapshot(){let e={Authorization:`Bearer ${this.apiKey}`};this.etag&&(e["If-None-Match"]=this.etag);let t=await fetch(`${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,{headers:e});if(t.status===304)return;if(!t.ok){let o=await t.json().catch(()=>({}));throw new Error(`Gradual: Failed to fetch snapshot - ${o.error??t.statusText}`)}let i=t.headers.get("ETag");i&&(this.etag=i),this.snapshot=await t.json();}startPolling(){this.pollingEnabled&&(this.pollingTimer=setInterval(async()=>{try{let e=this.snapshot?.version;if(await this.fetchSnapshot(),this.snapshot&&this.snapshot.version!==e)for(let t of this.updateListeners)t();}catch(e){console.warn("Gradual: Polling refresh failed",e);}},this.pollingIntervalMs));}connectWebSocket(){return new Promise((e,t)=>{let o=`${this.baseUrl.replace(E,"wss://").replace(w,"ws://")}/sdk/connect?apiKey=${encodeURIComponent(this.apiKey)}&environment=${encodeURIComponent(this.environment)}`,r=new WebSocket(o);this.ws=r;let a=false;r.onmessage=s=>{try{let l=JSON.parse(typeof s.data=="string"?s.data:""),u=this.snapshot?.version;if(this.snapshot=l,l.version&&(this.etag=`"${l.version}"`),!a)a=!0,this.reconnectAttempts=0,e();else if(l.version!==u)for(let d of this.updateListeners)d();}catch(l){console.warn("Gradual: Failed to parse WebSocket message",l),a||(a=true,this.fallbackToPolling(e,t));}},r.onerror=()=>{a||(a=true,r.close(),this.ws=null,this.fallbackToPolling(e,t));},r.onclose=()=>{if(!a){a=true,this.ws=null,this.fallbackToPolling(e,t);return}this.ws=null,this.scheduleReconnect();};})}fallbackToPolling(e,t){console.warn("Gradual: WebSocket failed, falling back to polling"),this.fetchSnapshot().then(()=>{this.startPolling(),e();}).catch(t);}scheduleReconnect(){if(this.reconnectTimer)return;let e=Math.min(1e3*2**this.reconnectAttempts,3e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.reconnectWebSocket();},e);}reconnectWebSocket(){let t=`${this.baseUrl.replace(E,"wss://").replace(w,"ws://")}/sdk/connect?apiKey=${encodeURIComponent(this.apiKey)}&environment=${encodeURIComponent(this.environment)}`,i=new WebSocket(t);this.ws=i,i.onmessage=o=>{try{let r=JSON.parse(typeof o.data=="string"?o.data:""),a=this.snapshot?.version;if(this.snapshot=r,this.reconnectAttempts=0,r.version!==a)for(let s of this.updateListeners)s();}catch(r){console.warn("Gradual: Failed to parse WebSocket message",r);}},i.onerror=()=>{},i.onclose=()=>{this.ws=null,this.scheduleReconnect();};}ensureReady(){if(!this.snapshot)throw new Error("Gradual: SDK not ready. Use await ready() or async methods.");return this.snapshot}mergeContext(e){let t={},i=new Set([...Object.keys(this.identifiedContext),...Object.keys(e?.context??{})]);for(let o of i)t[o]={...this.identifiedContext[o],...e?.context?.[o]};return t}evaluateRaw(e,t){let i=this.ensureReady();if(!i.flags)return {output:null,snapshot:i,durationUs:0};let o=i.flags[e];if(!o)return {output:null,snapshot:i,durationUs:0};let r=x(),a;try{a=v(o,t,i.segments??{});}catch(s){let l=s instanceof Error?s.message:String(s);a={value:void 0,variationKey:void 0,reasons:[{type:"error",detail:l}],errorDetail:l};}return {output:a,snapshot:i,durationUs:M(r)}}buildResult(e,t,i,o){let r=t.reasons.find(a=>a.type==="rule_match");return {schemaVersion:1,key:e,value:t.value,variationKey:t.variationKey,reasons:t.reasons,ruleId:r?.ruleId,flagVersion:i,evaluatedAt:new Date().toISOString(),evaluationDurationUs:o,inputsUsed:t.inputsUsed,traceId:crypto.randomUUID()}}evaluateAndTrack(e,t){let{output:i,snapshot:o,durationUs:r}=this.evaluateRaw(e,t),a=new Date().toISOString(),s=crypto.randomUUID();if(!i){this.trackEvent({key:e,variationKey:void 0,value:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],context:t,flagVersion:o.version,schemaVersion:1,evaluatedAt:a,traceId:s});return}return this.trackEvent({key:e,variationKey:i.variationKey,value:i.value,reasons:i.reasons,context:t,matchedTargetName:i.matchedTargetName,flagVersion:o.version,errorDetail:i.errorDetail,evaluationDurationUs:r,schemaVersion:1,evaluatedAt:a,inputsUsed:i.inputsUsed,traceId:s}),i.value}trackEvent(e){if(!this.eventBuffer)return;let{context:t}=e,i=Object.keys(t),o={};for(let a of i)o[a]=Object.keys(t[a]??{});let r=i.length===0||i.every(a=>Object.keys(t[a]??{}).length===0);this.eventBuffer.push({schemaVersion:e.schemaVersion??1,key:e.key,variationKey:e.variationKey,value:e.value,reasons:e.reasons,evaluatedAt:e.evaluatedAt??new Date().toISOString(),ruleId:e.ruleId,flagVersion:e.flagVersion??0,policyVersion:e.policyVersion,inputsUsed:e.inputsUsed,traceId:e.traceId,contextKinds:i,contextKeys:o,timestamp:Date.now(),matchedTargetName:e.matchedTargetName,errorDetail:e.errorDetail,evaluationDurationUs:e.evaluationDurationUs,isAnonymous:r});}async ready(){await this.initPromise;}isReady(){return this.snapshot!==null}async isEnabled(e,t){await this.initPromise;let i=this.evaluateAndTrack(e,this.mergeContext(t));return typeof i=="boolean"?i:false}async get(e,t){await this.initPromise;let i=this.evaluateAndTrack(e,this.mergeContext(t));return i??t.fallback}async evaluate(e,t){await this.initPromise;let i=this.mergeContext(t),{output:o,snapshot:r,durationUs:a}=this.evaluateRaw(e,i);if(!o){let l=crypto.randomUUID(),u=new Date().toISOString(),d={schemaVersion:1,key:e,value:void 0,variationKey:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],flagVersion:r.version,evaluatedAt:u,traceId:l};return this.trackEvent({key:e,variationKey:void 0,value:void 0,reasons:d.reasons,evaluatedAt:u,context:i,flagVersion:r.version,schemaVersion:1,traceId:l}),d}let s=this.buildResult(e,o,r.version,a);return this.trackEvent({key:e,variationKey:o.variationKey,value:o.value,reasons:o.reasons,evaluatedAt:s.evaluatedAt,ruleId:s.ruleId,context:i,matchedTargetName:o.matchedTargetName,flagVersion:r.version,errorDetail:o.errorDetail,evaluationDurationUs:a,schemaVersion:1,inputsUsed:o.inputsUsed,traceId:s.traceId}),s}isEnabledSync(e,t){let i=this.evaluateAndTrack(e,this.mergeContext(t));return typeof i=="boolean"?i:false}getSync(e,t){let i=this.evaluateAndTrack(e,this.mergeContext(t));return i??t.fallback}evaluateSync(e,t){let i=this.mergeContext(t),{output:o,snapshot:r,durationUs:a}=this.evaluateRaw(e,i);return o?this.buildResult(e,o,r.version,a):{schemaVersion:1,key:e,value:void 0,variationKey:void 0,reasons:[{type:"error",detail:"FLAG_NOT_FOUND"}],flagVersion:r.version,evaluatedAt:new Date().toISOString(),evaluationDurationUs:a,traceId:crypto.randomUUID()}}trackSync(e,t,i){let o=t.reasons.find(r=>r.type==="rule_match");this.trackEvent({key:e,variationKey:t.variationKey,value:t.value,reasons:t.reasons,evaluatedAt:t.evaluatedAt,ruleId:t.ruleId,context:this.mergeContext({context:i}),matchedTargetName:o?.ruleName,flagVersion:t.flagVersion,evaluationDurationUs:t.evaluationDurationUs,schemaVersion:t.schemaVersion,policyVersion:t.policyVersion,inputsUsed:t.inputsUsed,traceId:t.traceId});}identify(e){this.identifiedContext={...e};}reset(){this.identifiedContext={};}async refresh(){await this.fetchSnapshot();}getSnapshot(){return this.snapshot}onUpdate(e){return this.updateListeners.add(e),()=>this.updateListeners.delete(e)}close(){this.ws&&(this.ws.close(),this.ws=null),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.pollingTimer&&(clearInterval(this.pollingTimer),this.pollingTimer=null),this.eventBuffer&&(this.eventBuffer.destroy(),this.eventBuffer=null);}};function F(n){return new p(n)}
|
|
2
|
+
export{F as createGradual,v as evaluateFlag};//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/evaluator.ts","../src/event-buffer.ts","../src/client.ts"],"names":["hashString","str","hash","i","char","getBucketValue","flagKey","context","rollout","inputsUsed","bucketKey","seed","hashInput","resolveActiveRollout","now","startedAt","elapsedMinutes","cumulativeMinutes","step","selectVariationFromRollout","activeVariations","bucketValue","variations","scheduleStepIndex","cumulative","matchedRv","rv","variation","evaluateCondition","condition","contextKind","attributeKey","operator","value","contextValue","evaluateConditions","conditions","matchesIndividual","entries","entry","evaluateSegment","segment","evaluateTarget","target","segments","resolveTargetVariation","active","resolveDefaultVariation","flag","buildRuleMatchReason","buildRolloutReason","rolloutResult","evaluateFlag","options","sortedTargets","a","b","resolved","reasons","SDK_VERSION","g","doc","EventBuffer","event","batch","payload","DEFAULT_BASE_URL","detectPlatform","nav","win","SDK_PLATFORM","proc","hasHrtime","nowNs","elapsedUs","start","end","GradualClient","pollingEnabled","pollingIntervalMs","previousVersion","cb","error","initResponse","initData","snapshotResponse","initialEtag","merged","allKinds","kind","key","snapshot","startTime","output","err","errorDetail","flagVersion","durationUs","ruleMatch","evaluatedAt","traceId","params","contextKinds","contextKeys","isAnonymous","result","r","headers","response","etag","callback","createGradual"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n EvalOutput,\n EvaluationContext,\n Reason,\n SnapshotFlag,\n SnapshotIndividualEntry,\n SnapshotRollout,\n SnapshotRolloutVariation,\n SnapshotRuleCondition,\n SnapshotScheduleStep,\n SnapshotSegment,\n SnapshotTarget,\n SnapshotVariation,\n} from \"./types\";\n\nfunction hashString(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n // biome-ignore lint/suspicious/noBitwiseOperators: intentional hash algorithm using bitwise shift\n hash = (hash << 5) - hash + char;\n // biome-ignore lint/suspicious/noBitwiseOperators: converting to 32-bit integer\n hash |= 0;\n }\n return Math.abs(hash);\n}\n\nfunction getBucketValue(\n flagKey: string,\n context: EvaluationContext,\n rollout: SnapshotRollout,\n inputsUsed: Set<string>\n): number {\n inputsUsed.add(`${rollout.bucketContextKind}.${rollout.bucketAttributeKey}`);\n const bucketKey =\n context[rollout.bucketContextKind]?.[rollout.bucketAttributeKey];\n const seed = rollout.seed ?? \"\";\n const hashInput = `${flagKey}:${seed}:${String(bucketKey ?? \"anonymous\")}`;\n return hashString(hashInput) % 100_000;\n}\n\ninterface ActiveRollout {\n variations: SnapshotRolloutVariation[];\n stepIndex: number;\n}\n\nfunction resolveActiveRollout(\n rollout: SnapshotRollout,\n now: Date\n): ActiveRollout {\n if (!(rollout.schedule && rollout.startedAt)) {\n return { variations: rollout.variations, stepIndex: -1 };\n }\n\n const startedAt = new Date(rollout.startedAt).getTime();\n const elapsedMs = now.getTime() - startedAt;\n const elapsedMinutes = elapsedMs / 60_000;\n\n if (elapsedMinutes < 0) {\n return {\n variations: rollout.schedule[0]?.variations ?? rollout.variations,\n stepIndex: 0,\n };\n }\n\n let cumulativeMinutes = 0;\n for (let i = 0; i < rollout.schedule.length; i++) {\n const step = rollout.schedule[i] as SnapshotScheduleStep;\n if (step.durationMinutes === 0) {\n return { variations: step.variations, stepIndex: i };\n }\n cumulativeMinutes += step.durationMinutes;\n if (elapsedMinutes < cumulativeMinutes) {\n return { variations: step.variations, stepIndex: i };\n }\n }\n\n const lastStep = rollout.schedule.at(-1);\n return {\n variations: lastStep?.variations ?? rollout.variations,\n stepIndex: rollout.schedule.length - 1,\n };\n}\n\ninterface RolloutResult {\n variation: SnapshotVariation;\n variationKey: string;\n matchedWeight: number;\n bucketValue: number;\n scheduleStepIndex: number;\n}\n\nfunction selectVariationFromRollout(\n activeVariations: SnapshotRolloutVariation[],\n bucketValue: number,\n variations: Record<string, SnapshotVariation>,\n scheduleStepIndex: number\n): RolloutResult | undefined {\n let cumulative = 0;\n let matchedRv: SnapshotRolloutVariation | undefined;\n\n for (const rv of activeVariations) {\n cumulative += rv.weight;\n if (bucketValue < cumulative) {\n matchedRv = rv;\n break;\n }\n }\n\n if (!matchedRv) {\n matchedRv = activeVariations.at(-1);\n }\n\n if (!matchedRv) {\n return undefined;\n }\n\n const variation = variations[matchedRv.variationKey];\n if (!variation) {\n return undefined;\n }\n\n return {\n variation,\n variationKey: matchedRv.variationKey,\n matchedWeight: matchedRv.weight,\n bucketValue,\n scheduleStepIndex,\n };\n}\n\nfunction evaluateCondition(\n condition: SnapshotRuleCondition,\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n const { contextKind, attributeKey, operator, value } = condition;\n inputsUsed.add(`${contextKind}.${attributeKey}`);\n const contextValue = context[contextKind]?.[attributeKey];\n\n switch (operator) {\n case \"equals\":\n return contextValue === value;\n\n case \"not_equals\":\n return contextValue !== value;\n\n case \"contains\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.includes(value);\n }\n if (Array.isArray(contextValue)) {\n return contextValue.includes(value);\n }\n return false;\n\n case \"not_contains\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return !contextValue.includes(value);\n }\n if (Array.isArray(contextValue)) {\n return !contextValue.includes(value);\n }\n return true;\n\n case \"starts_with\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.startsWith(value);\n }\n return false;\n\n case \"ends_with\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.endsWith(value);\n }\n return false;\n\n case \"greater_than\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue > value;\n }\n return false;\n\n case \"less_than\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue < value;\n }\n return false;\n\n case \"greater_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue >= value;\n }\n return false;\n\n case \"less_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue <= value;\n }\n return false;\n\n case \"in\":\n if (Array.isArray(value)) {\n return value.includes(contextValue);\n }\n return false;\n\n case \"not_in\":\n if (Array.isArray(value)) {\n return !value.includes(contextValue);\n }\n return true;\n\n case \"exists\":\n return contextValue !== undefined && contextValue !== null;\n\n case \"not_exists\":\n return contextValue === undefined || contextValue === null;\n\n default:\n return false;\n }\n}\n\nfunction evaluateConditions(\n conditions: SnapshotRuleCondition[],\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n return conditions.every((condition) =>\n evaluateCondition(condition, context, inputsUsed)\n );\n}\n\nfunction matchesIndividual(\n entries: SnapshotIndividualEntry[],\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n for (const entry of entries) {\n inputsUsed.add(`${entry.contextKind}.${entry.attributeKey}`);\n if (\n context[entry.contextKind]?.[entry.attributeKey] === entry.attributeValue\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction evaluateSegment(\n segment: SnapshotSegment,\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n // Priority 1: Excluded individuals never match\n if (\n segment.excluded?.length &&\n matchesIndividual(segment.excluded, context, inputsUsed)\n ) {\n return false;\n }\n\n // Priority 2: Included individuals always match\n if (\n segment.included?.length &&\n matchesIndividual(segment.included, context, inputsUsed)\n ) {\n return true;\n }\n\n // Priority 3: Evaluate conditions (empty conditions = no match)\n if (segment.conditions.length === 0) {\n return false;\n }\n return evaluateConditions(segment.conditions, context, inputsUsed);\n}\n\nfunction evaluateTarget(\n target: SnapshotTarget,\n context: EvaluationContext,\n segments: Record<string, SnapshotSegment>,\n inputsUsed: Set<string>\n): boolean {\n switch (target.type) {\n case \"individual\":\n if (\n target.contextKind &&\n target.attributeKey &&\n target.attributeValue !== undefined\n ) {\n inputsUsed.add(`${target.contextKind}.${target.attributeKey}`);\n return (\n context[target.contextKind]?.[target.attributeKey] ===\n target.attributeValue\n );\n }\n return false;\n\n case \"rule\":\n if (target.conditions) {\n return evaluateConditions(target.conditions, context, inputsUsed);\n }\n return false;\n\n case \"segment\":\n if (target.segmentKey) {\n const segment = segments[target.segmentKey];\n if (segment) {\n return evaluateSegment(segment, context, inputsUsed);\n }\n }\n return false;\n\n default:\n return false;\n }\n}\n\nfunction resolveTargetVariation(\n target: SnapshotTarget,\n flagKey: string,\n context: EvaluationContext,\n variations: Record<string, SnapshotVariation>,\n inputsUsed: Set<string>,\n now: Date\n): RolloutResult | undefined {\n if (target.rollout) {\n const active = resolveActiveRollout(target.rollout, now);\n const bucketValue = getBucketValue(\n flagKey,\n context,\n target.rollout,\n inputsUsed\n );\n return selectVariationFromRollout(\n active.variations,\n bucketValue,\n variations,\n active.stepIndex\n );\n }\n\n if (target.variationKey) {\n const variation = variations[target.variationKey];\n if (variation) {\n return {\n variation,\n variationKey: target.variationKey,\n matchedWeight: 100_000,\n bucketValue: 0,\n scheduleStepIndex: -1,\n };\n }\n }\n\n return undefined;\n}\n\nfunction resolveDefaultVariation(\n flag: SnapshotFlag,\n context: EvaluationContext,\n inputsUsed: Set<string>,\n now: Date\n): RolloutResult | undefined {\n if (flag.defaultRollout) {\n const active = resolveActiveRollout(flag.defaultRollout, now);\n const bucketValue = getBucketValue(\n flag.key,\n context,\n flag.defaultRollout,\n inputsUsed\n );\n return selectVariationFromRollout(\n active.variations,\n bucketValue,\n flag.variations,\n active.stepIndex\n );\n }\n\n if (flag.defaultVariationKey) {\n const variation = flag.variations[flag.defaultVariationKey];\n if (variation) {\n return {\n variation,\n variationKey: flag.defaultVariationKey,\n matchedWeight: 100_000,\n bucketValue: 0,\n scheduleStepIndex: -1,\n };\n }\n }\n\n return undefined;\n}\n\nfunction buildRuleMatchReason(target: SnapshotTarget): Reason {\n return {\n type: \"rule_match\",\n ruleId: target.id ?? \"\",\n ruleName: target.name,\n };\n}\n\nfunction buildRolloutReason(rolloutResult: RolloutResult): Reason {\n if (rolloutResult.scheduleStepIndex >= 0) {\n return {\n type: \"gradual_rollout\",\n stepIndex: rolloutResult.scheduleStepIndex,\n percentage: rolloutResult.matchedWeight / 1000,\n bucket: rolloutResult.bucketValue,\n };\n }\n return {\n type: \"percentage_rollout\",\n percentage: rolloutResult.matchedWeight / 1000,\n bucket: rolloutResult.bucketValue,\n };\n}\n\nexport function evaluateFlag(\n flag: SnapshotFlag,\n context: EvaluationContext,\n segments: Record<string, SnapshotSegment>,\n options?: { now?: Date }\n): EvalOutput {\n if (!flag.enabled) {\n const offVariation = flag.variations[flag.offVariationKey];\n return {\n value: offVariation?.value,\n variationKey: flag.offVariationKey,\n reasons: [{ type: \"off\" }],\n inputsUsed: [],\n };\n }\n\n const now = options?.now ?? new Date();\n const inputsUsed = new Set<string>();\n\n const sortedTargets = [...flag.targets].sort(\n (a, b) => a.sortOrder - b.sortOrder\n );\n\n for (const target of sortedTargets) {\n if (evaluateTarget(target, context, segments, inputsUsed)) {\n const resolved = resolveTargetVariation(\n target,\n flag.key,\n context,\n flag.variations,\n inputsUsed,\n now\n );\n if (resolved) {\n const reasons: Reason[] = [buildRuleMatchReason(target)];\n if (target.rollout) {\n reasons.push(buildRolloutReason(resolved));\n }\n\n return {\n value: resolved.variation.value,\n variationKey: resolved.variationKey,\n reasons,\n matchedTargetName: target.name,\n inputsUsed: [...inputsUsed],\n };\n }\n }\n }\n\n const resolved = resolveDefaultVariation(flag, context, inputsUsed, now);\n if (resolved) {\n const reasons: Reason[] = [];\n if (flag.defaultRollout) {\n reasons.push(buildRolloutReason(resolved));\n }\n reasons.push({ type: \"default\" });\n\n return {\n value: resolved.variation.value,\n variationKey: resolved.variationKey,\n reasons,\n inputsUsed: [...inputsUsed],\n };\n }\n\n return {\n value: undefined,\n variationKey: undefined,\n reasons: [{ type: \"default\" }],\n inputsUsed: [...inputsUsed],\n };\n}\n","import type { EvaluationBatchPayload, EvaluationEvent } from \"./types\";\n\ndeclare const __SDK_VERSION__: string;\nexport const SDK_VERSION = __SDK_VERSION__;\n\ninterface EventBufferOptions {\n baseUrl: string;\n apiKey: string;\n meta: {\n projectId: string;\n organizationId: string;\n environmentId: string;\n sdkPlatform?: string;\n };\n flushIntervalMs: number;\n maxBatchSize: number;\n}\n\nconst g = globalThis as Record<string, unknown>;\nconst doc = g.document as\n | {\n visibilityState?: string;\n addEventListener?: (event: string, handler: () => void) => void;\n removeEventListener?: (event: string, handler: () => void) => void;\n }\n | undefined;\nexport class EventBuffer {\n private readonly events: EvaluationEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly options: EventBufferOptions;\n private readonly onVisibilityChange: (() => void) | null = null;\n\n constructor(options: EventBufferOptions) {\n this.options = options;\n this.timer = setInterval(() => this.flush(), this.options.flushIntervalMs);\n\n if (doc?.addEventListener) {\n this.onVisibilityChange = () => {\n if (doc.visibilityState === \"hidden\") {\n this.flushBeacon();\n }\n };\n doc.addEventListener(\"visibilitychange\", this.onVisibilityChange);\n }\n }\n\n push(event: EvaluationEvent): void {\n this.events.push(event);\n if (this.events.length >= this.options.maxBatchSize) {\n this.flush();\n }\n }\n\n private buildPayload(batch: EvaluationEvent[]): EvaluationBatchPayload {\n return {\n meta: {\n ...this.options.meta,\n sdkVersion: SDK_VERSION,\n },\n events: batch,\n };\n }\n\n flush(): void {\n if (this.events.length === 0) {\n return;\n }\n const batch = this.events.splice(0, this.options.maxBatchSize);\n const payload = this.buildPayload(batch);\n\n fetch(`${this.options.baseUrl}/sdk/evaluations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify(payload),\n }).catch(() => {\n // Fire-and-forget: silently drop failed events to prevent unbounded growth\n });\n }\n\n /**\n * Flush with keepalive flag for reliable delivery during page unload.\n * keepalive fetch survives page navigation like sendBeacon but supports headers.\n */\n private flushBeacon(): void {\n if (this.events.length === 0) {\n return;\n }\n\n const batch = this.events.splice(0, this.options.maxBatchSize);\n const payload = this.buildPayload(batch);\n\n fetch(`${this.options.baseUrl}/sdk/evaluations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify(payload),\n keepalive: true,\n }).catch(() => {\n // Fire-and-forget\n });\n }\n\n destroy(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n if (this.onVisibilityChange && doc?.removeEventListener) {\n doc.removeEventListener(\"visibilitychange\", this.onVisibilityChange);\n }\n this.flush();\n }\n}\n","import { evaluateFlag } from \"./evaluator\";\nimport { EventBuffer } from \"./event-buffer\";\nimport type {\n EnvironmentSnapshot,\n EvalOutput,\n EvaluationContext,\n EvaluationResult,\n FlagOptions,\n GradualOptions,\n IsEnabledOptions,\n Reason,\n} from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://worker.gradual.so/api/v1\";\n\ntype SdkPlatform = \"browser\" | \"node\" | \"react-native\" | \"edge\" | \"unknown\";\n\nfunction detectPlatform(): SdkPlatform {\n try {\n const g = globalThis as Record<string, unknown>;\n const nav = g.navigator as\n | { product?: string; userAgent?: string }\n | undefined;\n if (nav && nav.product === \"ReactNative\") {\n return \"react-native\";\n }\n const win = g.window as { document?: unknown } | undefined;\n if (win && typeof win.document !== \"undefined\") {\n return \"browser\";\n }\n const proc = g.process as { versions?: { node?: string } } | undefined;\n if (proc?.versions?.node) {\n return \"node\";\n }\n if (typeof globalThis !== \"undefined\") {\n return \"edge\";\n }\n } catch {\n // Ignore detection errors\n }\n return \"unknown\";\n}\n\nconst SDK_PLATFORM = detectPlatform();\n\nconst proc = (globalThis as Record<string, unknown>).process as\n | { hrtime?: { bigint?: () => bigint } }\n | undefined;\nconst hasHrtime = typeof proc?.hrtime?.bigint === \"function\";\n\nfunction nowNs(): bigint | number {\n if (hasHrtime) {\n // biome-ignore lint/style/noNonNullAssertion: guarded by hasHrtime check\n return proc!.hrtime!.bigint!();\n }\n if (typeof performance !== \"undefined\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction elapsedUs(start: bigint | number): number {\n const end = nowNs();\n if (typeof start === \"bigint\" && typeof end === \"bigint\") {\n // hrtime bigint: nanoseconds → microseconds\n return Number((end - start) / 1000n);\n }\n // performance.now() ms or Date.now() ms → microseconds\n return Math.round(((end as number) - (start as number)) * 1000);\n}\n\nexport interface Gradual {\n /** Wait for the SDK to be ready (snapshot fetched) */\n ready(): Promise<void>;\n\n /** Check if the SDK is ready for sync access */\n isReady(): boolean;\n\n /** Check if a boolean flag is enabled */\n isEnabled(key: string, options?: IsEnabledOptions): Promise<boolean>;\n\n /** Get a flag value with type inference from fallback */\n get<T>(key: string, options: FlagOptions<T>): Promise<T>;\n\n /** Evaluate a flag and return the full structured result (also tracks the evaluation) */\n evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): Promise<EvaluationResult<T>>;\n\n /** Set persistent user context for all evaluations */\n identify(context: EvaluationContext): void;\n\n /** Clear the identified user context */\n reset(): void;\n\n /** Refresh the snapshot from the server */\n refresh(): Promise<void>;\n\n /** Get the current snapshot (for debugging) */\n getSnapshot(): EnvironmentSnapshot | null;\n\n /** Subscribe to snapshot updates from polling (returns unsubscribe function) */\n onUpdate(callback: () => void): () => void;\n\n /** Flush pending evaluation events and stop the event buffer */\n close(): void;\n\n /** Sync methods (throw if not ready) */\n sync: GradualSync;\n}\n\nexport interface GradualSync {\n /** Sync version of isEnabled (throws if not ready) */\n isEnabled(key: string, options?: IsEnabledOptions): boolean;\n\n /** Sync version of get (throws if not ready) */\n get<T>(key: string, options: FlagOptions<T>): T;\n\n /** Evaluate a flag without tracking. Use with track() for React-safe evaluation. */\n evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): EvaluationResult<T>;\n\n /** Manually track an evaluation that was produced by evaluate(). */\n track(\n key: string,\n result: EvaluationResult,\n context?: EvaluationContext\n ): void;\n}\n\nclass GradualClient implements Gradual {\n private readonly apiKey: string;\n private readonly environment: string;\n private readonly baseUrl: string;\n private readonly initPromise: Promise<void>;\n private snapshot: EnvironmentSnapshot | null = null;\n private identifiedContext: EvaluationContext = {};\n private readonly updateListeners: Set<() => void> = new Set();\n private eventBuffer: EventBuffer | null = null;\n private etag: string | null = null;\n private readonly eventsEnabled: boolean;\n private readonly eventsFlushIntervalMs: number;\n private readonly eventsMaxBatchSize: number;\n\n readonly sync: GradualSync;\n\n constructor(options: GradualOptions) {\n this.apiKey = options.apiKey;\n this.environment = options.environment;\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n this.eventsEnabled = options.events?.enabled ?? true;\n this.eventsFlushIntervalMs = options.events?.flushIntervalMs ?? 30_000;\n this.eventsMaxBatchSize = options.events?.maxBatchSize ?? 100;\n this.initPromise = this.init();\n\n this.sync = {\n isEnabled: this.isEnabledSync.bind(this),\n get: this.getSync.bind(this),\n evaluate: this.evaluateSync.bind(this),\n track: this.trackSync.bind(this),\n };\n\n const pollingEnabled = options.polling?.enabled ?? true;\n const pollingIntervalMs = options.polling?.intervalMs ?? 10_000;\n\n if (pollingEnabled) {\n this.initPromise.then(() => {\n setInterval(async () => {\n try {\n const previousVersion = this.snapshot?.version;\n await this.refresh();\n if (this.snapshot && this.snapshot.version !== previousVersion) {\n for (const cb of this.updateListeners) {\n cb();\n }\n }\n } catch (error) {\n console.warn(\"Gradual: Polling refresh failed\", error);\n }\n }, pollingIntervalMs);\n });\n }\n }\n\n private async init(): Promise<void> {\n const initResponse = await fetch(`${this.baseUrl}/sdk/init`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ apiKey: this.apiKey }),\n });\n\n if (!initResponse.ok) {\n const error = await initResponse.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to initialize - ${(error as { error?: string }).error ?? initResponse.statusText}`\n );\n }\n\n const initData = (await initResponse.json()) as {\n valid: boolean;\n error?: string;\n };\n\n if (!initData.valid) {\n throw new Error(\n `Gradual: Invalid API key - ${initData.error ?? \"Unknown error\"}`\n );\n }\n\n const snapshotResponse = await fetch(\n `${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,\n { headers: { Authorization: `Bearer ${this.apiKey}` } }\n );\n\n if (!snapshotResponse.ok) {\n const error = await snapshotResponse.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to fetch snapshot - ${(error as { error?: string }).error ?? snapshotResponse.statusText}`\n );\n }\n\n const initialEtag = snapshotResponse.headers.get(\"ETag\");\n if (initialEtag) {\n this.etag = initialEtag;\n }\n this.snapshot = (await snapshotResponse.json()) as EnvironmentSnapshot;\n\n if (this.eventsEnabled && this.snapshot.meta) {\n this.eventBuffer = new EventBuffer({\n baseUrl: this.baseUrl,\n apiKey: this.apiKey,\n meta: {\n projectId: this.snapshot.meta.projectId,\n organizationId: this.snapshot.meta.organizationId,\n environmentId: this.snapshot.meta.environmentId,\n sdkPlatform: SDK_PLATFORM,\n },\n flushIntervalMs: this.eventsFlushIntervalMs,\n maxBatchSize: this.eventsMaxBatchSize,\n });\n }\n }\n\n private ensureReady(): EnvironmentSnapshot {\n if (!this.snapshot) {\n throw new Error(\n \"Gradual: SDK not ready. Use await ready() or async methods.\"\n );\n }\n return this.snapshot;\n }\n\n private mergeContext(options?: {\n context?: EvaluationContext;\n }): EvaluationContext {\n const merged: EvaluationContext = {};\n const allKinds = new Set([\n ...Object.keys(this.identifiedContext),\n ...Object.keys(options?.context ?? {}),\n ]);\n for (const kind of allKinds) {\n merged[kind] = {\n ...this.identifiedContext[kind],\n ...options?.context?.[kind],\n };\n }\n return merged;\n }\n\n private evaluateRaw(\n key: string,\n context: EvaluationContext\n ): {\n output: EvalOutput | null;\n snapshot: EnvironmentSnapshot;\n durationUs: number;\n } {\n const snapshot = this.ensureReady();\n if (!snapshot.flags) {\n return { output: null, snapshot, durationUs: 0 };\n }\n const flag = snapshot.flags[key];\n if (!flag) {\n return { output: null, snapshot, durationUs: 0 };\n }\n\n const startTime = nowNs();\n let output: EvalOutput;\n try {\n output = evaluateFlag(flag, context, snapshot.segments ?? {});\n } catch (err) {\n const errorDetail = err instanceof Error ? err.message : String(err);\n output = {\n value: undefined,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: errorDetail }],\n errorDetail,\n };\n }\n\n return { output, snapshot, durationUs: elapsedUs(startTime) };\n }\n\n private buildResult<T>(\n key: string,\n output: EvalOutput,\n flagVersion: number,\n durationUs?: number\n ): EvaluationResult<T> {\n const ruleMatch = output.reasons.find(\n (r): r is Extract<Reason, { type: \"rule_match\" }> =>\n r.type === \"rule_match\"\n );\n\n return {\n schemaVersion: 1,\n key,\n value: output.value as T,\n variationKey: output.variationKey,\n reasons: output.reasons,\n ruleId: ruleMatch?.ruleId,\n flagVersion,\n evaluatedAt: new Date().toISOString(),\n evaluationDurationUs: durationUs,\n inputsUsed: output.inputsUsed,\n traceId: crypto.randomUUID(),\n };\n }\n\n private evaluateAndTrack(key: string, context: EvaluationContext): unknown {\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n const evaluatedAt = new Date().toISOString();\n const traceId = crypto.randomUUID();\n\n if (!output) {\n this.trackEvent({\n key,\n variationKey: undefined,\n value: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n context,\n flagVersion: snapshot.version,\n schemaVersion: 1,\n evaluatedAt,\n traceId,\n });\n return undefined;\n }\n\n this.trackEvent({\n key,\n variationKey: output.variationKey,\n value: output.value,\n reasons: output.reasons,\n context,\n matchedTargetName: output.matchedTargetName,\n flagVersion: snapshot.version,\n errorDetail: output.errorDetail,\n evaluationDurationUs: durationUs,\n schemaVersion: 1,\n evaluatedAt,\n inputsUsed: output.inputsUsed,\n traceId,\n });\n\n return output.value;\n }\n\n private trackEvent(params: {\n key: string;\n variationKey: string | undefined;\n value: unknown;\n reasons: Reason[];\n evaluatedAt?: string;\n ruleId?: string;\n context: EvaluationContext;\n matchedTargetName?: string;\n flagVersion?: number;\n errorDetail?: string;\n evaluationDurationUs?: number;\n schemaVersion?: 1;\n policyVersion?: number;\n inputsUsed?: string[];\n traceId?: string;\n }): void {\n if (!this.eventBuffer) {\n return;\n }\n const { context } = params;\n const contextKinds = Object.keys(context);\n const contextKeys: Record<string, string[]> = {};\n for (const kind of contextKinds) {\n contextKeys[kind] = Object.keys(context[kind] ?? {});\n }\n\n const isAnonymous =\n contextKinds.length === 0 ||\n contextKinds.every(\n (kind) => Object.keys(context[kind] ?? {}).length === 0\n );\n\n this.eventBuffer.push({\n schemaVersion: params.schemaVersion ?? 1,\n key: params.key,\n variationKey: params.variationKey,\n value: params.value,\n reasons: params.reasons,\n evaluatedAt: params.evaluatedAt ?? new Date().toISOString(),\n ruleId: params.ruleId,\n flagVersion: params.flagVersion ?? 0,\n policyVersion: params.policyVersion,\n inputsUsed: params.inputsUsed,\n traceId: params.traceId,\n contextKinds,\n contextKeys,\n timestamp: Date.now(),\n matchedTargetName: params.matchedTargetName,\n errorDetail: params.errorDetail,\n evaluationDurationUs: params.evaluationDurationUs,\n isAnonymous,\n });\n }\n\n async ready(): Promise<void> {\n await this.initPromise;\n }\n\n isReady(): boolean {\n return this.snapshot !== null;\n }\n\n async isEnabled(key: string, options?: IsEnabledOptions): Promise<boolean> {\n await this.initPromise;\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return typeof value === \"boolean\" ? value : false;\n }\n\n async get<T>(key: string, options: FlagOptions<T>): Promise<T> {\n await this.initPromise;\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return value !== undefined && value !== null\n ? (value as T)\n : options.fallback;\n }\n\n async evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): Promise<EvaluationResult<T>> {\n await this.initPromise;\n const context = this.mergeContext(options);\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n\n if (!output) {\n const traceId = crypto.randomUUID();\n const evaluatedAt = new Date().toISOString();\n const result: EvaluationResult<T> = {\n schemaVersion: 1,\n key,\n value: undefined as T,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n flagVersion: snapshot.version,\n evaluatedAt,\n traceId,\n };\n this.trackEvent({\n key,\n variationKey: undefined,\n value: undefined,\n reasons: result.reasons,\n evaluatedAt,\n context,\n flagVersion: snapshot.version,\n schemaVersion: 1,\n traceId,\n });\n return result;\n }\n\n const result = this.buildResult<T>(\n key,\n output,\n snapshot.version,\n durationUs\n );\n\n this.trackEvent({\n key,\n variationKey: output.variationKey,\n value: output.value,\n reasons: output.reasons,\n evaluatedAt: result.evaluatedAt,\n ruleId: result.ruleId,\n context,\n matchedTargetName: output.matchedTargetName,\n flagVersion: snapshot.version,\n errorDetail: output.errorDetail,\n evaluationDurationUs: durationUs,\n schemaVersion: 1,\n inputsUsed: output.inputsUsed,\n traceId: result.traceId,\n });\n\n return result;\n }\n\n private isEnabledSync(key: string, options?: IsEnabledOptions): boolean {\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return typeof value === \"boolean\" ? value : false;\n }\n\n private getSync<T>(key: string, options: FlagOptions<T>): T {\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return value !== undefined && value !== null\n ? (value as T)\n : options.fallback;\n }\n\n private evaluateSync<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): EvaluationResult<T> {\n const context = this.mergeContext(options);\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n\n if (!output) {\n return {\n schemaVersion: 1,\n key,\n value: undefined as T,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n flagVersion: snapshot.version,\n evaluatedAt: new Date().toISOString(),\n evaluationDurationUs: durationUs,\n traceId: crypto.randomUUID(),\n };\n }\n\n return this.buildResult<T>(key, output, snapshot.version, durationUs);\n }\n\n private trackSync(\n key: string,\n result: EvaluationResult,\n context?: EvaluationContext\n ): void {\n const ruleMatch = result.reasons.find(\n (r): r is Extract<Reason, { type: \"rule_match\" }> =>\n r.type === \"rule_match\"\n );\n\n this.trackEvent({\n key,\n variationKey: result.variationKey,\n value: result.value,\n reasons: result.reasons,\n evaluatedAt: result.evaluatedAt,\n ruleId: result.ruleId,\n context: this.mergeContext({ context }),\n matchedTargetName: ruleMatch?.ruleName,\n flagVersion: result.flagVersion,\n evaluationDurationUs: result.evaluationDurationUs,\n schemaVersion: result.schemaVersion,\n policyVersion: result.policyVersion,\n inputsUsed: result.inputsUsed,\n traceId: result.traceId,\n });\n }\n\n identify(context: EvaluationContext): void {\n this.identifiedContext = { ...context };\n }\n\n reset(): void {\n this.identifiedContext = {};\n }\n\n async refresh(): Promise<void> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n };\n if (this.etag) {\n headers[\"If-None-Match\"] = this.etag;\n }\n\n const response = await fetch(\n `${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,\n { headers }\n );\n\n if (response.status === 304) {\n return;\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to refresh - ${(error as { error?: string }).error ?? response.statusText}`\n );\n }\n\n const etag = response.headers.get(\"ETag\");\n if (etag) {\n this.etag = etag;\n }\n this.snapshot = (await response.json()) as EnvironmentSnapshot;\n }\n\n getSnapshot(): EnvironmentSnapshot | null {\n return this.snapshot;\n }\n\n onUpdate(callback: () => void): () => void {\n this.updateListeners.add(callback);\n return () => this.updateListeners.delete(callback);\n }\n\n close(): void {\n if (this.eventBuffer) {\n this.eventBuffer.destroy();\n this.eventBuffer = null;\n }\n }\n}\n\n/**\n * Create a Gradual feature flag client\n *\n * @example\n * ```ts\n * const gradual = createGradual({\n * apiKey: 'gra_xxx',\n * environment: 'production'\n * })\n *\n * // Boolean flags\n * const enabled = await gradual.isEnabled('new-feature')\n *\n * // Typed values (inferred from fallback)\n * const theme = await gradual.get('theme', { fallback: 'dark' })\n *\n * // Full structured result\n * const result = await gradual.evaluate('new-feature')\n * // result.value, result.reasons, result.ruleId, result.flagVersion\n *\n * // With user context\n * gradual.identify({ userId: '123', plan: 'pro' })\n * const proFeature = await gradual.isEnabled('pro-feature')\n * ```\n */\nexport function createGradual(options: GradualOptions): Gradual {\n return new GradualClient(options);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/evaluator.ts","../src/event-buffer.ts","../src/client.ts"],"names":["hashString","str","hash","i","char","getBucketValue","flagKey","context","rollout","inputsUsed","bucketKey","seed","hashInput","resolveActiveRollout","now","startedAt","elapsedMinutes","cumulativeMinutes","step","selectVariationFromRollout","activeVariations","bucketValue","variations","scheduleStepIndex","cumulative","matchedRv","rv","variation","evaluateCondition","condition","contextKind","attributeKey","operator","value","contextValue","evaluateConditions","conditions","matchesIndividual","entries","entry","evaluateSegment","segment","evaluateTarget","target","segments","resolveTargetVariation","active","resolveDefaultVariation","flag","buildRuleMatchReason","buildRolloutReason","rolloutResult","evaluateFlag","options","sortedTargets","a","b","resolved","reasons","SDK_VERSION","g","doc","EventBuffer","event","batch","payload","DEFAULT_BASE_URL","HTTPS_RE","HTTP_RE","detectPlatform","nav","win","SDK_PLATFORM","proc","hasHrtime","nowNs","elapsedUs","start","end","GradualClient","hasWebSocket","initResponse","error","initData","headers","response","etag","previousVersion","cb","resolve","reject","wsUrl","ws","newSnapshot","err","delay","merged","allKinds","kind","key","snapshot","startTime","output","errorDetail","flagVersion","durationUs","ruleMatch","r","evaluatedAt","traceId","params","contextKinds","contextKeys","isAnonymous","result","callback","createGradual"],"mappings":"AAeA,SAASA,EAAWC,CAAAA,CAAqB,CACvC,IAAIC,CAAAA,CAAO,CAAA,CACX,QAASC,CAAAA,CAAI,CAAA,CAAGA,EAAIF,CAAAA,CAAI,MAAA,CAAQE,IAAK,CACnC,IAAMC,EAAOH,CAAAA,CAAI,UAAA,CAAWE,CAAC,CAAA,CAE7BD,CAAAA,CAAAA,CAAQA,CAAAA,EAAQ,CAAA,EAAKA,EAAOE,CAAAA,CAE5BF,CAAAA,EAAQ,EACV,CACA,OAAO,KAAK,GAAA,CAAIA,CAAI,CACtB,CAEA,SAASG,EACPC,CAAAA,CACAC,CAAAA,CACAC,EACAC,CAAAA,CACQ,CACRA,EAAW,GAAA,CAAI,CAAA,EAAGD,CAAAA,CAAQ,iBAAiB,IAAIA,CAAAA,CAAQ,kBAAkB,EAAE,CAAA,CAC3E,IAAME,EACJH,CAAAA,CAAQC,CAAAA,CAAQ,iBAAiB,CAAA,GAAIA,CAAAA,CAAQ,kBAAkB,CAAA,CAC3DG,CAAAA,CAAOH,EAAQ,IAAA,EAAQ,EAAA,CACvBI,EAAY,CAAA,EAAGN,CAAO,IAAIK,CAAI,CAAA,CAAA,EAAI,OAAOD,CAAAA,EAAa,WAAW,CAAC,CAAA,CAAA,CACxE,OAAOV,EAAWY,CAAS,CAAA,CAAI,GACjC,CAOA,SAASC,EACPL,CAAAA,CACAM,CAAAA,CACe,CACf,GAAI,EAAEN,EAAQ,QAAA,EAAYA,CAAAA,CAAQ,SAAA,CAAA,CAChC,OAAO,CAAE,UAAA,CAAYA,CAAAA,CAAQ,WAAY,SAAA,CAAW,EAAG,EAGzD,IAAMO,CAAAA,CAAY,IAAI,IAAA,CAAKP,CAAAA,CAAQ,SAAS,CAAA,CAAE,OAAA,GAExCQ,CAAAA,CAAAA,CADYF,CAAAA,CAAI,SAAQ,CAAIC,CAAAA,EACC,IAEnC,GAAIC,CAAAA,CAAiB,EACnB,OAAO,CACL,WAAYR,CAAAA,CAAQ,QAAA,CAAS,CAAC,CAAA,EAAG,UAAA,EAAcA,EAAQ,UAAA,CACvD,SAAA,CAAW,CACb,CAAA,CAGF,IAAIS,EAAoB,CAAA,CACxB,IAAA,IAASd,EAAI,CAAA,CAAGA,CAAAA,CAAIK,CAAAA,CAAQ,QAAA,CAAS,OAAQL,CAAAA,EAAAA,CAAK,CAChD,IAAMe,CAAAA,CAAOV,CAAAA,CAAQ,SAASL,CAAC,CAAA,CAC/B,GAAIe,CAAAA,CAAK,eAAA,GAAoB,EAC3B,OAAO,CAAE,WAAYA,CAAAA,CAAK,UAAA,CAAY,UAAWf,CAAE,CAAA,CAGrD,GADAc,CAAAA,EAAqBC,CAAAA,CAAK,gBACtBF,CAAAA,CAAiBC,CAAAA,CACnB,OAAO,CAAE,UAAA,CAAYC,EAAK,UAAA,CAAY,SAAA,CAAWf,CAAE,CAEvD,CAGA,OAAO,CACL,UAAA,CAFeK,EAAQ,QAAA,CAAS,EAAA,CAAG,EAAE,CAAA,EAEf,UAAA,EAAcA,CAAAA,CAAQ,UAAA,CAC5C,UAAWA,CAAAA,CAAQ,QAAA,CAAS,OAAS,CACvC,CACF,CAUA,SAASW,CAAAA,CACPC,EACAC,CAAAA,CACAC,CAAAA,CACAC,EAC2B,CAC3B,IAAIC,EAAa,CAAA,CACbC,CAAAA,CAEJ,QAAWC,CAAAA,IAAMN,CAAAA,CAEf,GADAI,CAAAA,EAAcE,EAAG,MAAA,CACbL,CAAAA,CAAcG,EAAY,CAC5BC,CAAAA,CAAYC,EACZ,KACF,CAOF,GAJKD,CAAAA,GACHA,CAAAA,CAAYL,EAAiB,EAAA,CAAG,EAAE,GAGhC,CAACK,CAAAA,CACH,OAGF,IAAME,CAAAA,CAAYL,CAAAA,CAAWG,CAAAA,CAAU,YAAY,CAAA,CACnD,GAAKE,EAIL,OAAO,CACL,UAAAA,CAAAA,CACA,YAAA,CAAcF,EAAU,YAAA,CACxB,aAAA,CAAeA,EAAU,MAAA,CACzB,WAAA,CAAAJ,EACA,iBAAA,CAAAE,CACF,CACF,CAEA,SAASK,EACPC,CAAAA,CACAtB,CAAAA,CACAE,EACS,CACT,GAAM,CAAE,WAAA,CAAAqB,CAAAA,CAAa,aAAAC,CAAAA,CAAc,QAAA,CAAAC,EAAU,KAAA,CAAAC,CAAM,EAAIJ,CAAAA,CACvDpB,CAAAA,CAAW,IAAI,CAAA,EAAGqB,CAAW,IAAIC,CAAY,CAAA,CAAE,CAAA,CAC/C,IAAMG,EAAe3B,CAAAA,CAAQuB,CAAW,IAAIC,CAAY,CAAA,CAExD,OAAQC,CAAAA,EACN,KAAK,QAAA,CACH,OAAOE,IAAiBD,CAAAA,CAE1B,KAAK,aACH,OAAOC,CAAAA,GAAiBD,EAE1B,KAAK,UAAA,CAIH,OAHI,OAAOC,CAAAA,EAAiB,UAAY,OAAOD,CAAAA,EAAU,UAGrD,KAAA,CAAM,OAAA,CAAQC,CAAY,CAAA,CACrBA,CAAAA,CAAa,SAASD,CAAK,CAAA,CAE7B,MAET,KAAK,cAAA,CAIH,OAHI,OAAOC,CAAAA,EAAiB,UAAY,OAAOD,CAAAA,EAAU,QAAA,EAGrD,KAAA,CAAM,QAAQC,CAAY,CAAA,CACrB,CAACA,CAAAA,CAAa,QAAA,CAASD,CAAK,CAAA,CAE9B,IAAA,CAET,KAAK,aAAA,CACH,OAAI,OAAOC,CAAAA,EAAiB,QAAA,EAAY,OAAOD,CAAAA,EAAU,QAAA,CAChDC,EAAa,UAAA,CAAWD,CAAK,EAE/B,KAAA,CAET,KAAK,YACH,OAAI,OAAOC,GAAiB,QAAA,EAAY,OAAOD,GAAU,QAAA,CAChDC,CAAAA,CAAa,SAASD,CAAK,CAAA,CAE7B,MAET,KAAK,cAAA,CACH,OAAI,OAAOC,CAAAA,EAAiB,UAAY,OAAOD,CAAAA,EAAU,QAAA,CAChDC,CAAAA,CAAeD,EAEjB,KAAA,CAET,KAAK,YACH,OAAI,OAAOC,GAAiB,QAAA,EAAY,OAAOD,GAAU,QAAA,CAChDC,CAAAA,CAAeD,EAEjB,KAAA,CAET,KAAK,wBACH,OAAI,OAAOC,GAAiB,QAAA,EAAY,OAAOD,CAAAA,EAAU,QAAA,CAChDC,GAAgBD,CAAAA,CAElB,KAAA,CAET,KAAK,oBAAA,CACH,OAAI,OAAOC,CAAAA,EAAiB,QAAA,EAAY,OAAOD,CAAAA,EAAU,QAAA,CAChDC,GAAgBD,CAAAA,CAElB,KAAA,CAET,KAAK,IAAA,CACH,OAAI,MAAM,OAAA,CAAQA,CAAK,CAAA,CACdA,CAAAA,CAAM,SAASC,CAAY,CAAA,CAE7B,MAET,KAAK,QAAA,CACH,OAAI,KAAA,CAAM,OAAA,CAAQD,CAAK,CAAA,CACd,CAACA,EAAM,QAAA,CAASC,CAAY,EAE9B,IAAA,CAET,KAAK,SACH,OAAqCA,CAAAA,EAAiB,KAExD,KAAK,YAAA,CACH,OAAqCA,CAAAA,EAAiB,IAAA,CAExD,QACE,OAAO,MACX,CACF,CAEA,SAASC,EACPC,CAAAA,CACA7B,CAAAA,CACAE,EACS,CACT,OAAO2B,EAAW,KAAA,CAAOP,CAAAA,EACvBD,EAAkBC,CAAAA,CAAWtB,CAAAA,CAASE,CAAU,CAClD,CACF,CAEA,SAAS4B,EACPC,CAAAA,CACA/B,CAAAA,CACAE,EACS,CACT,IAAA,IAAW8B,KAASD,CAAAA,CAElB,GADA7B,EAAW,GAAA,CAAI,CAAA,EAAG8B,EAAM,WAAW,CAAA,CAAA,EAAIA,EAAM,YAAY,CAAA,CAAE,EAEzDhC,CAAAA,CAAQgC,CAAAA,CAAM,WAAW,CAAA,GAAIA,CAAAA,CAAM,YAAY,CAAA,GAAMA,CAAAA,CAAM,eAE3D,OAAO,KAAA,CAGX,OAAO,MACT,CAEA,SAASC,CAAAA,CACPC,CAAAA,CACAlC,EACAE,CAAAA,CACS,CAET,OACEgC,CAAAA,CAAQ,QAAA,EAAU,MAAA,EAClBJ,CAAAA,CAAkBI,EAAQ,QAAA,CAAUlC,CAAAA,CAASE,CAAU,CAAA,CAEhD,KAAA,CAKPgC,EAAQ,QAAA,EAAU,MAAA,EAClBJ,EAAkBI,CAAAA,CAAQ,QAAA,CAAUlC,EAASE,CAAU,CAAA,CAEhD,KAILgC,CAAAA,CAAQ,UAAA,CAAW,SAAW,CAAA,CACzB,KAAA,CAEFN,EAAmBM,CAAAA,CAAQ,UAAA,CAAYlC,EAASE,CAAU,CACnE,CAEA,SAASiC,CAAAA,CACPC,EACApC,CAAAA,CACAqC,CAAAA,CACAnC,EACS,CACT,OAAQkC,EAAO,IAAA,EACb,KAAK,YAAA,CACH,OACEA,EAAO,WAAA,EACPA,CAAAA,CAAO,YAAA,EACPA,CAAAA,CAAO,iBAAmB,MAAA,EAE1BlC,CAAAA,CAAW,IAAI,CAAA,EAAGkC,CAAAA,CAAO,WAAW,CAAA,CAAA,EAAIA,CAAAA,CAAO,YAAY,CAAA,CAAE,CAAA,CAE3DpC,EAAQoC,CAAAA,CAAO,WAAW,IAAIA,CAAAA,CAAO,YAAY,IACjDA,CAAAA,CAAO,cAAA,EAGJ,KAAA,CAET,KAAK,OACH,OAAIA,CAAAA,CAAO,WACFR,CAAAA,CAAmBQ,CAAAA,CAAO,WAAYpC,CAAAA,CAASE,CAAU,EAE3D,KAAA,CAET,KAAK,UACH,GAAIkC,CAAAA,CAAO,WAAY,CACrB,IAAMF,EAAUG,CAAAA,CAASD,CAAAA,CAAO,UAAU,CAAA,CAC1C,GAAIF,CAAAA,CACF,OAAOD,EAAgBC,CAAAA,CAASlC,CAAAA,CAASE,CAAU,CAEvD,CACA,OAAO,MAAA,CAET,QACE,OAAO,MACX,CACF,CAEA,SAASoC,CAAAA,CACPF,EACArC,CAAAA,CACAC,CAAAA,CACAe,EACAb,CAAAA,CACAK,CAAAA,CAC2B,CAC3B,GAAI6B,CAAAA,CAAO,QAAS,CAClB,IAAMG,EAASjC,CAAAA,CAAqB8B,CAAAA,CAAO,QAAS7B,CAAG,CAAA,CACjDO,EAAchB,CAAAA,CAClBC,CAAAA,CACAC,EACAoC,CAAAA,CAAO,OAAA,CACPlC,CACF,CAAA,CACA,OAAOU,CAAAA,CACL2B,CAAAA,CAAO,WACPzB,CAAAA,CACAC,CAAAA,CACAwB,EAAO,SACT,CACF,CAEA,GAAIH,CAAAA,CAAO,aAAc,CACvB,IAAMhB,EAAYL,CAAAA,CAAWqB,CAAAA,CAAO,YAAY,CAAA,CAChD,GAAIhB,EACF,OAAO,CACL,UAAAA,CAAAA,CACA,YAAA,CAAcgB,EAAO,YAAA,CACrB,aAAA,CAAe,IACf,WAAA,CAAa,CAAA,CACb,kBAAmB,EACrB,CAEJ,CAGF,CAEA,SAASI,EACPC,CAAAA,CACAzC,CAAAA,CACAE,EACAK,CAAAA,CAC2B,CAC3B,GAAIkC,CAAAA,CAAK,cAAA,CAAgB,CACvB,IAAMF,EAASjC,CAAAA,CAAqBmC,CAAAA,CAAK,eAAgBlC,CAAG,CAAA,CACtDO,EAAchB,CAAAA,CAClB2C,CAAAA,CAAK,IACLzC,CAAAA,CACAyC,CAAAA,CAAK,eACLvC,CACF,CAAA,CACA,OAAOU,CAAAA,CACL2B,CAAAA,CAAO,WACPzB,CAAAA,CACA2B,CAAAA,CAAK,WACLF,CAAAA,CAAO,SACT,CACF,CAEA,GAAIE,EAAK,mBAAA,CAAqB,CAC5B,IAAMrB,CAAAA,CAAYqB,CAAAA,CAAK,WAAWA,CAAAA,CAAK,mBAAmB,EAC1D,GAAIrB,CAAAA,CACF,OAAO,CACL,SAAA,CAAAA,EACA,YAAA,CAAcqB,CAAAA,CAAK,mBAAA,CACnB,aAAA,CAAe,IACf,WAAA,CAAa,CAAA,CACb,kBAAmB,EACrB,CAEJ,CAGF,CAEA,SAASC,EAAqBN,CAAAA,CAAgC,CAC5D,OAAO,CACL,IAAA,CAAM,aACN,MAAA,CAAQA,CAAAA,CAAO,IAAM,EAAA,CACrB,QAAA,CAAUA,CAAAA,CAAO,IACnB,CACF,CAEA,SAASO,EAAmBC,CAAAA,CAAsC,CAChE,OAAIA,CAAAA,CAAc,iBAAA,EAAqB,EAC9B,CACL,IAAA,CAAM,kBACN,SAAA,CAAWA,CAAAA,CAAc,kBACzB,UAAA,CAAYA,CAAAA,CAAc,cAAgB,GAAA,CAC1C,MAAA,CAAQA,CAAAA,CAAc,WACxB,EAEK,CACL,IAAA,CAAM,qBACN,UAAA,CAAYA,CAAAA,CAAc,cAAgB,GAAA,CAC1C,MAAA,CAAQA,EAAc,WACxB,CACF,CAEO,SAASC,CAAAA,CACdJ,EACAzC,CAAAA,CACAqC,CAAAA,CACAS,EACY,CACZ,GAAI,CAACL,CAAAA,CAAK,OAAA,CAER,OAAO,CACL,KAAA,CAFmBA,EAAK,UAAA,CAAWA,CAAAA,CAAK,eAAe,CAAA,EAElC,KAAA,CACrB,aAAcA,CAAAA,CAAK,eAAA,CACnB,QAAS,CAAC,CAAE,KAAM,KAAM,CAAC,EACzB,UAAA,CAAY,EACd,CAAA,CAGF,IAAMlC,CAAAA,CAAMuC,CAAAA,EAAS,KAAO,IAAI,IAAA,CAC1B5C,EAAa,IAAI,GAAA,CAEjB6C,EAAgB,CAAC,GAAGN,EAAK,OAAO,CAAA,CAAE,KACtC,CAACO,CAAAA,CAAGC,IAAMD,CAAAA,CAAE,SAAA,CAAYC,EAAE,SAC5B,CAAA,CAEA,QAAWb,CAAAA,IAAUW,CAAAA,CACnB,GAAIZ,CAAAA,CAAeC,CAAAA,CAAQpC,EAASqC,CAAAA,CAAUnC,CAAU,EAAG,CACzD,IAAMgD,EAAWZ,CAAAA,CACfF,CAAAA,CACAK,EAAK,GAAA,CACLzC,CAAAA,CACAyC,EAAK,UAAA,CACLvC,CAAAA,CACAK,CACF,CAAA,CACA,GAAI2C,CAAAA,CAAU,CACZ,IAAMC,CAAAA,CAAoB,CAACT,EAAqBN,CAAM,CAAC,EACvD,OAAIA,CAAAA,CAAO,SACTe,CAAAA,CAAQ,IAAA,CAAKR,EAAmBO,CAAQ,CAAC,EAGpC,CACL,KAAA,CAAOA,EAAS,SAAA,CAAU,KAAA,CAC1B,aAAcA,CAAAA,CAAS,YAAA,CACvB,QAAAC,CAAAA,CACA,iBAAA,CAAmBf,EAAO,IAAA,CAC1B,UAAA,CAAY,CAAC,GAAGlC,CAAU,CAC5B,CACF,CACF,CAGF,IAAMgD,CAAAA,CAAWV,EAAwBC,CAAAA,CAAMzC,CAAAA,CAASE,CAAAA,CAAYK,CAAG,EACvE,GAAI2C,CAAAA,CAAU,CACZ,IAAMC,CAAAA,CAAoB,EAAC,CAC3B,OAAIV,EAAK,cAAA,EACPU,CAAAA,CAAQ,KAAKR,CAAAA,CAAmBO,CAAQ,CAAC,CAAA,CAE3CC,CAAAA,CAAQ,KAAK,CAAE,IAAA,CAAM,SAAU,CAAC,EAEzB,CACL,KAAA,CAAOD,EAAS,SAAA,CAAU,KAAA,CAC1B,aAAcA,CAAAA,CAAS,YAAA,CACvB,QAAAC,CAAAA,CACA,UAAA,CAAY,CAAC,GAAGjD,CAAU,CAC5B,CACF,CAEA,OAAO,CACL,KAAA,CAAO,MAAA,CACP,YAAA,CAAc,OACd,OAAA,CAAS,CAAC,CAAE,IAAA,CAAM,SAAU,CAAC,CAAA,CAC7B,UAAA,CAAY,CAAC,GAAGA,CAAU,CAC5B,CACF,CC1eO,IAAMkD,CAAAA,CAAc,OAAA,CAerBC,EAAI,UAAA,CACJC,CAAAA,CAAMD,EAAE,QAAA,CAODE,CAAAA,CAAN,KAAkB,CACN,MAAA,CAA4B,EAAC,CACtC,KAAA,CAA+C,KACtC,OAAA,CACA,kBAAA,CAA0C,KAE3D,WAAA,CAAYT,CAAAA,CAA6B,CACvC,IAAA,CAAK,OAAA,CAAUA,EACf,IAAA,CAAK,KAAA,CAAQ,YAAY,IAAM,IAAA,CAAK,KAAA,EAAM,CAAG,KAAK,OAAA,CAAQ,eAAe,EAErEQ,CAAAA,EAAK,gBAAA,GACP,KAAK,kBAAA,CAAqB,IAAM,CAC1BA,CAAAA,CAAI,eAAA,GAAoB,UAC1B,IAAA,CAAK,WAAA,GAET,CAAA,CACAA,CAAAA,CAAI,iBAAiB,kBAAA,CAAoB,IAAA,CAAK,kBAAkB,CAAA,EAEpE,CAEA,KAAKE,CAAAA,CAA8B,CACjC,KAAK,MAAA,CAAO,IAAA,CAAKA,CAAK,CAAA,CAClB,IAAA,CAAK,OAAO,MAAA,EAAU,IAAA,CAAK,QAAQ,YAAA,EACrC,IAAA,CAAK,QAET,CAEQ,aAAaC,CAAAA,CAAkD,CACrE,OAAO,CACL,KAAM,CACJ,GAAG,KAAK,OAAA,CAAQ,IAAA,CAChB,WAAYL,CACd,CAAA,CACA,OAAQK,CACV,CACF,CAEA,KAAA,EAAc,CACZ,GAAI,IAAA,CAAK,MAAA,CAAO,SAAW,CAAA,CACzB,OAEF,IAAMA,CAAAA,CAAQ,IAAA,CAAK,OAAO,MAAA,CAAO,CAAA,CAAG,KAAK,OAAA,CAAQ,YAAY,EACvDC,CAAAA,CAAU,IAAA,CAAK,aAAaD,CAAK,CAAA,CAEvC,MAAM,CAAA,EAAG,IAAA,CAAK,QAAQ,OAAO,CAAA,gBAAA,CAAA,CAAoB,CAC/C,MAAA,CAAQ,MAAA,CACR,OAAA,CAAS,CACP,eAAgB,kBAAA,CAChB,aAAA,CAAe,UAAU,IAAA,CAAK,OAAA,CAAQ,MAAM,CAAA,CAC9C,CAAA,CACA,KAAM,IAAA,CAAK,SAAA,CAAUC,CAAO,CAC9B,CAAC,EAAE,KAAA,CAAM,IAAM,CAEf,CAAC,EACH,CAMQ,WAAA,EAAoB,CAC1B,GAAI,IAAA,CAAK,OAAO,MAAA,GAAW,CAAA,CACzB,OAGF,IAAMD,CAAAA,CAAQ,KAAK,MAAA,CAAO,MAAA,CAAO,EAAG,IAAA,CAAK,OAAA,CAAQ,YAAY,CAAA,CACvDC,CAAAA,CAAU,KAAK,YAAA,CAAaD,CAAK,CAAA,CAEvC,KAAA,CAAM,GAAG,IAAA,CAAK,OAAA,CAAQ,OAAO,CAAA,gBAAA,CAAA,CAAoB,CAC/C,OAAQ,MAAA,CACR,OAAA,CAAS,CACP,cAAA,CAAgB,kBAAA,CAChB,cAAe,CAAA,OAAA,EAAU,IAAA,CAAK,QAAQ,MAAM,CAAA,CAC9C,EACA,IAAA,CAAM,IAAA,CAAK,UAAUC,CAAO,CAAA,CAC5B,UAAW,IACb,CAAC,EAAE,KAAA,CAAM,IAAM,CAEf,CAAC,EACH,CAEA,OAAA,EAAgB,CACV,KAAK,KAAA,GACP,aAAA,CAAc,KAAK,KAAK,CAAA,CACxB,KAAK,KAAA,CAAQ,IAAA,CAAA,CAEX,IAAA,CAAK,kBAAA,EAAsBJ,GAAK,mBAAA,EAClCA,CAAAA,CAAI,oBAAoB,kBAAA,CAAoB,IAAA,CAAK,kBAAkB,CAAA,CAErE,IAAA,CAAK,QACP,CACF,ECxGA,IAAMK,CAAAA,CAAmB,mCACnBC,CAAAA,CAAW,aAAA,CACXC,EAAU,YAAA,CAIhB,SAASC,GAA8B,CACrC,GAAI,CACF,IAAMT,CAAAA,CAAI,WACJU,CAAAA,CAAMV,CAAAA,CAAE,UAGd,GAAIU,CAAAA,EAAOA,EAAI,OAAA,GAAY,aAAA,CACzB,OAAO,cAAA,CAET,IAAMC,EAAMX,CAAAA,CAAE,MAAA,CACd,GAAIW,CAAAA,EAAO,OAAOA,CAAAA,CAAI,QAAA,CAAa,IACjC,OAAO,SAAA,CAGT,GADaX,CAAAA,CAAE,OAAA,EACL,UAAU,IAAA,CAClB,OAAO,OAET,GAAI,OAAO,WAAe,GAAA,CACxB,OAAO,MAEX,CAAA,KAAQ,CAER,CACA,OAAO,SACT,CAEA,IAAMY,CAAAA,CAAeH,GAAe,CAE9BI,CAAAA,CAAQ,WAAuC,OAAA,CAG/CC,CAAAA,CAAY,OAAOD,CAAAA,EAAM,MAAA,EAAQ,QAAW,UAAA,CAElD,SAASE,GAAyB,CAChC,OAAID,EAEKD,CAAAA,CAAM,MAAA,CAAQ,QAAQ,CAE3B,OAAO,WAAA,CAAgB,GAAA,CAClB,YAAY,GAAA,EAAI,CAElB,KAAK,GAAA,EACd,CAEA,SAASG,CAAAA,CAAUC,EAAgC,CACjD,IAAMC,EAAMH,CAAAA,EAAM,CAClB,OAAI,OAAOE,CAAAA,EAAU,UAAY,OAAOC,CAAAA,EAAQ,QAAA,CAEvC,MAAA,CAAA,CAAQA,EAAMD,CAAAA,EAAS,KAAK,EAG9B,IAAA,CAAK,KAAA,CAAA,CAAQC,EAAkBD,CAAAA,EAAoB,GAAI,CAChE,CAgEA,IAAME,EAAN,KAAuC,CACpB,OACA,WAAA,CACA,OAAA,CACA,YACT,QAAA,CAAuC,IAAA,CACvC,iBAAA,CAAuC,GAC9B,eAAA,CAAmC,IAAI,IAChD,WAAA,CAAkC,IAAA,CAClC,KAAsB,IAAA,CACb,aAAA,CACA,sBACA,kBAAA,CACA,eAAA,CACA,eACA,iBAAA,CACT,YAAA,CAAsD,KACtD,EAAA,CAAuB,IAAA,CACvB,eAAuD,IAAA,CACvD,iBAAA,CAAoB,EAEnB,IAAA,CAET,WAAA,CAAY1B,EAAyB,CACnC,IAAA,CAAK,OAASA,CAAAA,CAAQ,MAAA,CACtB,KAAK,WAAA,CAAcA,CAAAA,CAAQ,YAC3B,IAAA,CAAK,OAAA,CAAUA,EAAQ,OAAA,EAAWa,CAAAA,CAClC,KAAK,aAAA,CAAgBb,CAAAA,CAAQ,QAAQ,OAAA,EAAW,IAAA,CAChD,IAAA,CAAK,qBAAA,CAAwBA,EAAQ,MAAA,EAAQ,eAAA,EAAmB,IAChE,IAAA,CAAK,kBAAA,CAAqBA,EAAQ,MAAA,EAAQ,YAAA,EAAgB,IAE1D,IAAM2B,CAAAA,CAAe,OAAO,UAAA,CAAW,SAAA,CAAc,IACrD,IAAA,CAAK,eAAA,CAAkB3B,EAAQ,QAAA,EAAU,OAAA,EAAW2B,EACpD,IAAA,CAAK,cAAA,CAAiB3B,EAAQ,OAAA,EAAS,OAAA,EAAW,KAClD,IAAA,CAAK,iBAAA,CAAoBA,EAAQ,OAAA,EAAS,UAAA,EAAc,IAExD,IAAA,CAAK,WAAA,CAAc,KAAK,IAAA,EAAK,CAE7B,KAAK,IAAA,CAAO,CACV,UAAW,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,IAAI,EACvC,GAAA,CAAK,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAI,EAC3B,QAAA,CAAU,IAAA,CAAK,aAAa,IAAA,CAAK,IAAI,EACrC,KAAA,CAAO,IAAA,CAAK,UAAU,IAAA,CAAK,IAAI,CACjC,EACF,CAEA,MAAc,IAAA,EAAsB,CAClC,IAAM4B,CAAAA,CAAe,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,SAAA,CAAA,CAAa,CAC3D,OAAQ,MAAA,CACR,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,EAC9C,IAAA,CAAM,IAAA,CAAK,UAAU,CAAE,MAAA,CAAQ,IAAA,CAAK,MAAO,CAAC,CAC9C,CAAC,EAED,GAAI,CAACA,EAAa,EAAA,CAAI,CACpB,IAAMC,CAAAA,CAAQ,MAAMD,EAAa,IAAA,EAAK,CAAE,MAAM,KAAO,GAAG,CAAA,CACxD,MAAM,IAAI,KAAA,CACR,mCAAoCC,CAAAA,CAA6B,KAAA,EAASD,EAAa,UAAU,CAAA,CACnG,CACF,CAEA,IAAME,EAAY,MAAMF,CAAAA,CAAa,MAAK,CAK1C,GAAI,CAACE,CAAAA,CAAS,KAAA,CACZ,MAAM,IAAI,KAAA,CACR,CAAA,2BAAA,EAA8BA,CAAAA,CAAS,OAAS,eAAe,CAAA,CACjE,EAGE,IAAA,CAAK,eAAA,CACP,MAAM,IAAA,CAAK,gBAAA,IAEX,MAAM,IAAA,CAAK,eAAc,CACzB,IAAA,CAAK,cAAa,CAAA,CAGpB,IAAA,CAAK,wBACP,CAEQ,uBAA8B,CAChC,IAAA,CAAK,eAAiB,IAAA,CAAK,QAAA,EAAU,OACvC,IAAA,CAAK,WAAA,CAAc,IAAIrB,CAAAA,CAAY,CACjC,QAAS,IAAA,CAAK,OAAA,CACd,OAAQ,IAAA,CAAK,MAAA,CACb,KAAM,CACJ,SAAA,CAAW,KAAK,QAAA,CAAS,IAAA,CAAK,SAAA,CAC9B,cAAA,CAAgB,KAAK,QAAA,CAAS,IAAA,CAAK,eACnC,aAAA,CAAe,IAAA,CAAK,SAAS,IAAA,CAAK,aAAA,CAClC,YAAaU,CACf,CAAA,CACA,gBAAiB,IAAA,CAAK,qBAAA,CACtB,aAAc,IAAA,CAAK,kBACrB,CAAC,CAAA,EAEL,CAEA,MAAc,aAAA,EAA+B,CAC3C,IAAMY,CAAAA,CAAkC,CACtC,cAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CACtC,CAAA,CACI,KAAK,IAAA,GACPA,CAAAA,CAAQ,eAAe,CAAA,CAAI,IAAA,CAAK,MAGlC,IAAMC,CAAAA,CAAW,MAAM,KAAA,CACrB,CAAA,EAAG,IAAA,CAAK,OAAO,6BAA6B,kBAAA,CAAmB,IAAA,CAAK,WAAW,CAAC,CAAA,CAAA,CAChF,CAAE,OAAA,CAAAD,CAAQ,CACZ,CAAA,CAEA,GAAIC,EAAS,MAAA,GAAW,GAAA,CACtB,OAGF,GAAI,CAACA,EAAS,EAAA,CAAI,CAChB,IAAMH,CAAAA,CAAQ,MAAMG,EAAS,IAAA,EAAK,CAAE,MAAM,KAAO,GAAG,CAAA,CACpD,MAAM,IAAI,KAAA,CACR,CAAA,oCAAA,EAAwCH,EAA6B,KAAA,EAASG,CAAAA,CAAS,UAAU,CAAA,CACnG,CACF,CAEA,IAAMC,CAAAA,CAAOD,CAAAA,CAAS,OAAA,CAAQ,IAAI,MAAM,CAAA,CACpCC,IACF,IAAA,CAAK,IAAA,CAAOA,GAEd,IAAA,CAAK,QAAA,CAAY,MAAMD,CAAAA,CAAS,IAAA,GAClC,CAEQ,YAAA,EAAqB,CACtB,IAAA,CAAK,cAAA,GAGV,KAAK,YAAA,CAAe,WAAA,CAAY,SAAY,CAC1C,GAAI,CACF,IAAME,EAAkB,IAAA,CAAK,QAAA,EAAU,QAEvC,GADA,MAAM,KAAK,aAAA,EAAc,CACrB,KAAK,QAAA,EAAY,IAAA,CAAK,SAAS,OAAA,GAAYA,CAAAA,CAC7C,QAAWC,CAAAA,IAAM,IAAA,CAAK,eAAA,CACpBA,CAAAA,GAGN,CAAA,MAASN,CAAAA,CAAO,CACd,OAAA,CAAQ,IAAA,CAAK,kCAAmCA,CAAK,EACvD,CACF,CAAA,CAAG,IAAA,CAAK,iBAAiB,CAAA,EAC3B,CAEQ,kBAAkC,CACxC,OAAO,IAAI,OAAA,CAAc,CAACO,EAASC,CAAAA,GAAW,CAI5C,IAAMC,CAAAA,CAAQ,CAAA,EAHC,KAAK,OAAA,CACjB,OAAA,CAAQxB,EAAU,QAAQ,CAAA,CAC1B,QAAQC,CAAAA,CAAS,OAAO,CACJ,CAAA,oBAAA,EAAuB,kBAAA,CAAmB,KAAK,MAAM,CAAC,gBAAgB,kBAAA,CAAmB,IAAA,CAAK,WAAW,CAAC,GAE3HwB,CAAAA,CAAK,IAAI,UAAUD,CAAK,CAAA,CAC9B,KAAK,EAAA,CAAKC,CAAAA,CACV,IAAInC,CAAAA,CAAW,KAAA,CAEfmC,EAAG,SAAA,CAAa7B,CAAAA,EAAwB,CACtC,GAAI,CACF,IAAM8B,CAAAA,CAAc,IAAA,CAAK,MACvB,OAAO9B,CAAAA,CAAM,MAAS,QAAA,CAAWA,CAAAA,CAAM,KAAO,EAChD,CAAA,CACMwB,EAAkB,IAAA,CAAK,QAAA,EAAU,QAOvC,GANA,IAAA,CAAK,SAAWM,CAAAA,CAEZA,CAAAA,CAAY,UACd,IAAA,CAAK,IAAA,CAAO,IAAIA,CAAAA,CAAY,OAAO,CAAA,CAAA,CAAA,CAAA,CAGjC,CAACpC,EACHA,CAAAA,CAAW,CAAA,CAAA,CACX,KAAK,iBAAA,CAAoB,CAAA,CACzBgC,GAAQ,CAAA,KAAA,GACCI,CAAAA,CAAY,UAAYN,CAAAA,CACjC,IAAA,IAAWC,KAAM,IAAA,CAAK,eAAA,CACpBA,IAGN,CAAA,MAASM,EAAK,CACZ,OAAA,CAAQ,KAAK,4CAAA,CAA8CA,CAAG,EACzDrC,CAAAA,GACHA,CAAAA,CAAW,KACX,IAAA,CAAK,iBAAA,CAAkBgC,EAASC,CAAM,CAAA,EAE1C,CACF,CAAA,CAEAE,CAAAA,CAAG,QAAU,IAAM,CACZnC,IACHA,CAAAA,CAAW,IAAA,CACXmC,EAAG,KAAA,EAAM,CACT,IAAA,CAAK,EAAA,CAAK,KACV,IAAA,CAAK,iBAAA,CAAkBH,EAASC,CAAM,CAAA,EAE1C,EAEAE,CAAAA,CAAG,OAAA,CAAU,IAAM,CACjB,GAAI,CAACnC,CAAAA,CAAU,CACbA,EAAW,IAAA,CACX,IAAA,CAAK,GAAK,IAAA,CACV,IAAA,CAAK,iBAAA,CAAkBgC,CAAAA,CAASC,CAAM,CAAA,CACtC,MACF,CAEA,IAAA,CAAK,EAAA,CAAK,KACV,IAAA,CAAK,iBAAA,GACP,EACF,CAAC,CACH,CAEQ,iBAAA,CACND,EACAC,CAAAA,CACM,CACN,QAAQ,IAAA,CAAK,oDAAoD,CAAA,CACjE,IAAA,CAAK,eAAc,CAChB,IAAA,CAAK,IAAM,CACV,IAAA,CAAK,cAAa,CAClBD,CAAAA,GACF,CAAC,CAAA,CACA,MAAMC,CAAM,EACjB,CAEQ,iBAAA,EAA0B,CAChC,GAAI,IAAA,CAAK,cAAA,CACP,OAEF,IAAMK,CAAAA,CAAQ,KAAK,GAAA,CAAI,GAAA,CAAO,GAAK,IAAA,CAAK,iBAAA,CAAmB,GAAM,CAAA,CACjE,IAAA,CAAK,oBAEL,IAAA,CAAK,cAAA,CAAiB,WAAW,IAAM,CACrC,KAAK,cAAA,CAAiB,IAAA,CACtB,KAAK,kBAAA,GACP,CAAA,CAAGA,CAAK,EACV,CAEQ,kBAAA,EAA2B,CAIjC,IAAMJ,CAAAA,CAAQ,GAHC,IAAA,CAAK,OAAA,CACjB,QAAQxB,CAAAA,CAAU,QAAQ,EAC1B,OAAA,CAAQC,CAAAA,CAAS,OAAO,CACJ,CAAA,oBAAA,EAAuB,mBAAmB,IAAA,CAAK,MAAM,CAAC,CAAA,aAAA,EAAgB,kBAAA,CAAmB,KAAK,WAAW,CAAC,GAE3HwB,CAAAA,CAAK,IAAI,UAAUD,CAAK,CAAA,CAC9B,KAAK,EAAA,CAAKC,CAAAA,CAEVA,EAAG,SAAA,CAAa7B,CAAAA,EAAwB,CACtC,GAAI,CACF,IAAM8B,CAAAA,CAAc,IAAA,CAAK,KAAA,CACvB,OAAO9B,EAAM,IAAA,EAAS,QAAA,CAAWA,EAAM,IAAA,CAAO,EAChD,EACMwB,CAAAA,CAAkB,IAAA,CAAK,UAAU,OAAA,CAIvC,GAHA,KAAK,QAAA,CAAWM,CAAAA,CAChB,KAAK,iBAAA,CAAoB,CAAA,CAErBA,EAAY,OAAA,GAAYN,CAAAA,CAC1B,QAAWC,CAAAA,IAAM,IAAA,CAAK,gBACpBA,CAAAA,GAGN,OAASM,CAAAA,CAAK,CACZ,QAAQ,IAAA,CAAK,4CAAA,CAA8CA,CAAG,EAChE,CACF,EAEAF,CAAAA,CAAG,OAAA,CAAU,IAAM,CAEnB,CAAA,CAEAA,EAAG,OAAA,CAAU,IAAM,CACjB,IAAA,CAAK,GAAK,IAAA,CACV,IAAA,CAAK,oBACP,EACF,CAEQ,WAAA,EAAmC,CACzC,GAAI,CAAC,IAAA,CAAK,SACR,MAAM,IAAI,MACR,6DACF,CAAA,CAEF,OAAO,IAAA,CAAK,QACd,CAEQ,YAAA,CAAavC,EAEC,CACpB,IAAM2C,EAA4B,EAAC,CAC7BC,EAAW,IAAI,GAAA,CAAI,CACvB,GAAG,MAAA,CAAO,KAAK,IAAA,CAAK,iBAAiB,EACrC,GAAG,MAAA,CAAO,KAAK5C,CAAAA,EAAS,OAAA,EAAW,EAAE,CACvC,CAAC,CAAA,CACD,QAAW6C,CAAAA,IAAQD,CAAAA,CACjBD,EAAOE,CAAI,CAAA,CAAI,CACb,GAAG,IAAA,CAAK,kBAAkBA,CAAI,CAAA,CAC9B,GAAG7C,CAAAA,EAAS,OAAA,GAAU6C,CAAI,CAC5B,CAAA,CAEF,OAAOF,CACT,CAEQ,YACNG,CAAAA,CACA5F,CAAAA,CAKA,CACA,IAAM6F,CAAAA,CAAW,KAAK,WAAA,EAAY,CAClC,GAAI,CAACA,CAAAA,CAAS,MACZ,OAAO,CAAE,OAAQ,IAAA,CAAM,QAAA,CAAAA,EAAU,UAAA,CAAY,CAAE,CAAA,CAEjD,IAAMpD,EAAOoD,CAAAA,CAAS,KAAA,CAAMD,CAAG,CAAA,CAC/B,GAAI,CAACnD,CAAAA,CACH,OAAO,CAAE,MAAA,CAAQ,IAAA,CAAM,SAAAoD,CAAAA,CAAU,UAAA,CAAY,CAAE,CAAA,CAGjD,IAAMC,EAAY1B,CAAAA,EAAM,CACpB2B,EACJ,GAAI,CACFA,EAASlD,CAAAA,CAAaJ,CAAAA,CAAMzC,EAAS6F,CAAAA,CAAS,QAAA,EAAY,EAAE,EAC9D,OAASN,CAAAA,CAAK,CACZ,IAAMS,CAAAA,CAAcT,CAAAA,YAAe,MAAQA,CAAAA,CAAI,OAAA,CAAU,OAAOA,CAAG,CAAA,CACnEQ,CAAAA,CAAS,CACP,MAAO,MAAA,CACP,YAAA,CAAc,OACd,OAAA,CAAS,CAAC,CAAE,IAAA,CAAM,OAAA,CAAS,OAAQC,CAAY,CAAC,EAChD,WAAA,CAAAA,CACF,EACF,CAEA,OAAO,CAAE,MAAA,CAAAD,CAAAA,CAAQ,SAAAF,CAAAA,CAAU,UAAA,CAAYxB,EAAUyB,CAAS,CAAE,CAC9D,CAEQ,WAAA,CACNF,EACAG,CAAAA,CACAE,CAAAA,CACAC,EACqB,CACrB,IAAMC,EAAYJ,CAAAA,CAAO,OAAA,CAAQ,KAC9BK,CAAAA,EACCA,CAAAA,CAAE,OAAS,YACf,CAAA,CAEA,OAAO,CACL,cAAe,CAAA,CACf,GAAA,CAAAR,EACA,KAAA,CAAOG,CAAAA,CAAO,MACd,YAAA,CAAcA,CAAAA,CAAO,aACrB,OAAA,CAASA,CAAAA,CAAO,QAChB,MAAA,CAAQI,CAAAA,EAAW,OACnB,WAAA,CAAAF,CAAAA,CACA,YAAa,IAAI,IAAA,EAAK,CAAE,WAAA,GACxB,oBAAA,CAAsBC,CAAAA,CACtB,WAAYH,CAAAA,CAAO,UAAA,CACnB,QAAS,MAAA,CAAO,UAAA,EAClB,CACF,CAEQ,iBAAiBH,CAAAA,CAAa5F,CAAAA,CAAqC,CACzE,GAAM,CAAE,OAAA+F,CAAAA,CAAQ,QAAA,CAAAF,CAAAA,CAAU,UAAA,CAAAK,CAAW,CAAA,CAAI,IAAA,CAAK,YAAYN,CAAAA,CAAK5F,CAAO,EAChEqG,CAAAA,CAAc,IAAI,MAAK,CAAE,WAAA,GACzBC,CAAAA,CAAU,MAAA,CAAO,YAAW,CAElC,GAAI,CAACP,CAAAA,CAAQ,CACX,KAAK,UAAA,CAAW,CACd,IAAAH,CAAAA,CACA,YAAA,CAAc,OACd,KAAA,CAAO,MAAA,CACP,QAAS,CAAC,CAAE,KAAM,OAAA,CAAS,MAAA,CAAQ,gBAAiB,CAAC,CAAA,CACrD,QAAA5F,CAAAA,CACA,WAAA,CAAa6F,EAAS,OAAA,CACtB,aAAA,CAAe,CAAA,CACf,WAAA,CAAAQ,EACA,OAAA,CAAAC,CACF,CAAC,CAAA,CACD,MACF,CAEA,OAAA,IAAA,CAAK,UAAA,CAAW,CACd,GAAA,CAAAV,CAAAA,CACA,aAAcG,CAAAA,CAAO,YAAA,CACrB,MAAOA,CAAAA,CAAO,KAAA,CACd,QAASA,CAAAA,CAAO,OAAA,CAChB,QAAA/F,CAAAA,CACA,iBAAA,CAAmB+F,EAAO,iBAAA,CAC1B,WAAA,CAAaF,EAAS,OAAA,CACtB,WAAA,CAAaE,EAAO,WAAA,CACpB,oBAAA,CAAsBG,EACtB,aAAA,CAAe,CAAA,CACf,YAAAG,CAAAA,CACA,UAAA,CAAYN,EAAO,UAAA,CACnB,OAAA,CAAAO,CACF,CAAC,CAAA,CAEMP,CAAAA,CAAO,KAChB,CAEQ,UAAA,CAAWQ,CAAAA,CAgBV,CACP,GAAI,CAAC,KAAK,WAAA,CACR,OAEF,GAAM,CAAE,OAAA,CAAAvG,CAAQ,CAAA,CAAIuG,CAAAA,CACdC,EAAe,MAAA,CAAO,IAAA,CAAKxG,CAAO,CAAA,CAClCyG,CAAAA,CAAwC,EAAC,CAC/C,IAAA,IAAWd,KAAQa,CAAAA,CACjBC,CAAAA,CAAYd,CAAI,CAAA,CAAI,MAAA,CAAO,KAAK3F,CAAAA,CAAQ2F,CAAI,GAAK,EAAE,EAGrD,IAAMe,CAAAA,CACJF,EAAa,MAAA,GAAW,CAAA,EACxBA,EAAa,KAAA,CACVb,CAAAA,EAAS,MAAA,CAAO,IAAA,CAAK3F,EAAQ2F,CAAI,CAAA,EAAK,EAAE,CAAA,CAAE,SAAW,CACxD,CAAA,CAEF,KAAK,WAAA,CAAY,IAAA,CAAK,CACpB,aAAA,CAAeY,CAAAA,CAAO,eAAiB,CAAA,CACvC,GAAA,CAAKA,EAAO,GAAA,CACZ,YAAA,CAAcA,CAAAA,CAAO,YAAA,CACrB,MAAOA,CAAAA,CAAO,KAAA,CACd,QAASA,CAAAA,CAAO,OAAA,CAChB,YAAaA,CAAAA,CAAO,WAAA,EAAe,IAAI,IAAA,EAAK,CAAE,aAAY,CAC1D,MAAA,CAAQA,EAAO,MAAA,CACf,WAAA,CAAaA,EAAO,WAAA,EAAe,CAAA,CACnC,aAAA,CAAeA,CAAAA,CAAO,cACtB,UAAA,CAAYA,CAAAA,CAAO,WACnB,OAAA,CAASA,CAAAA,CAAO,QAChB,YAAA,CAAAC,CAAAA,CACA,YAAAC,CAAAA,CACA,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,kBAAmBF,CAAAA,CAAO,iBAAA,CAC1B,YAAaA,CAAAA,CAAO,WAAA,CACpB,qBAAsBA,CAAAA,CAAO,oBAAA,CAC7B,YAAAG,CACF,CAAC,EACH,CAEA,MAAM,OAAuB,CAC3B,MAAM,KAAK,YACb,CAEA,SAAmB,CACjB,OAAO,KAAK,QAAA,GAAa,IAC3B,CAEA,MAAM,SAAA,CAAUd,CAAAA,CAAa9C,CAAAA,CAA8C,CACzE,MAAM,IAAA,CAAK,YACX,IAAMpB,CAAAA,CAAQ,KAAK,gBAAA,CAAiBkE,CAAAA,CAAK,KAAK,YAAA,CAAa9C,CAAO,CAAC,CAAA,CACnE,OAAO,OAAOpB,CAAAA,EAAU,SAAA,CAAYA,EAAQ,KAC9C,CAEA,MAAM,GAAA,CAAOkE,CAAAA,CAAa9C,EAAqC,CAC7D,MAAM,KAAK,WAAA,CACX,IAAMpB,EAAQ,IAAA,CAAK,gBAAA,CAAiBkE,EAAK,IAAA,CAAK,YAAA,CAAa9C,CAAO,CAAC,CAAA,CACnE,OAA8BpB,CAAAA,EAE1BoB,CAAAA,CAAQ,QACd,CAEA,MAAM,QAAA,CACJ8C,CAAAA,CACA9C,EAC8B,CAC9B,MAAM,KAAK,WAAA,CACX,IAAM9C,EAAU,IAAA,CAAK,YAAA,CAAa8C,CAAO,CAAA,CACnC,CAAE,OAAAiD,CAAAA,CAAQ,QAAA,CAAAF,EAAU,UAAA,CAAAK,CAAW,EAAI,IAAA,CAAK,WAAA,CAAYN,EAAK5F,CAAO,CAAA,CAEtE,GAAI,CAAC+F,CAAAA,CAAQ,CACX,IAAMO,CAAAA,CAAU,OAAO,UAAA,EAAW,CAC5BD,EAAc,IAAI,IAAA,GAAO,WAAA,EAAY,CACrCM,EAA8B,CAClC,aAAA,CAAe,EACf,GAAA,CAAAf,CAAAA,CACA,KAAA,CAAO,MAAA,CACP,aAAc,MAAA,CACd,OAAA,CAAS,CAAC,CAAE,IAAA,CAAM,QAAS,MAAA,CAAQ,gBAAiB,CAAC,CAAA,CACrD,WAAA,CAAaC,EAAS,OAAA,CACtB,WAAA,CAAAQ,EACA,OAAA,CAAAC,CACF,EACA,OAAA,IAAA,CAAK,UAAA,CAAW,CACd,GAAA,CAAAV,EACA,YAAA,CAAc,MAAA,CACd,MAAO,MAAA,CACP,OAAA,CAASe,EAAO,OAAA,CAChB,WAAA,CAAAN,EACA,OAAA,CAAArG,CAAAA,CACA,YAAa6F,CAAAA,CAAS,OAAA,CACtB,cAAe,CAAA,CACf,OAAA,CAAAS,CACF,CAAC,CAAA,CACMK,CACT,CAEA,IAAMA,CAAAA,CAAS,IAAA,CAAK,YAClBf,CAAAA,CACAG,CAAAA,CACAF,EAAS,OAAA,CACTK,CACF,EAEA,OAAA,IAAA,CAAK,UAAA,CAAW,CACd,GAAA,CAAAN,CAAAA,CACA,aAAcG,CAAAA,CAAO,YAAA,CACrB,MAAOA,CAAAA,CAAO,KAAA,CACd,QAASA,CAAAA,CAAO,OAAA,CAChB,YAAaY,CAAAA,CAAO,WAAA,CACpB,OAAQA,CAAAA,CAAO,MAAA,CACf,QAAA3G,CAAAA,CACA,iBAAA,CAAmB+F,EAAO,iBAAA,CAC1B,WAAA,CAAaF,EAAS,OAAA,CACtB,WAAA,CAAaE,EAAO,WAAA,CACpB,oBAAA,CAAsBG,EACtB,aAAA,CAAe,CAAA,CACf,UAAA,CAAYH,CAAAA,CAAO,WACnB,OAAA,CAASY,CAAAA,CAAO,OAClB,CAAC,CAAA,CAEMA,CACT,CAEQ,aAAA,CAAcf,EAAa9C,CAAAA,CAAqC,CACtE,IAAMpB,CAAAA,CAAQ,IAAA,CAAK,iBAAiBkE,CAAAA,CAAK,IAAA,CAAK,aAAa9C,CAAO,CAAC,EACnE,OAAO,OAAOpB,GAAU,SAAA,CAAYA,CAAAA,CAAQ,KAC9C,CAEQ,OAAA,CAAWkE,EAAa9C,CAAAA,CAA4B,CAC1D,IAAMpB,CAAAA,CAAQ,IAAA,CAAK,iBAAiBkE,CAAAA,CAAK,IAAA,CAAK,aAAa9C,CAAO,CAAC,EACnE,OAA8BpB,CAAAA,EAE1BoB,CAAAA,CAAQ,QACd,CAEQ,YAAA,CACN8C,CAAAA,CACA9C,EACqB,CACrB,IAAM9C,EAAU,IAAA,CAAK,YAAA,CAAa8C,CAAO,CAAA,CACnC,CAAE,OAAAiD,CAAAA,CAAQ,QAAA,CAAAF,EAAU,UAAA,CAAAK,CAAW,EAAI,IAAA,CAAK,WAAA,CAAYN,EAAK5F,CAAO,CAAA,CAEtE,OAAK+F,CAAAA,CAcE,IAAA,CAAK,YAAeH,CAAAA,CAAKG,CAAAA,CAAQF,EAAS,OAAA,CAASK,CAAU,EAb3D,CACL,aAAA,CAAe,EACf,GAAA,CAAAN,CAAAA,CACA,MAAO,MAAA,CACP,YAAA,CAAc,OACd,OAAA,CAAS,CAAC,CAAE,IAAA,CAAM,QAAS,MAAA,CAAQ,gBAAiB,CAAC,CAAA,CACrD,WAAA,CAAaC,EAAS,OAAA,CACtB,WAAA,CAAa,IAAI,IAAA,EAAK,CAAE,aAAY,CACpC,oBAAA,CAAsBK,EACtB,OAAA,CAAS,MAAA,CAAO,YAClB,CAIJ,CAEQ,SAAA,CACNN,EACAe,CAAAA,CACA3G,CAAAA,CACM,CACN,IAAMmG,CAAAA,CAAYQ,EAAO,OAAA,CAAQ,IAAA,CAC9B,GACC,CAAA,CAAE,IAAA,GAAS,YACf,CAAA,CAEA,IAAA,CAAK,WAAW,CACd,GAAA,CAAAf,EACA,YAAA,CAAce,CAAAA,CAAO,YAAA,CACrB,KAAA,CAAOA,EAAO,KAAA,CACd,OAAA,CAASA,EAAO,OAAA,CAChB,WAAA,CAAaA,EAAO,WAAA,CACpB,MAAA,CAAQA,EAAO,MAAA,CACf,OAAA,CAAS,KAAK,YAAA,CAAa,CAAE,QAAA3G,CAAQ,CAAC,EACtC,iBAAA,CAAmBmG,CAAAA,EAAW,SAC9B,WAAA,CAAaQ,CAAAA,CAAO,YACpB,oBAAA,CAAsBA,CAAAA,CAAO,qBAC7B,aAAA,CAAeA,CAAAA,CAAO,cACtB,aAAA,CAAeA,CAAAA,CAAO,cACtB,UAAA,CAAYA,CAAAA,CAAO,WACnB,OAAA,CAASA,CAAAA,CAAO,OAClB,CAAC,EACH,CAEA,QAAA,CAAS3G,CAAAA,CAAkC,CACzC,IAAA,CAAK,kBAAoB,CAAE,GAAGA,CAAQ,EACxC,CAEA,OAAc,CACZ,IAAA,CAAK,kBAAoB,GAC3B,CAEA,MAAM,OAAA,EAAyB,CAC7B,MAAM,IAAA,CAAK,gBACb,CAEA,aAA0C,CACxC,OAAO,KAAK,QACd,CAEA,SAAS4G,CAAAA,CAAkC,CACzC,YAAK,eAAA,CAAgB,GAAA,CAAIA,CAAQ,CAAA,CAC1B,IAAM,KAAK,eAAA,CAAgB,MAAA,CAAOA,CAAQ,CACnD,CAEA,OAAc,CACR,IAAA,CAAK,EAAA,GACP,IAAA,CAAK,GAAG,KAAA,EAAM,CACd,KAAK,EAAA,CAAK,IAAA,CAAA,CAER,KAAK,cAAA,GACP,YAAA,CAAa,KAAK,cAAc,CAAA,CAChC,KAAK,cAAA,CAAiB,IAAA,CAAA,CAEpB,KAAK,YAAA,GACP,aAAA,CAAc,KAAK,YAAY,CAAA,CAC/B,KAAK,YAAA,CAAe,IAAA,CAAA,CAElB,KAAK,WAAA,GACP,IAAA,CAAK,YAAY,OAAA,EAAQ,CACzB,KAAK,WAAA,CAAc,IAAA,EAEvB,CACF,CAAA,CA2BO,SAASC,EAAc/D,CAAAA,CAAkC,CAC9D,OAAO,IAAI0B,CAAAA,CAAc1B,CAAO,CAClC","file":"index.js","sourcesContent":["import type {\n EvalOutput,\n EvaluationContext,\n Reason,\n SnapshotFlag,\n SnapshotIndividualEntry,\n SnapshotRollout,\n SnapshotRolloutVariation,\n SnapshotRuleCondition,\n SnapshotScheduleStep,\n SnapshotSegment,\n SnapshotTarget,\n SnapshotVariation,\n} from \"./types\";\n\nfunction hashString(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n // biome-ignore lint/suspicious/noBitwiseOperators: intentional hash algorithm using bitwise shift\n hash = (hash << 5) - hash + char;\n // biome-ignore lint/suspicious/noBitwiseOperators: converting to 32-bit integer\n hash |= 0;\n }\n return Math.abs(hash);\n}\n\nfunction getBucketValue(\n flagKey: string,\n context: EvaluationContext,\n rollout: SnapshotRollout,\n inputsUsed: Set<string>\n): number {\n inputsUsed.add(`${rollout.bucketContextKind}.${rollout.bucketAttributeKey}`);\n const bucketKey =\n context[rollout.bucketContextKind]?.[rollout.bucketAttributeKey];\n const seed = rollout.seed ?? \"\";\n const hashInput = `${flagKey}:${seed}:${String(bucketKey ?? \"anonymous\")}`;\n return hashString(hashInput) % 100_000;\n}\n\ninterface ActiveRollout {\n variations: SnapshotRolloutVariation[];\n stepIndex: number;\n}\n\nfunction resolveActiveRollout(\n rollout: SnapshotRollout,\n now: Date\n): ActiveRollout {\n if (!(rollout.schedule && rollout.startedAt)) {\n return { variations: rollout.variations, stepIndex: -1 };\n }\n\n const startedAt = new Date(rollout.startedAt).getTime();\n const elapsedMs = now.getTime() - startedAt;\n const elapsedMinutes = elapsedMs / 60_000;\n\n if (elapsedMinutes < 0) {\n return {\n variations: rollout.schedule[0]?.variations ?? rollout.variations,\n stepIndex: 0,\n };\n }\n\n let cumulativeMinutes = 0;\n for (let i = 0; i < rollout.schedule.length; i++) {\n const step = rollout.schedule[i] as SnapshotScheduleStep;\n if (step.durationMinutes === 0) {\n return { variations: step.variations, stepIndex: i };\n }\n cumulativeMinutes += step.durationMinutes;\n if (elapsedMinutes < cumulativeMinutes) {\n return { variations: step.variations, stepIndex: i };\n }\n }\n\n const lastStep = rollout.schedule.at(-1);\n return {\n variations: lastStep?.variations ?? rollout.variations,\n stepIndex: rollout.schedule.length - 1,\n };\n}\n\ninterface RolloutResult {\n variation: SnapshotVariation;\n variationKey: string;\n matchedWeight: number;\n bucketValue: number;\n scheduleStepIndex: number;\n}\n\nfunction selectVariationFromRollout(\n activeVariations: SnapshotRolloutVariation[],\n bucketValue: number,\n variations: Record<string, SnapshotVariation>,\n scheduleStepIndex: number\n): RolloutResult | undefined {\n let cumulative = 0;\n let matchedRv: SnapshotRolloutVariation | undefined;\n\n for (const rv of activeVariations) {\n cumulative += rv.weight;\n if (bucketValue < cumulative) {\n matchedRv = rv;\n break;\n }\n }\n\n if (!matchedRv) {\n matchedRv = activeVariations.at(-1);\n }\n\n if (!matchedRv) {\n return undefined;\n }\n\n const variation = variations[matchedRv.variationKey];\n if (!variation) {\n return undefined;\n }\n\n return {\n variation,\n variationKey: matchedRv.variationKey,\n matchedWeight: matchedRv.weight,\n bucketValue,\n scheduleStepIndex,\n };\n}\n\nfunction evaluateCondition(\n condition: SnapshotRuleCondition,\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n const { contextKind, attributeKey, operator, value } = condition;\n inputsUsed.add(`${contextKind}.${attributeKey}`);\n const contextValue = context[contextKind]?.[attributeKey];\n\n switch (operator) {\n case \"equals\":\n return contextValue === value;\n\n case \"not_equals\":\n return contextValue !== value;\n\n case \"contains\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.includes(value);\n }\n if (Array.isArray(contextValue)) {\n return contextValue.includes(value);\n }\n return false;\n\n case \"not_contains\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return !contextValue.includes(value);\n }\n if (Array.isArray(contextValue)) {\n return !contextValue.includes(value);\n }\n return true;\n\n case \"starts_with\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.startsWith(value);\n }\n return false;\n\n case \"ends_with\":\n if (typeof contextValue === \"string\" && typeof value === \"string\") {\n return contextValue.endsWith(value);\n }\n return false;\n\n case \"greater_than\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue > value;\n }\n return false;\n\n case \"less_than\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue < value;\n }\n return false;\n\n case \"greater_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue >= value;\n }\n return false;\n\n case \"less_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof value === \"number\") {\n return contextValue <= value;\n }\n return false;\n\n case \"in\":\n if (Array.isArray(value)) {\n return value.includes(contextValue);\n }\n return false;\n\n case \"not_in\":\n if (Array.isArray(value)) {\n return !value.includes(contextValue);\n }\n return true;\n\n case \"exists\":\n return contextValue !== undefined && contextValue !== null;\n\n case \"not_exists\":\n return contextValue === undefined || contextValue === null;\n\n default:\n return false;\n }\n}\n\nfunction evaluateConditions(\n conditions: SnapshotRuleCondition[],\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n return conditions.every((condition) =>\n evaluateCondition(condition, context, inputsUsed)\n );\n}\n\nfunction matchesIndividual(\n entries: SnapshotIndividualEntry[],\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n for (const entry of entries) {\n inputsUsed.add(`${entry.contextKind}.${entry.attributeKey}`);\n if (\n context[entry.contextKind]?.[entry.attributeKey] === entry.attributeValue\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction evaluateSegment(\n segment: SnapshotSegment,\n context: EvaluationContext,\n inputsUsed: Set<string>\n): boolean {\n // Priority 1: Excluded individuals never match\n if (\n segment.excluded?.length &&\n matchesIndividual(segment.excluded, context, inputsUsed)\n ) {\n return false;\n }\n\n // Priority 2: Included individuals always match\n if (\n segment.included?.length &&\n matchesIndividual(segment.included, context, inputsUsed)\n ) {\n return true;\n }\n\n // Priority 3: Evaluate conditions (empty conditions = no match)\n if (segment.conditions.length === 0) {\n return false;\n }\n return evaluateConditions(segment.conditions, context, inputsUsed);\n}\n\nfunction evaluateTarget(\n target: SnapshotTarget,\n context: EvaluationContext,\n segments: Record<string, SnapshotSegment>,\n inputsUsed: Set<string>\n): boolean {\n switch (target.type) {\n case \"individual\":\n if (\n target.contextKind &&\n target.attributeKey &&\n target.attributeValue !== undefined\n ) {\n inputsUsed.add(`${target.contextKind}.${target.attributeKey}`);\n return (\n context[target.contextKind]?.[target.attributeKey] ===\n target.attributeValue\n );\n }\n return false;\n\n case \"rule\":\n if (target.conditions) {\n return evaluateConditions(target.conditions, context, inputsUsed);\n }\n return false;\n\n case \"segment\":\n if (target.segmentKey) {\n const segment = segments[target.segmentKey];\n if (segment) {\n return evaluateSegment(segment, context, inputsUsed);\n }\n }\n return false;\n\n default:\n return false;\n }\n}\n\nfunction resolveTargetVariation(\n target: SnapshotTarget,\n flagKey: string,\n context: EvaluationContext,\n variations: Record<string, SnapshotVariation>,\n inputsUsed: Set<string>,\n now: Date\n): RolloutResult | undefined {\n if (target.rollout) {\n const active = resolveActiveRollout(target.rollout, now);\n const bucketValue = getBucketValue(\n flagKey,\n context,\n target.rollout,\n inputsUsed\n );\n return selectVariationFromRollout(\n active.variations,\n bucketValue,\n variations,\n active.stepIndex\n );\n }\n\n if (target.variationKey) {\n const variation = variations[target.variationKey];\n if (variation) {\n return {\n variation,\n variationKey: target.variationKey,\n matchedWeight: 100_000,\n bucketValue: 0,\n scheduleStepIndex: -1,\n };\n }\n }\n\n return undefined;\n}\n\nfunction resolveDefaultVariation(\n flag: SnapshotFlag,\n context: EvaluationContext,\n inputsUsed: Set<string>,\n now: Date\n): RolloutResult | undefined {\n if (flag.defaultRollout) {\n const active = resolveActiveRollout(flag.defaultRollout, now);\n const bucketValue = getBucketValue(\n flag.key,\n context,\n flag.defaultRollout,\n inputsUsed\n );\n return selectVariationFromRollout(\n active.variations,\n bucketValue,\n flag.variations,\n active.stepIndex\n );\n }\n\n if (flag.defaultVariationKey) {\n const variation = flag.variations[flag.defaultVariationKey];\n if (variation) {\n return {\n variation,\n variationKey: flag.defaultVariationKey,\n matchedWeight: 100_000,\n bucketValue: 0,\n scheduleStepIndex: -1,\n };\n }\n }\n\n return undefined;\n}\n\nfunction buildRuleMatchReason(target: SnapshotTarget): Reason {\n return {\n type: \"rule_match\",\n ruleId: target.id ?? \"\",\n ruleName: target.name,\n };\n}\n\nfunction buildRolloutReason(rolloutResult: RolloutResult): Reason {\n if (rolloutResult.scheduleStepIndex >= 0) {\n return {\n type: \"gradual_rollout\",\n stepIndex: rolloutResult.scheduleStepIndex,\n percentage: rolloutResult.matchedWeight / 1000,\n bucket: rolloutResult.bucketValue,\n };\n }\n return {\n type: \"percentage_rollout\",\n percentage: rolloutResult.matchedWeight / 1000,\n bucket: rolloutResult.bucketValue,\n };\n}\n\nexport function evaluateFlag(\n flag: SnapshotFlag,\n context: EvaluationContext,\n segments: Record<string, SnapshotSegment>,\n options?: { now?: Date }\n): EvalOutput {\n if (!flag.enabled) {\n const offVariation = flag.variations[flag.offVariationKey];\n return {\n value: offVariation?.value,\n variationKey: flag.offVariationKey,\n reasons: [{ type: \"off\" }],\n inputsUsed: [],\n };\n }\n\n const now = options?.now ?? new Date();\n const inputsUsed = new Set<string>();\n\n const sortedTargets = [...flag.targets].sort(\n (a, b) => a.sortOrder - b.sortOrder\n );\n\n for (const target of sortedTargets) {\n if (evaluateTarget(target, context, segments, inputsUsed)) {\n const resolved = resolveTargetVariation(\n target,\n flag.key,\n context,\n flag.variations,\n inputsUsed,\n now\n );\n if (resolved) {\n const reasons: Reason[] = [buildRuleMatchReason(target)];\n if (target.rollout) {\n reasons.push(buildRolloutReason(resolved));\n }\n\n return {\n value: resolved.variation.value,\n variationKey: resolved.variationKey,\n reasons,\n matchedTargetName: target.name,\n inputsUsed: [...inputsUsed],\n };\n }\n }\n }\n\n const resolved = resolveDefaultVariation(flag, context, inputsUsed, now);\n if (resolved) {\n const reasons: Reason[] = [];\n if (flag.defaultRollout) {\n reasons.push(buildRolloutReason(resolved));\n }\n reasons.push({ type: \"default\" });\n\n return {\n value: resolved.variation.value,\n variationKey: resolved.variationKey,\n reasons,\n inputsUsed: [...inputsUsed],\n };\n }\n\n return {\n value: undefined,\n variationKey: undefined,\n reasons: [{ type: \"default\" }],\n inputsUsed: [...inputsUsed],\n };\n}\n","import type { EvaluationBatchPayload, EvaluationEvent } from \"./types\";\n\ndeclare const __SDK_VERSION__: string;\nexport const SDK_VERSION = __SDK_VERSION__;\n\ninterface EventBufferOptions {\n baseUrl: string;\n apiKey: string;\n meta: {\n projectId: string;\n organizationId: string;\n environmentId: string;\n sdkPlatform?: string;\n };\n flushIntervalMs: number;\n maxBatchSize: number;\n}\n\nconst g = globalThis as Record<string, unknown>;\nconst doc = g.document as\n | {\n visibilityState?: string;\n addEventListener?: (event: string, handler: () => void) => void;\n removeEventListener?: (event: string, handler: () => void) => void;\n }\n | undefined;\nexport class EventBuffer {\n private readonly events: EvaluationEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly options: EventBufferOptions;\n private readonly onVisibilityChange: (() => void) | null = null;\n\n constructor(options: EventBufferOptions) {\n this.options = options;\n this.timer = setInterval(() => this.flush(), this.options.flushIntervalMs);\n\n if (doc?.addEventListener) {\n this.onVisibilityChange = () => {\n if (doc.visibilityState === \"hidden\") {\n this.flushBeacon();\n }\n };\n doc.addEventListener(\"visibilitychange\", this.onVisibilityChange);\n }\n }\n\n push(event: EvaluationEvent): void {\n this.events.push(event);\n if (this.events.length >= this.options.maxBatchSize) {\n this.flush();\n }\n }\n\n private buildPayload(batch: EvaluationEvent[]): EvaluationBatchPayload {\n return {\n meta: {\n ...this.options.meta,\n sdkVersion: SDK_VERSION,\n },\n events: batch,\n };\n }\n\n flush(): void {\n if (this.events.length === 0) {\n return;\n }\n const batch = this.events.splice(0, this.options.maxBatchSize);\n const payload = this.buildPayload(batch);\n\n fetch(`${this.options.baseUrl}/sdk/evaluations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify(payload),\n }).catch(() => {\n // Fire-and-forget: silently drop failed events to prevent unbounded growth\n });\n }\n\n /**\n * Flush with keepalive flag for reliable delivery during page unload.\n * keepalive fetch survives page navigation like sendBeacon but supports headers.\n */\n private flushBeacon(): void {\n if (this.events.length === 0) {\n return;\n }\n\n const batch = this.events.splice(0, this.options.maxBatchSize);\n const payload = this.buildPayload(batch);\n\n fetch(`${this.options.baseUrl}/sdk/evaluations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify(payload),\n keepalive: true,\n }).catch(() => {\n // Fire-and-forget\n });\n }\n\n destroy(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n if (this.onVisibilityChange && doc?.removeEventListener) {\n doc.removeEventListener(\"visibilitychange\", this.onVisibilityChange);\n }\n this.flush();\n }\n}\n","import { evaluateFlag } from \"./evaluator\";\nimport { EventBuffer } from \"./event-buffer\";\nimport type {\n EnvironmentSnapshot,\n EvalOutput,\n EvaluationContext,\n EvaluationResult,\n FlagOptions,\n GradualOptions,\n IsEnabledOptions,\n Reason,\n} from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://worker.gradual.so/api/v1\";\nconst HTTPS_RE = /^https:\\/\\//;\nconst HTTP_RE = /^http:\\/\\//;\n\ntype SdkPlatform = \"browser\" | \"node\" | \"react-native\" | \"edge\" | \"unknown\";\n\nfunction detectPlatform(): SdkPlatform {\n try {\n const g = globalThis as Record<string, unknown>;\n const nav = g.navigator as\n | { product?: string; userAgent?: string }\n | undefined;\n if (nav && nav.product === \"ReactNative\") {\n return \"react-native\";\n }\n const win = g.window as { document?: unknown } | undefined;\n if (win && typeof win.document !== \"undefined\") {\n return \"browser\";\n }\n const proc = g.process as { versions?: { node?: string } } | undefined;\n if (proc?.versions?.node) {\n return \"node\";\n }\n if (typeof globalThis !== \"undefined\") {\n return \"edge\";\n }\n } catch {\n // Ignore detection errors\n }\n return \"unknown\";\n}\n\nconst SDK_PLATFORM = detectPlatform();\n\nconst proc = (globalThis as Record<string, unknown>).process as\n | { hrtime?: { bigint?: () => bigint } }\n | undefined;\nconst hasHrtime = typeof proc?.hrtime?.bigint === \"function\";\n\nfunction nowNs(): bigint | number {\n if (hasHrtime) {\n // biome-ignore lint/style/noNonNullAssertion: guarded by hasHrtime check\n return proc!.hrtime!.bigint!();\n }\n if (typeof performance !== \"undefined\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction elapsedUs(start: bigint | number): number {\n const end = nowNs();\n if (typeof start === \"bigint\" && typeof end === \"bigint\") {\n // hrtime bigint: nanoseconds → microseconds\n return Number((end - start) / 1000n);\n }\n // performance.now() ms or Date.now() ms → microseconds\n return Math.round(((end as number) - (start as number)) * 1000);\n}\n\nexport interface Gradual {\n /** Wait for the SDK to be ready (snapshot fetched) */\n ready(): Promise<void>;\n\n /** Check if the SDK is ready for sync access */\n isReady(): boolean;\n\n /** Check if a boolean flag is enabled */\n isEnabled(key: string, options?: IsEnabledOptions): Promise<boolean>;\n\n /** Get a flag value with type inference from fallback */\n get<T>(key: string, options: FlagOptions<T>): Promise<T>;\n\n /** Evaluate a flag and return the full structured result (also tracks the evaluation) */\n evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): Promise<EvaluationResult<T>>;\n\n /** Set persistent user context for all evaluations */\n identify(context: EvaluationContext): void;\n\n /** Clear the identified user context */\n reset(): void;\n\n /** Refresh the snapshot from the server */\n refresh(): Promise<void>;\n\n /** Get the current snapshot (for debugging) */\n getSnapshot(): EnvironmentSnapshot | null;\n\n /** Subscribe to snapshot updates from polling (returns unsubscribe function) */\n onUpdate(callback: () => void): () => void;\n\n /** Flush pending evaluation events and stop the event buffer */\n close(): void;\n\n /** Sync methods (throw if not ready) */\n sync: GradualSync;\n}\n\nexport interface GradualSync {\n /** Sync version of isEnabled (throws if not ready) */\n isEnabled(key: string, options?: IsEnabledOptions): boolean;\n\n /** Sync version of get (throws if not ready) */\n get<T>(key: string, options: FlagOptions<T>): T;\n\n /** Evaluate a flag without tracking. Use with track() for React-safe evaluation. */\n evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): EvaluationResult<T>;\n\n /** Manually track an evaluation that was produced by evaluate(). */\n track(\n key: string,\n result: EvaluationResult,\n context?: EvaluationContext\n ): void;\n}\n\nclass GradualClient implements Gradual {\n private readonly apiKey: string;\n private readonly environment: string;\n private readonly baseUrl: string;\n private readonly initPromise: Promise<void>;\n private snapshot: EnvironmentSnapshot | null = null;\n private identifiedContext: EvaluationContext = {};\n private readonly updateListeners: Set<() => void> = new Set();\n private eventBuffer: EventBuffer | null = null;\n private etag: string | null = null;\n private readonly eventsEnabled: boolean;\n private readonly eventsFlushIntervalMs: number;\n private readonly eventsMaxBatchSize: number;\n private readonly realtimeEnabled: boolean;\n private readonly pollingEnabled: boolean;\n private readonly pollingIntervalMs: number;\n private pollingTimer: ReturnType<typeof setInterval> | null = null;\n private ws: WebSocket | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectAttempts = 0;\n\n readonly sync: GradualSync;\n\n constructor(options: GradualOptions) {\n this.apiKey = options.apiKey;\n this.environment = options.environment;\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n this.eventsEnabled = options.events?.enabled ?? true;\n this.eventsFlushIntervalMs = options.events?.flushIntervalMs ?? 30_000;\n this.eventsMaxBatchSize = options.events?.maxBatchSize ?? 100;\n\n const hasWebSocket = typeof globalThis.WebSocket !== \"undefined\";\n this.realtimeEnabled = options.realtime?.enabled ?? hasWebSocket;\n this.pollingEnabled = options.polling?.enabled ?? true;\n this.pollingIntervalMs = options.polling?.intervalMs ?? 10_000;\n\n this.initPromise = this.init();\n\n this.sync = {\n isEnabled: this.isEnabledSync.bind(this),\n get: this.getSync.bind(this),\n evaluate: this.evaluateSync.bind(this),\n track: this.trackSync.bind(this),\n };\n }\n\n private async init(): Promise<void> {\n const initResponse = await fetch(`${this.baseUrl}/sdk/init`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ apiKey: this.apiKey }),\n });\n\n if (!initResponse.ok) {\n const error = await initResponse.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to initialize - ${(error as { error?: string }).error ?? initResponse.statusText}`\n );\n }\n\n const initData = (await initResponse.json()) as {\n valid: boolean;\n error?: string;\n };\n\n if (!initData.valid) {\n throw new Error(\n `Gradual: Invalid API key - ${initData.error ?? \"Unknown error\"}`\n );\n }\n\n if (this.realtimeEnabled) {\n await this.connectWebSocket();\n } else {\n await this.fetchSnapshot();\n this.startPolling();\n }\n\n this.initializeEventBuffer();\n }\n\n private initializeEventBuffer(): void {\n if (this.eventsEnabled && this.snapshot?.meta) {\n this.eventBuffer = new EventBuffer({\n baseUrl: this.baseUrl,\n apiKey: this.apiKey,\n meta: {\n projectId: this.snapshot.meta.projectId,\n organizationId: this.snapshot.meta.organizationId,\n environmentId: this.snapshot.meta.environmentId,\n sdkPlatform: SDK_PLATFORM,\n },\n flushIntervalMs: this.eventsFlushIntervalMs,\n maxBatchSize: this.eventsMaxBatchSize,\n });\n }\n }\n\n private async fetchSnapshot(): Promise<void> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n };\n if (this.etag) {\n headers[\"If-None-Match\"] = this.etag;\n }\n\n const response = await fetch(\n `${this.baseUrl}/sdk/snapshot?environment=${encodeURIComponent(this.environment)}`,\n { headers }\n );\n\n if (response.status === 304) {\n return;\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n `Gradual: Failed to fetch snapshot - ${(error as { error?: string }).error ?? response.statusText}`\n );\n }\n\n const etag = response.headers.get(\"ETag\");\n if (etag) {\n this.etag = etag;\n }\n this.snapshot = (await response.json()) as EnvironmentSnapshot;\n }\n\n private startPolling(): void {\n if (!this.pollingEnabled) {\n return;\n }\n this.pollingTimer = setInterval(async () => {\n try {\n const previousVersion = this.snapshot?.version;\n await this.fetchSnapshot();\n if (this.snapshot && this.snapshot.version !== previousVersion) {\n for (const cb of this.updateListeners) {\n cb();\n }\n }\n } catch (error) {\n console.warn(\"Gradual: Polling refresh failed\", error);\n }\n }, this.pollingIntervalMs);\n }\n\n private connectWebSocket(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const wsBase = this.baseUrl\n .replace(HTTPS_RE, \"wss://\")\n .replace(HTTP_RE, \"ws://\");\n const wsUrl = `${wsBase}/sdk/connect?apiKey=${encodeURIComponent(this.apiKey)}&environment=${encodeURIComponent(this.environment)}`;\n\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n let resolved = false;\n\n ws.onmessage = (event: MessageEvent) => {\n try {\n const newSnapshot = JSON.parse(\n typeof event.data === \"string\" ? event.data : \"\"\n ) as EnvironmentSnapshot;\n const previousVersion = this.snapshot?.version;\n this.snapshot = newSnapshot;\n\n if (newSnapshot.version) {\n this.etag = `\"${newSnapshot.version}\"`;\n }\n\n if (!resolved) {\n resolved = true;\n this.reconnectAttempts = 0;\n resolve();\n } else if (newSnapshot.version !== previousVersion) {\n for (const cb of this.updateListeners) {\n cb();\n }\n }\n } catch (err) {\n console.warn(\"Gradual: Failed to parse WebSocket message\", err);\n if (!resolved) {\n resolved = true;\n this.fallbackToPolling(resolve, reject);\n }\n }\n };\n\n ws.onerror = () => {\n if (!resolved) {\n resolved = true;\n ws.close();\n this.ws = null;\n this.fallbackToPolling(resolve, reject);\n }\n };\n\n ws.onclose = () => {\n if (!resolved) {\n resolved = true;\n this.ws = null;\n this.fallbackToPolling(resolve, reject);\n return;\n }\n // Already connected — schedule reconnect\n this.ws = null;\n this.scheduleReconnect();\n };\n });\n }\n\n private fallbackToPolling(\n resolve: () => void,\n reject: (err: Error) => void\n ): void {\n console.warn(\"Gradual: WebSocket failed, falling back to polling\");\n this.fetchSnapshot()\n .then(() => {\n this.startPolling();\n resolve();\n })\n .catch(reject);\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) {\n return;\n }\n const delay = Math.min(1000 * 2 ** this.reconnectAttempts, 30_000);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.reconnectWebSocket();\n }, delay);\n }\n\n private reconnectWebSocket(): void {\n const wsBase = this.baseUrl\n .replace(HTTPS_RE, \"wss://\")\n .replace(HTTP_RE, \"ws://\");\n const wsUrl = `${wsBase}/sdk/connect?apiKey=${encodeURIComponent(this.apiKey)}&environment=${encodeURIComponent(this.environment)}`;\n\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n\n ws.onmessage = (event: MessageEvent) => {\n try {\n const newSnapshot = JSON.parse(\n typeof event.data === \"string\" ? event.data : \"\"\n ) as EnvironmentSnapshot;\n const previousVersion = this.snapshot?.version;\n this.snapshot = newSnapshot;\n this.reconnectAttempts = 0;\n\n if (newSnapshot.version !== previousVersion) {\n for (const cb of this.updateListeners) {\n cb();\n }\n }\n } catch (err) {\n console.warn(\"Gradual: Failed to parse WebSocket message\", err);\n }\n };\n\n ws.onerror = () => {\n // onclose will fire after this\n };\n\n ws.onclose = () => {\n this.ws = null;\n this.scheduleReconnect();\n };\n }\n\n private ensureReady(): EnvironmentSnapshot {\n if (!this.snapshot) {\n throw new Error(\n \"Gradual: SDK not ready. Use await ready() or async methods.\"\n );\n }\n return this.snapshot;\n }\n\n private mergeContext(options?: {\n context?: EvaluationContext;\n }): EvaluationContext {\n const merged: EvaluationContext = {};\n const allKinds = new Set([\n ...Object.keys(this.identifiedContext),\n ...Object.keys(options?.context ?? {}),\n ]);\n for (const kind of allKinds) {\n merged[kind] = {\n ...this.identifiedContext[kind],\n ...options?.context?.[kind],\n };\n }\n return merged;\n }\n\n private evaluateRaw(\n key: string,\n context: EvaluationContext\n ): {\n output: EvalOutput | null;\n snapshot: EnvironmentSnapshot;\n durationUs: number;\n } {\n const snapshot = this.ensureReady();\n if (!snapshot.flags) {\n return { output: null, snapshot, durationUs: 0 };\n }\n const flag = snapshot.flags[key];\n if (!flag) {\n return { output: null, snapshot, durationUs: 0 };\n }\n\n const startTime = nowNs();\n let output: EvalOutput;\n try {\n output = evaluateFlag(flag, context, snapshot.segments ?? {});\n } catch (err) {\n const errorDetail = err instanceof Error ? err.message : String(err);\n output = {\n value: undefined,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: errorDetail }],\n errorDetail,\n };\n }\n\n return { output, snapshot, durationUs: elapsedUs(startTime) };\n }\n\n private buildResult<T>(\n key: string,\n output: EvalOutput,\n flagVersion: number,\n durationUs?: number\n ): EvaluationResult<T> {\n const ruleMatch = output.reasons.find(\n (r): r is Extract<Reason, { type: \"rule_match\" }> =>\n r.type === \"rule_match\"\n );\n\n return {\n schemaVersion: 1,\n key,\n value: output.value as T,\n variationKey: output.variationKey,\n reasons: output.reasons,\n ruleId: ruleMatch?.ruleId,\n flagVersion,\n evaluatedAt: new Date().toISOString(),\n evaluationDurationUs: durationUs,\n inputsUsed: output.inputsUsed,\n traceId: crypto.randomUUID(),\n };\n }\n\n private evaluateAndTrack(key: string, context: EvaluationContext): unknown {\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n const evaluatedAt = new Date().toISOString();\n const traceId = crypto.randomUUID();\n\n if (!output) {\n this.trackEvent({\n key,\n variationKey: undefined,\n value: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n context,\n flagVersion: snapshot.version,\n schemaVersion: 1,\n evaluatedAt,\n traceId,\n });\n return undefined;\n }\n\n this.trackEvent({\n key,\n variationKey: output.variationKey,\n value: output.value,\n reasons: output.reasons,\n context,\n matchedTargetName: output.matchedTargetName,\n flagVersion: snapshot.version,\n errorDetail: output.errorDetail,\n evaluationDurationUs: durationUs,\n schemaVersion: 1,\n evaluatedAt,\n inputsUsed: output.inputsUsed,\n traceId,\n });\n\n return output.value;\n }\n\n private trackEvent(params: {\n key: string;\n variationKey: string | undefined;\n value: unknown;\n reasons: Reason[];\n evaluatedAt?: string;\n ruleId?: string;\n context: EvaluationContext;\n matchedTargetName?: string;\n flagVersion?: number;\n errorDetail?: string;\n evaluationDurationUs?: number;\n schemaVersion?: 1;\n policyVersion?: number;\n inputsUsed?: string[];\n traceId?: string;\n }): void {\n if (!this.eventBuffer) {\n return;\n }\n const { context } = params;\n const contextKinds = Object.keys(context);\n const contextKeys: Record<string, string[]> = {};\n for (const kind of contextKinds) {\n contextKeys[kind] = Object.keys(context[kind] ?? {});\n }\n\n const isAnonymous =\n contextKinds.length === 0 ||\n contextKinds.every(\n (kind) => Object.keys(context[kind] ?? {}).length === 0\n );\n\n this.eventBuffer.push({\n schemaVersion: params.schemaVersion ?? 1,\n key: params.key,\n variationKey: params.variationKey,\n value: params.value,\n reasons: params.reasons,\n evaluatedAt: params.evaluatedAt ?? new Date().toISOString(),\n ruleId: params.ruleId,\n flagVersion: params.flagVersion ?? 0,\n policyVersion: params.policyVersion,\n inputsUsed: params.inputsUsed,\n traceId: params.traceId,\n contextKinds,\n contextKeys,\n timestamp: Date.now(),\n matchedTargetName: params.matchedTargetName,\n errorDetail: params.errorDetail,\n evaluationDurationUs: params.evaluationDurationUs,\n isAnonymous,\n });\n }\n\n async ready(): Promise<void> {\n await this.initPromise;\n }\n\n isReady(): boolean {\n return this.snapshot !== null;\n }\n\n async isEnabled(key: string, options?: IsEnabledOptions): Promise<boolean> {\n await this.initPromise;\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return typeof value === \"boolean\" ? value : false;\n }\n\n async get<T>(key: string, options: FlagOptions<T>): Promise<T> {\n await this.initPromise;\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return value !== undefined && value !== null\n ? (value as T)\n : options.fallback;\n }\n\n async evaluate<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): Promise<EvaluationResult<T>> {\n await this.initPromise;\n const context = this.mergeContext(options);\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n\n if (!output) {\n const traceId = crypto.randomUUID();\n const evaluatedAt = new Date().toISOString();\n const result: EvaluationResult<T> = {\n schemaVersion: 1,\n key,\n value: undefined as T,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n flagVersion: snapshot.version,\n evaluatedAt,\n traceId,\n };\n this.trackEvent({\n key,\n variationKey: undefined,\n value: undefined,\n reasons: result.reasons,\n evaluatedAt,\n context,\n flagVersion: snapshot.version,\n schemaVersion: 1,\n traceId,\n });\n return result;\n }\n\n const result = this.buildResult<T>(\n key,\n output,\n snapshot.version,\n durationUs\n );\n\n this.trackEvent({\n key,\n variationKey: output.variationKey,\n value: output.value,\n reasons: output.reasons,\n evaluatedAt: result.evaluatedAt,\n ruleId: result.ruleId,\n context,\n matchedTargetName: output.matchedTargetName,\n flagVersion: snapshot.version,\n errorDetail: output.errorDetail,\n evaluationDurationUs: durationUs,\n schemaVersion: 1,\n inputsUsed: output.inputsUsed,\n traceId: result.traceId,\n });\n\n return result;\n }\n\n private isEnabledSync(key: string, options?: IsEnabledOptions): boolean {\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return typeof value === \"boolean\" ? value : false;\n }\n\n private getSync<T>(key: string, options: FlagOptions<T>): T {\n const value = this.evaluateAndTrack(key, this.mergeContext(options));\n return value !== undefined && value !== null\n ? (value as T)\n : options.fallback;\n }\n\n private evaluateSync<T = unknown>(\n key: string,\n options?: { context?: EvaluationContext }\n ): EvaluationResult<T> {\n const context = this.mergeContext(options);\n const { output, snapshot, durationUs } = this.evaluateRaw(key, context);\n\n if (!output) {\n return {\n schemaVersion: 1,\n key,\n value: undefined as T,\n variationKey: undefined,\n reasons: [{ type: \"error\", detail: \"FLAG_NOT_FOUND\" }],\n flagVersion: snapshot.version,\n evaluatedAt: new Date().toISOString(),\n evaluationDurationUs: durationUs,\n traceId: crypto.randomUUID(),\n };\n }\n\n return this.buildResult<T>(key, output, snapshot.version, durationUs);\n }\n\n private trackSync(\n key: string,\n result: EvaluationResult,\n context?: EvaluationContext\n ): void {\n const ruleMatch = result.reasons.find(\n (r): r is Extract<Reason, { type: \"rule_match\" }> =>\n r.type === \"rule_match\"\n );\n\n this.trackEvent({\n key,\n variationKey: result.variationKey,\n value: result.value,\n reasons: result.reasons,\n evaluatedAt: result.evaluatedAt,\n ruleId: result.ruleId,\n context: this.mergeContext({ context }),\n matchedTargetName: ruleMatch?.ruleName,\n flagVersion: result.flagVersion,\n evaluationDurationUs: result.evaluationDurationUs,\n schemaVersion: result.schemaVersion,\n policyVersion: result.policyVersion,\n inputsUsed: result.inputsUsed,\n traceId: result.traceId,\n });\n }\n\n identify(context: EvaluationContext): void {\n this.identifiedContext = { ...context };\n }\n\n reset(): void {\n this.identifiedContext = {};\n }\n\n async refresh(): Promise<void> {\n await this.fetchSnapshot();\n }\n\n getSnapshot(): EnvironmentSnapshot | null {\n return this.snapshot;\n }\n\n onUpdate(callback: () => void): () => void {\n this.updateListeners.add(callback);\n return () => this.updateListeners.delete(callback);\n }\n\n close(): void {\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.pollingTimer) {\n clearInterval(this.pollingTimer);\n this.pollingTimer = null;\n }\n if (this.eventBuffer) {\n this.eventBuffer.destroy();\n this.eventBuffer = null;\n }\n }\n}\n\n/**\n * Create a Gradual feature flag client\n *\n * @example\n * ```ts\n * const gradual = createGradual({\n * apiKey: 'gra_xxx',\n * environment: 'production'\n * })\n *\n * // Boolean flags\n * const enabled = await gradual.isEnabled('new-feature')\n *\n * // Typed values (inferred from fallback)\n * const theme = await gradual.get('theme', { fallback: 'dark' })\n *\n * // Full structured result\n * const result = await gradual.evaluate('new-feature')\n * // result.value, result.reasons, result.ruleId, result.flagVersion\n *\n * // With user context\n * gradual.identify({ userId: '123', plan: 'pro' })\n * const proFeature = await gradual.isEnabled('pro-feature')\n * ```\n */\nexport function createGradual(options: GradualOptions): Gradual {\n return new GradualClient(options);\n}\n"]}
|