@harnessio/ff-javascript-client-sdk
Advanced tools
Comparing version 1.17.0-rc.3 to 1.17.0-rc.4
@@ -5,7 +5,6 @@ import type { Options } from './types'; | ||
private configurations; | ||
private pollInterval; | ||
private timeoutId; | ||
private isRunning; | ||
private maxAttempts; | ||
constructor(fetchFlagsFn: () => Promise<any>, configurations: Options, pollInterval: number); | ||
constructor(fetchFlagsFn: () => Promise<any>, configurations: Options); | ||
start(): void; | ||
@@ -12,0 +11,0 @@ private poll; |
@@ -1,1 +0,1 @@ | ||
var De=Object.create;var x=Object.defineProperty,Ae=Object.defineProperties,Ce=Object.getOwnPropertyDescriptor,Oe=Object.getOwnPropertyDescriptors,Fe=Object.getOwnPropertyNames,ae=Object.getOwnPropertySymbols,xe=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty,Ve=Object.prototype.propertyIsEnumerable;var re=(n,e,a)=>e in n?x(n,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):n[e]=a,D=(n,e)=>{for(var a in e||(e={}))oe.call(e,a)&&re(n,a,e[a]);if(ae)for(var a of ae(e))Ve.call(e,a)&&re(n,a,e[a]);return n},U=(n,e)=>Ae(n,Oe(e));var Ne=(n,e)=>{for(var a in e)x(n,a,{get:e[a],enumerable:!0})},se=(n,e,a,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Fe(e))!oe.call(n,o)&&o!==a&&x(n,o,{get:()=>e[o],enumerable:!(s=Ce(e,o))||s.enumerable});return n};var le=(n,e,a)=>(a=n!=null?De(xe(n)):{},se(e||!n||!n.__esModule?x(a,"default",{value:n,enumerable:!0}):a,n)),ke=n=>se(x({},"__esModule",{value:!0}),n);var C=(n,e,a)=>new Promise((s,o)=>{var f=b=>{try{I(a.next(b))}catch(y){o(y)}},v=b=>{try{I(a.throw(b))}catch(y){o(y)}},I=b=>b.done?s(b.value):Promise.resolve(b.value).then(f,v);I((a=a.apply(n,e)).next())});var Le={};Ne(Le,{Event:()=>M,initialize:()=>He});module.exports=ke(Le);var Ee=le(require("jwt-decode")),me=le(require("mitt"));var M=(h=>(h.READY="ready",h.CONNECTED="connected",h.DISCONNECTED="disconnected",h.FLAGS_LOADED="flags loaded",h.CACHE_LOADED="cache loaded",h.CHANGED="changed",h.ERROR="error",h.ERROR_METRICS="metrics error",h.ERROR_AUTH="auth error",h.ERROR_FETCH_FLAGS="fetch flags error",h.ERROR_FETCH_FLAG="fetch flag error",h.ERROR_STREAM="stream error",h))(M||{});var ce={debug:!1,baseUrl:"https://config.ff.harness.io/api/1.0",eventUrl:"https://events.ff.harness.io/api/1.0",eventsSyncInterval:6e4,pollingInterval:6e4,streamEnabled:!0,pollingEnabled:!1,allAttributesPrivate:!1,privateAttributeNames:[],cache:!1},R=(n,...e)=>console.error(`[FF-SDK] ${n}`,...e),j=(n,e=!0)=>{e?setTimeout(n,0):n()},P=(n,e)=>Math.round(Math.random()*(e-n)+n);function W(n){return"HARNESS_FF_CACHE_"+n}function H(n,e={}){let a=W(n),s=parseInt(window.localStorage.getItem(a+".ts"));if(e!=null&&e.ttl&&!isNaN(s)&&s+e.ttl<Date.now())return _e(n),[];let o=window.localStorage.getItem(a);if(o)try{return JSON.parse(o)}catch(f){}return[]}function L(n,e){let a=W(n);window.localStorage.setItem(a,JSON.stringify(e)),window.localStorage.setItem(a+".ts",Date.now().toString())}function de(n,e){let a=H(n),s=a.find(({flag:o})=>o===e.flag);s?Object.assign(s,e):a.push(e),L(n,a)}function ue(n,e){let a=H(n),s=a.findIndex(({flag:o})=>o===e);s>-1&&(a.splice(s,1),L(n,a))}function _e(n){let e=W(n);window.localStorage.removeItem(e),window.localStorage.removeItem(e+".ts")}function J(n){return function(...a){let[s,o]=n(a);return fetch(s,o)}}var fe=3e4,G=class{constructor(e,a,s,o,f,v,I){this.closed=!1;this.eventBus=e,this.configurations=a,this.url=s,this.apiKey=o,this.standardHeaders=f,this.eventCallback=I,this.fallbackPoller=v}start(){let e=c=>{c.toString().split(/\r?\n/).forEach(a)},a=c=>{if(c.startsWith("data:")){let T=JSON.parse(c.substring(5));this.logDebug("Received event from stream: ",T),this.eventCallback(T)}},s=()=>{this.logDebug("Stream connected"),this.eventBus.emit("connected")},o=()=>{clearInterval(y);let c=P(1e3,1e4);this.logDebug("Stream disconnected, will reconnect in "+c+"ms"),this.eventBus.emit("disconnected"),setTimeout(()=>this.start(),c)},f=c=>{c&&R("Stream has issue",c),this.fallBackToPolling(),this.eventBus.emit("stream error",c),this.eventBus.emit("error",c),o()},v=D({"Cache-Control":"no-cache",Accept:"text/event-stream","API-Key":this.apiKey},this.standardHeaders);this.logDebug("SSE HTTP start request",this.url),this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url);for(let[c,T]of Object.entries(v))this.xhr.setRequestHeader(c,T);this.xhr.timeout=24*60*60*1e3,this.xhr.onerror=()=>{f("XMLHttpRequest error on SSE stream")},this.xhr.onabort=()=>{this.logDebug("SSE aborted"),this.closed||f(null)},this.xhr.ontimeout=()=>{f("SSE timeout")},this.xhr.onload=()=>{if(this.xhr.status>=400&&this.xhr.status<=599){f(`HTTP code ${this.xhr.status}`);return}this.stopFallBackPolling(),s()};let I=0,b=Date.now();this.xhr.onprogress=()=>{b=Date.now();let c=this.xhr.responseText.slice(I);I+=c.length,this.logDebug("SSE GOT: "+c),e(c)};let y=setInterval(()=>{b<Date.now()-fe&&(R("SSE read timeout"),this.xhr.abort())},fe);this.xhr.send()}close(){this.closed=!0,this.xhr&&this.xhr.abort(),this.stopFallBackPolling()}fallBackToPolling(){!this.fallbackPoller.isPolling()&&this.configurations.pollingEnabled&&(R("Falling back to polling mode while stream recovers"),this.fallbackPoller.start())}stopFallBackPolling(){this.fallbackPoller.isPolling()&&(R("Stopping fallback polling mode"),this.fallbackPoller.stop())}logDebug(e,...a){this.configurations.debug&&console.debug(`[FF-SDK] Streaming: ${e}`,...a)}};function ge(n,e,a,s,o){let f=n in a,v=f?a[n]:e;return f&&s(n,v),o?{value:v,isDefaultValue:!f}:v}var V=class{constructor(e,a,s){this.fetchFlagsFn=e;this.configurations=a;this.pollInterval=s;this.maxAttempts=5}start(){if(this.isPolling()){this.logDebug("Already polling.");return}this.configurations.pollingEnabled&&(this.isRunning=!0,window.setTimeout(()=>this.poll(),this.configurations.pollingInterval))}poll(){this.attemptFetch().finally(()=>{this.timeoutId=window.setTimeout(()=>this.poll(),this.configurations.pollingInterval)})}attemptFetch(){return C(this,null,function*(){for(let e=1;e<=this.maxAttempts;e++){let a=yield this.fetchFlagsFn();if(!a){this.logDebug("Successfully polled for flag updates");return}if(R("Error when polling for flag updates",a),e>=this.maxAttempts){this.logDebug(`Maximum attempts reached for polling for flags. Next poll in ${this.pollInterval}ms.`);return}this.logDebug(`Polling for flags attempt #${e} failed. Remaining attempts: ${this.maxAttempts-e}.`);let s=P(1e3,1e4);yield new Promise(o=>setTimeout(o,s))}})}stop(){this.timeoutId&&(window.clearTimeout(this.timeoutId),this.timeoutId=void 0,this.isRunning=!1)}isPolling(){return this.isRunning}logDebug(e,...a){this.configurations.debug&&console.debug(`[FF-SDK] Poller: ${e}`,...a)}};var Re="1.16.0",pe=`Javascript ${Re} Client`,Me=500,Pe=globalThis.fetch,Y=!!globalThis.Proxy,X=n=>{let{value:e}=n;try{switch(n.kind.toLowerCase()){case"int":case"number":e=Number(e);break;case"boolean":e=e.toString().toLowerCase()==="true";break;case"json":e=JSON.parse(e);break}}catch(a){R(a)}return e},He=(n,e,a)=>{let s=!1,o,f,v,I,b,y,c=!0,T={},h=J(t=>t),z=0,Q=!1,N=()=>{c=!1},k=()=>{c=!0},S=[],d=(0,me.default)(),u=D(D({},ce),a);u.eventsSyncInterval<6e4&&(u.eventsSyncInterval=6e4),u.pollingInterval<6e4&&(u.pollingInterval=6e4);let m=(t,...i)=>{u.debug&&console.debug(`[FF-SDK] ${t}`,...i)},$=t=>{if(c){let i=Date.now();i-t.lastAccessed>Me&&(t.count++,t.lastAccessed=i)}};globalThis.onbeforeunload=()=>{S.length&&globalThis.localStorage&&(N(),globalThis.localStorage.HARNESS_FF_METRICS=JSON.stringify(S),k())};let be=(t,i)=>C(void 0,null,function*(){return(yield(yield Pe(`${i.baseUrl}/client/auth`,{method:"POST",headers:{"Content-Type":"application/json","Harness-SDK-Info":pe},body:JSON.stringify({apiKey:t,target:U(D({},e),{identifier:String(e.identifier)})})})).json()).authToken}),B=0,K=()=>{if(S.length){m("Sending metrics...",{metrics:S,evaluations:w});let t={metricsData:S.map(i=>({timestamp:Date.now(),count:i.count,metricsType:"FFMETRICS",attributes:[{key:"featureIdentifier",value:i.featureIdentifier},{key:"featureName",value:i.featureIdentifier},{key:"variationIdentifier",value:i.variationIdentifier},{key:"target",value:e.identifier},{key:"SDK_NAME",value:"JavaScript"},{key:"SDK_LANGUAGE",value:"JavaScript"},{key:"SDK_TYPE",value:"client"},{key:"SDK_VERSION",value:Re}]}))};h(`${u.eventUrl}/metrics/${o}?cluster=${f}`,{method:"POST",headers:D({"Content-Type":"application/json"},T),body:JSON.stringify(t)}).then(()=>{S=[],B=0}).catch(i=>{B++&&(S=[],B=0),m(i),d.emit("metrics error",i)}).finally(()=>{y=window.setTimeout(K,u.eventsSyncInterval)})}else y=window.setTimeout(K,u.eventsSyncInterval)},w={},Se=t=>{m("Sending event for",t.flag),Y?d.emit("changed",new Proxy(t,{get(i,l){var p;if(c&&i.hasOwnProperty(l)&&l==="value"){let E=i.flag,r=t.value,g=S.find(F=>F.featureIdentifier===E&&F.featureValue===r);g?($(g),g.variationIdentifier=((p=w[E])==null?void 0:p.identifier)||""):S.push({featureIdentifier:E,featureValue:String(r),variationIdentifier:w[E].identifier||"",count:1,lastAccessed:Date.now()}),m("Metrics event: Flag",l,"has been read with value via stream update",r)}return l==="value"?X(t):t[l]}})):d.emit("changed",{deleted:t.deleted,flag:t.flag,value:X(t)})},Z=function(){return Y?new Proxy({},{get(t,i){var p,E,r;let l=t[i];if(c&&t.hasOwnProperty(i)){let g=t[i],F=S.find(ne=>ne.featureIdentifier===i&&g===ne.featureValue);F?(F.variationIdentifier=((p=w[i])==null?void 0:p.identifier)||"",$(F)):S.push({featureIdentifier:i,featureValue:g,variationIdentifier:((E=w[i])==null?void 0:E.identifier)||"",count:1,lastAccessed:Date.now()}),m("Metrics event: Flag:",i,"has been read with value:",g,"variationIdentifier:",(r=w[i])==null?void 0:r.identifier)}return l}}):{}},A=Z();be(n,u).then(t=>C(void 0,null,function*(){if(s)return;b=t;let i=(0,Ee.default)(t);if(T={Authorization:`Bearer ${b}`,"Harness-AccountID":i.accountID,"Harness-EnvironmentID":i.environmentIdentifier,"Harness-SDK-Info":pe},m("Authenticated",i),globalThis.localStorage&&globalThis.localStorage.HARNESS_FF_METRICS)try{delete globalThis.localStorage.HARNESS_FF_METRICS,m("Picking up metrics from previous session")}catch(E){}y=window.setTimeout(K,u.eventsSyncInterval),o=i.environment,f=i.clusterIdentifier;let l=!!Object.keys(w).length;if((yield _())||m("Fetch all flags ok",A),!s){if(u.streamEnabled?(m("Streaming mode enabled"),Ie()):u.pollingEnabled?(m("Polling mode enabled"),we()):m("Streaming and polling mode disabled"),!l){N();let E=D({},A);k(),d.emit("ready",E)}Q=!0}})).catch(t=>{R("Authentication error: ",t),d.emit("auth error",t),d.emit("error",t)});let _=()=>C(void 0,null,function*(){try{let t=yield h(`${u.baseUrl}/client/env/${o}/target/${e.identifier}/evaluations?cluster=${f}`,{headers:T});if(t.ok){let i=yield t.json();i.forEach(O),d.emit("flags loaded",i)}else R("Features fetch operation error: ",t),d.emit("fetch flags error",t),d.emit("error",t)}catch(t){return R("Features fetch operation error: ",t),d.emit("fetch flags error",t),d.emit("error",t),t}}),ee=t=>C(void 0,null,function*(){try{let i=yield h(`${u.baseUrl}/client/env/${o}/target/${e.identifier}/evaluations/${t}?cluster=${f}`,{headers:T});if(i.ok){let l=yield i.json();O(l)}else R("Feature fetch operation error: ",i),d.emit("fetch flag error",i),d.emit("error",i)}catch(i){R("Feature fetch operation error: ",i),d.emit("fetch flag error",i),d.emit("error",i)}}),O=t=>{N();let i=X(t);i!==A[t.flag]&&(m("Flag variation has changed for ",t.identifier),A[t.flag]=i,w[t.flag]=U(D({},t),{value:i}),Se(t)),k()};I=new V(_,u,u.pollingInterval);let Ie=()=>{let t=r=>{switch(r.event){case"create":l(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):setTimeout(()=>ee(r.identifier),1e3);break;case"patch":l(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):ee(r.identifier);break;case"delete":delete A[r.identifier],d.emit("changed",{flag:r.identifier,value:void 0,deleted:!0}),m("Evaluation deleted",{message:r,storage:A});break}},i=r=>!(!r||!r.flag||!r.identifier||!r.kind||!r.value),l=r=>!(!r||r.length==0||!r.every(g=>i(g))),p=r=>{r.event==="patch"&&(l(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):_())},E=`${u.baseUrl}/stream?cluster=${f}`;v=new G(d,u,E,n,T,I,r=>{r.domain==="flag"?t(r):r.domain==="target-segment"&&p(r)}),v.start()},we=()=>{I.start()},q=(t,i)=>d.on(t,i),ye=(t,i)=>{t?d.off(t,i):te()},Te=(t,i)=>{var r;if(!c||Y||i===void 0)return;let l=i,p=t,E=S.find(g=>g.featureIdentifier===p&&g.featureValue===l);E?($(E),E.variationIdentifier=((r=w[p])==null?void 0:r.identifier)||""):S.push({featureIdentifier:p,featureValue:l,count:1,variationIdentifier:w[p].identifier||"",lastAccessed:Date.now()})},te=()=>{s=!0,m("Closing event stream"),A=Z(),w={},clearTimeout(y),d.all.clear(),typeof(v==null?void 0:v.close)=="function"&&v.close()},ie=(t,i=!0)=>{t.length&&j(()=>{let l=!!Object.keys(w).length;if(t.forEach(O),!l){N();let p=D({},A);k(),d.emit("ready",p)}},i)};if(u.cache&&"localStorage"in window){let t=!0,i=H(e.identifier,typeof u.cache=="boolean"?{}:u.cache);i!=null&&i.length&&j(()=>{m("loading from cache",i),ie(i,!1),d.emit("cache loaded",i)}),q("flags loaded",l=>{L(e.identifier,l),t=!1}),q("changed",l=>{t||(l.deleted?ue(e.identifier,l.flag):de(e.identifier,l))})}return{on:q,off:ye,close:te,setEvaluations:ie,registerAPIRequestMiddleware:t=>{h=J(t)},refreshEvaluations:()=>{Q&&!s&&Date.now()-z>=6e4&&(_(),z=Date.now())},variation:(t,i,l=!1)=>ge(t,i,A,Te,l)}};0&&(module.exports={Event,initialize}); | ||
var Te=Object.create;var x=Object.defineProperty,Ae=Object.defineProperties,Ce=Object.getOwnPropertyDescriptor,Oe=Object.getOwnPropertyDescriptors,Fe=Object.getOwnPropertyNames,ae=Object.getOwnPropertySymbols,xe=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty,Ve=Object.prototype.propertyIsEnumerable;var re=(n,e,a)=>e in n?x(n,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):n[e]=a,T=(n,e)=>{for(var a in e||(e={}))oe.call(e,a)&&re(n,a,e[a]);if(ae)for(var a of ae(e))Ve.call(e,a)&&re(n,a,e[a]);return n},U=(n,e)=>Ae(n,Oe(e));var Ne=(n,e)=>{for(var a in e)x(n,a,{get:e[a],enumerable:!0})},se=(n,e,a,l)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Fe(e))!oe.call(n,o)&&o!==a&&x(n,o,{get:()=>e[o],enumerable:!(l=Ce(e,o))||l.enumerable});return n};var le=(n,e,a)=>(a=n!=null?Te(xe(n)):{},se(e||!n||!n.__esModule?x(a,"default",{value:n,enumerable:!0}):a,n)),ke=n=>se(x({},"__esModule",{value:!0}),n);var C=(n,e,a)=>new Promise((l,o)=>{var f=R=>{try{S(a.next(R))}catch(D){o(D)}},v=R=>{try{S(a.throw(R))}catch(D){o(D)}},S=R=>R.done?l(R.value):Promise.resolve(R.value).then(f,v);S((a=a.apply(n,e)).next())});var Le={};Ne(Le,{Event:()=>M,initialize:()=>He});module.exports=ke(Le);var Ee=le(require("jwt-decode")),me=le(require("mitt"));var M=(h=>(h.READY="ready",h.CONNECTED="connected",h.DISCONNECTED="disconnected",h.FLAGS_LOADED="flags loaded",h.CACHE_LOADED="cache loaded",h.CHANGED="changed",h.ERROR="error",h.ERROR_METRICS="metrics error",h.ERROR_AUTH="auth error",h.ERROR_FETCH_FLAGS="fetch flags error",h.ERROR_FETCH_FLAG="fetch flag error",h.ERROR_STREAM="stream error",h))(M||{});var ce={debug:!1,baseUrl:"https://config.ff.harness.io/api/1.0",eventUrl:"https://events.ff.harness.io/api/1.0",eventsSyncInterval:6e4,pollingInterval:6e4,streamEnabled:!0,pollingEnabled:!1,allAttributesPrivate:!1,privateAttributeNames:[],cache:!1},y=(n,...e)=>console.error(`[FF-SDK] ${n}`,...e),j=(n,e=!0)=>{e?setTimeout(n,0):n()},P=(n,e)=>Math.round(Math.random()*(e-n)+n);function W(n){return"HARNESS_FF_CACHE_"+n}function H(n,e={}){let a=W(n),l=parseInt(window.localStorage.getItem(a+".ts"));if(e!=null&&e.ttl&&!isNaN(l)&&l+e.ttl<Date.now())return _e(n),[];let o=window.localStorage.getItem(a);if(o)try{return JSON.parse(o)}catch(f){}return[]}function L(n,e){let a=W(n);window.localStorage.setItem(a,JSON.stringify(e)),window.localStorage.setItem(a+".ts",Date.now().toString())}function de(n,e){let a=H(n),l=a.find(({flag:o})=>o===e.flag);l?Object.assign(l,e):a.push(e),L(n,a)}function ue(n,e){let a=H(n),l=a.findIndex(({flag:o})=>o===e);l>-1&&(a.splice(l,1),L(n,a))}function _e(n){let e=W(n);window.localStorage.removeItem(e),window.localStorage.removeItem(e+".ts")}function J(n){return function(...a){let[l,o]=n(a);return fetch(l,o)}}var fe=3e4,G=class{constructor(e,a,l,o,f,v,S){this.closed=!1;this.eventBus=e,this.configurations=a,this.url=l,this.apiKey=o,this.standardHeaders=f,this.eventCallback=S,this.fallbackPoller=v}start(){let e=c=>{c.toString().split(/\r?\n/).forEach(a)},a=c=>{if(c.startsWith("data:")){let w=JSON.parse(c.substring(5));this.logDebug("Received event from stream: ",w),this.eventCallback(w)}},l=()=>{this.logDebug("Stream connected"),this.eventBus.emit("connected")},o=()=>{clearInterval(D);let c=P(1e3,1e4);this.logDebug("Stream disconnected, will reconnect in "+c+"ms"),this.eventBus.emit("disconnected"),setTimeout(()=>this.start(),c)},f=c=>{c&&y("Stream has issue",c),this.fallBackToPolling(),this.eventBus.emit("stream error",c),this.eventBus.emit("error",c),o()},v=T({"Cache-Control":"no-cache",Accept:"text/event-stream","API-Key":this.apiKey},this.standardHeaders);this.logDebug("SSE HTTP start request",this.url),this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url);for(let[c,w]of Object.entries(v))this.xhr.setRequestHeader(c,w);this.xhr.timeout=24*60*60*1e3,this.xhr.onerror=()=>{f("XMLHttpRequest error on SSE stream")},this.xhr.onabort=()=>{this.logDebug("SSE aborted"),this.closed||f(null)},this.xhr.ontimeout=()=>{f("SSE timeout")},this.xhr.onload=()=>{if(this.xhr.status>=400&&this.xhr.status<=599){f(`HTTP code ${this.xhr.status}`);return}l()};let S=0,R=Date.now();this.xhr.onprogress=()=>{this.stopFallBackPolling(),R=Date.now();let c=this.xhr.responseText.slice(S);S+=c.length,this.logDebug("SSE GOT: "+c),e(c)};let D=setInterval(()=>{R<Date.now()-fe&&(y("SSE read timeout"),this.xhr.abort())},fe);this.xhr.send()}close(){this.closed=!0,this.xhr&&this.xhr.abort(),this.stopFallBackPolling()}fallBackToPolling(){!this.fallbackPoller.isPolling()&&this.configurations.pollingEnabled&&(this.logDebug("Falling back to polling mode while stream recovers"),this.fallbackPoller.start())}stopFallBackPolling(){this.fallbackPoller.isPolling()&&(this.logDebug("Stopping fallback polling mode"),this.fallbackPoller.stop())}logDebug(e,...a){this.configurations.debug&&console.debug(`[FF-SDK] Streaming: ${e}`,...a)}};function ge(n,e,a,l,o){let f=n in a,v=f?a[n]:e;return f&&l(n,v),o?{value:v,isDefaultValue:!f}:v}var V=class{constructor(e,a){this.fetchFlagsFn=e;this.configurations=a;this.maxAttempts=5}start(){if(this.isPolling()){this.logDebug("Already polling.");return}this.isRunning=!0,setTimeout(()=>this.poll(),this.configurations.pollingInterval)}poll(){this.attemptFetch().finally(()=>{this.timeoutId=setTimeout(()=>this.poll(),this.configurations.pollingInterval)})}attemptFetch(){return C(this,null,function*(){for(let e=1;e<=this.maxAttempts;e++){let a=yield this.fetchFlagsFn();if(!a){this.logDebug("Successfully polled for flag updates");return}if(y("Error when polling for flag updates",a),e>=this.maxAttempts){this.logDebug(`Maximum attempts reached for polling for flags. Next poll in ${this.configurations.pollingInterval}ms.`);return}this.logDebug(`Polling for flags attempt #${e} failed. Remaining attempts: ${this.maxAttempts-e}.`);let l=P(1e3,1e4);yield new Promise(o=>setTimeout(o,l))}})}stop(){this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=void 0,this.isRunning=!1)}isPolling(){return this.isRunning}logDebug(e,...a){this.configurations.debug&&console.debug(`[FF-SDK] Poller: ${e}`,...a)}};var Re="1.16.0",pe=`Javascript ${Re} Client`,Me=500,Pe=globalThis.fetch,Y=!!globalThis.Proxy,X=n=>{let{value:e}=n;try{switch(n.kind.toLowerCase()){case"int":case"number":e=Number(e);break;case"boolean":e=e.toString().toLowerCase()==="true";break;case"json":e=JSON.parse(e);break}}catch(a){y(a)}return e},He=(n,e,a)=>{let l=!1,o,f,v,S,R,D,c=!0,w={},h=J(t=>t),z=0,Q=!1,N=()=>{c=!1},k=()=>{c=!0},b=[],d=(0,me.default)(),u=T(T({},ce),a);u.eventsSyncInterval<6e4&&(u.eventsSyncInterval=6e4),u.pollingInterval<6e4&&(u.pollingInterval=6e4);let m=(t,...i)=>{u.debug&&console.debug(`[FF-SDK] ${t}`,...i)},$=t=>{if(c){let i=Date.now();i-t.lastAccessed>Me&&(t.count++,t.lastAccessed=i)}};globalThis.onbeforeunload=()=>{b.length&&globalThis.localStorage&&(N(),globalThis.localStorage.HARNESS_FF_METRICS=JSON.stringify(b),k())};let be=(t,i)=>C(void 0,null,function*(){return(yield(yield Pe(`${i.baseUrl}/client/auth`,{method:"POST",headers:{"Content-Type":"application/json","Harness-SDK-Info":pe},body:JSON.stringify({apiKey:t,target:U(T({},e),{identifier:String(e.identifier)})})})).json()).authToken}),B=0,K=()=>{if(b.length){m("Sending metrics...",{metrics:b,evaluations:I});let t={metricsData:b.map(i=>({timestamp:Date.now(),count:i.count,metricsType:"FFMETRICS",attributes:[{key:"featureIdentifier",value:i.featureIdentifier},{key:"featureName",value:i.featureIdentifier},{key:"variationIdentifier",value:i.variationIdentifier},{key:"target",value:e.identifier},{key:"SDK_NAME",value:"JavaScript"},{key:"SDK_LANGUAGE",value:"JavaScript"},{key:"SDK_TYPE",value:"client"},{key:"SDK_VERSION",value:Re}]}))};h(`${u.eventUrl}/metrics/${o}?cluster=${f}`,{method:"POST",headers:T({"Content-Type":"application/json"},w),body:JSON.stringify(t)}).then(()=>{b=[],B=0}).catch(i=>{B++&&(b=[],B=0),m(i),d.emit("metrics error",i)}).finally(()=>{D=window.setTimeout(K,u.eventsSyncInterval)})}else D=window.setTimeout(K,u.eventsSyncInterval)},I={},Se=t=>{m("Sending event for",t.flag),Y?d.emit("changed",new Proxy(t,{get(i,s){var p;if(c&&i.hasOwnProperty(s)&&s==="value"){let E=i.flag,r=t.value,g=b.find(F=>F.featureIdentifier===E&&F.featureValue===r);g?($(g),g.variationIdentifier=((p=I[E])==null?void 0:p.identifier)||""):b.push({featureIdentifier:E,featureValue:String(r),variationIdentifier:I[E].identifier||"",count:1,lastAccessed:Date.now()}),m("Metrics event: Flag",s,"has been read with value via stream update",r)}return s==="value"?X(t):t[s]}})):d.emit("changed",{deleted:t.deleted,flag:t.flag,value:X(t)})},Z=function(){return Y?new Proxy({},{get(t,i){var p,E,r;let s=t[i];if(c&&t.hasOwnProperty(i)){let g=t[i],F=b.find(ne=>ne.featureIdentifier===i&&g===ne.featureValue);F?(F.variationIdentifier=((p=I[i])==null?void 0:p.identifier)||"",$(F)):b.push({featureIdentifier:i,featureValue:g,variationIdentifier:((E=I[i])==null?void 0:E.identifier)||"",count:1,lastAccessed:Date.now()}),m("Metrics event: Flag:",i,"has been read with value:",g,"variationIdentifier:",(r=I[i])==null?void 0:r.identifier)}return s}}):{}},A=Z();be(n,u).then(t=>C(void 0,null,function*(){if(l)return;R=t;let i=(0,Ee.default)(t);if(w={Authorization:`Bearer ${R}`,"Harness-AccountID":i.accountID,"Harness-EnvironmentID":i.environmentIdentifier,"Harness-SDK-Info":pe},m("Authenticated",i),globalThis.localStorage&&globalThis.localStorage.HARNESS_FF_METRICS)try{delete globalThis.localStorage.HARNESS_FF_METRICS,m("Picking up metrics from previous session")}catch(E){}D=window.setTimeout(K,u.eventsSyncInterval),o=i.environment,f=i.clusterIdentifier;let s=!!Object.keys(I).length;if((yield _())||m("Fetch all flags ok",A),!l){if(u.streamEnabled?(m("Streaming mode enabled"),Ie()):u.pollingEnabled?(m("Polling mode enabled"),ye()):m("Streaming and polling mode disabled"),!s){N();let E=T({},A);k(),d.emit("ready",E)}Q=!0}})).catch(t=>{y("Authentication error: ",t),d.emit("auth error",t),d.emit("error",t)});let _=()=>C(void 0,null,function*(){try{let t=yield h(`${u.baseUrl}/client/env/${o}/target/${e.identifier}/evaluations?cluster=${f}`,{headers:w});if(t.ok){let i=yield t.json();i.forEach(O),d.emit("flags loaded",i)}else y("Features fetch operation error: ",t),d.emit("fetch flags error",t),d.emit("error",t)}catch(t){return y("Features fetch operation error: ",t),d.emit("fetch flags error",t),d.emit("error",t),t}}),ee=t=>C(void 0,null,function*(){try{let i=yield h(`${u.baseUrl}/client/env/${o}/target/${e.identifier}/evaluations/${t}?cluster=${f}`,{headers:w});if(i.ok){let s=yield i.json();O(s)}else y("Feature fetch operation error: ",i),d.emit("fetch flag error",i),d.emit("error",i)}catch(i){y("Feature fetch operation error: ",i),d.emit("fetch flag error",i),d.emit("error",i)}}),O=t=>{N();let i=X(t);i!==A[t.flag]&&(m("Flag variation has changed for ",t.identifier),A[t.flag]=i,I[t.flag]=U(T({},t),{value:i}),Se(t)),k()};S=new V(_,u);let Ie=()=>{let t=r=>{switch(r.event){case"create":s(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):setTimeout(()=>ee(r.identifier),1e3);break;case"patch":s(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):ee(r.identifier);break;case"delete":delete A[r.identifier],d.emit("changed",{flag:r.identifier,value:void 0,deleted:!0}),m("Evaluation deleted",{message:r,storage:A});break}},i=r=>!(!r||!r.flag||!r.identifier||!r.kind||!r.value),s=r=>!(!r||r.length==0||!r.every(g=>i(g))),p=r=>{r.event==="patch"&&(s(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):_())},E=`${u.baseUrl}/stream?cluster=${f}`;v=new G(d,u,E,n,w,S,r=>{r.domain==="flag"?t(r):r.domain==="target-segment"&&p(r)}),v.start()},ye=()=>{S.start()},q=(t,i)=>d.on(t,i),De=(t,i)=>{t?d.off(t,i):te()},we=(t,i)=>{var r;if(!c||Y||i===void 0)return;let s=i,p=t,E=b.find(g=>g.featureIdentifier===p&&g.featureValue===s);E?($(E),E.variationIdentifier=((r=I[p])==null?void 0:r.identifier)||""):b.push({featureIdentifier:p,featureValue:s,count:1,variationIdentifier:I[p].identifier||"",lastAccessed:Date.now()})},te=()=>{l=!0,m("Closing event stream"),A=Z(),I={},clearTimeout(D),d.all.clear(),typeof(v==null?void 0:v.close)=="function"&&v.close()},ie=(t,i=!0)=>{t.length&&j(()=>{let s=!!Object.keys(I).length;if(t.forEach(O),!s){N();let p=T({},A);k(),d.emit("ready",p)}},i)};if(u.cache&&"localStorage"in window){let t=!0,i=H(e.identifier,typeof u.cache=="boolean"?{}:u.cache);i!=null&&i.length&&j(()=>{m("loading from cache",i),ie(i,!1),d.emit("cache loaded",i)}),q("flags loaded",s=>{L(e.identifier,s),t=!1}),q("changed",s=>{t||(s.deleted?ue(e.identifier,s.flag):de(e.identifier,s))})}return{on:q,off:De,close:te,setEvaluations:ie,registerAPIRequestMiddleware:t=>{h=J(t)},refreshEvaluations:()=>{Q&&!l&&Date.now()-z>=6e4&&(_(),z=Date.now())},variation:(t,i,s=!1)=>ge(t,i,A,we,s)}};0&&(module.exports={Event,initialize}); |
@@ -1,1 +0,2 @@ | ||
var HarnessFFSDK=(()=>{var _=Object.defineProperty,Ce=Object.defineProperties,De=Object.getOwnPropertyDescriptor,Oe=Object.getOwnPropertyDescriptors,Fe=Object.getOwnPropertyNames,oe=Object.getOwnPropertySymbols;var le=Object.prototype.hasOwnProperty,xe=Object.prototype.propertyIsEnumerable;var se=(t,e,i)=>e in t?_(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i,A=(t,e)=>{for(var i in e||(e={}))le.call(e,i)&&se(t,i,e[i]);if(oe)for(var i of oe(e))xe.call(e,i)&&se(t,i,e[i]);return t},j=(t,e)=>Ce(t,Oe(e));var ke=(t,e)=>{for(var i in e)_(t,i,{get:e[i],enumerable:!0})},Ve=(t,e,i,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Fe(e))!le.call(t,s)&&s!==i&&_(t,s,{get:()=>e[s],enumerable:!(r=De(e,s))||r.enumerable});return t};var Ne=t=>Ve(_({},"__esModule",{value:!0}),t);var D=(t,e,i)=>new Promise((r,s)=>{var c=R=>{try{I(i.next(R))}catch(y){s(y)}},g=R=>{try{I(i.throw(R))}catch(y){s(y)}},I=R=>R.done?r(R.value):Promise.resolve(R.value).then(c,g);I((i=i.apply(t,e)).next())});var $e={};ke($e,{Event:()=>P,initialize:()=>Ge});function J(t){this.message=t}J.prototype=new Error,J.prototype.name="InvalidCharacterError";var ce=typeof window!="undefined"&&window.atob&&window.atob.bind(window)||function(t){var e=String(t).replace(/=+$/,"");if(e.length%4==1)throw new J("'atob' failed: The string to be decoded is not correctly encoded.");for(var i,r,s=0,c=0,g="";r=e.charAt(c++);~r&&(i=s%4?64*i+r:r,s++%4)?g+=String.fromCharCode(255&i>>(-2*s&6)):0)r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(r);return g};function _e(t){var e=t.replace(/-/g,"+").replace(/_/g,"/");switch(e.length%4){case 0:break;case 2:e+="==";break;case 3:e+="=";break;default:throw"Illegal base64url string!"}try{return function(i){return decodeURIComponent(ce(i).replace(/(.)/g,function(r,s){var c=s.charCodeAt(0).toString(16).toUpperCase();return c.length<2&&(c="0"+c),"%"+c}))}(e)}catch(i){return ce(e)}}function M(t){this.message=t}function Me(t,e){if(typeof t!="string")throw new M("Invalid token specified");var i=(e=e||{}).header===!0?0:1;try{return JSON.parse(_e(t.split(".")[i]))}catch(r){throw new M("Invalid token specified: "+r.message)}}M.prototype=new Error,M.prototype.name="InvalidTokenError";var de=Me;function ue(t){return{all:t=t||new Map,on:function(e,i){var r=t.get(e);r&&r.push(i)||t.set(e,[i])},off:function(e,i){var r=t.get(e);r&&r.splice(r.indexOf(i)>>>0,1)},emit:function(e,i){(t.get(e)||[]).slice().map(function(r){r(i)}),(t.get("*")||[]).slice().map(function(r){r(e,i)})}}}var P=(p=>(p.READY="ready",p.CONNECTED="connected",p.DISCONNECTED="disconnected",p.FLAGS_LOADED="flags loaded",p.CACHE_LOADED="cache loaded",p.CHANGED="changed",p.ERROR="error",p.ERROR_METRICS="metrics error",p.ERROR_AUTH="auth error",p.ERROR_FETCH_FLAGS="fetch flags error",p.ERROR_FETCH_FLAG="fetch flag error",p.ERROR_STREAM="stream error",p))(P||{});var fe={debug:!1,baseUrl:"https://config.ff.harness.io/api/1.0",eventUrl:"https://events.ff.harness.io/api/1.0",eventsSyncInterval:6e4,pollingInterval:6e4,streamEnabled:!0,pollingEnabled:!1,allAttributesPrivate:!1,privateAttributeNames:[],cache:!1},b=(t,...e)=>console.error(`[FF-SDK] ${t}`,...e),W=(t,e=!0)=>{e?setTimeout(t,0):t()},H=(t,e)=>Math.round(Math.random()*(e-t)+t);function Y(t){return"HARNESS_FF_CACHE_"+t}function L(t,e={}){let i=Y(t),r=parseInt(window.localStorage.getItem(i+".ts"));if(e!=null&&e.ttl&&!isNaN(r)&&r+e.ttl<Date.now())return Pe(t),[];let s=window.localStorage.getItem(i);if(s)try{return JSON.parse(s)}catch(c){}return[]}function G(t,e){let i=Y(t);window.localStorage.setItem(i,JSON.stringify(e)),window.localStorage.setItem(i+".ts",Date.now().toString())}function ge(t,e){let i=L(t),r=i.find(({flag:s})=>s===e.flag);r?Object.assign(r,e):i.push(e),G(t,i)}function he(t,e){let i=L(t),r=i.findIndex(({flag:s})=>s===e);r>-1&&(i.splice(r,1),G(t,i))}function Pe(t){let e=Y(t);window.localStorage.removeItem(e),window.localStorage.removeItem(e+".ts")}function X(t){return function(...i){let[r,s]=t(i);return fetch(r,s)}}var pe=3e4,$=class{constructor(e,i,r,s,c,g,I){this.closed=!1;this.eventBus=e,this.configurations=i,this.url=r,this.apiKey=s,this.standardHeaders=c,this.eventCallback=I,this.fallbackPoller=g}start(){let e=d=>{d.toString().split(/\r?\n/).forEach(i)},i=d=>{if(d.startsWith("data:")){let T=JSON.parse(d.substring(5));this.logDebug("Received event from stream: ",T),this.eventCallback(T)}},r=()=>{this.logDebug("Stream connected"),this.eventBus.emit("connected")},s=()=>{clearInterval(y);let d=H(1e3,1e4);this.logDebug("Stream disconnected, will reconnect in "+d+"ms"),this.eventBus.emit("disconnected"),setTimeout(()=>this.start(),d)},c=d=>{d&&b("Stream has issue",d),this.fallBackToPolling(),this.eventBus.emit("stream error",d),this.eventBus.emit("error",d),s()},g=A({"Cache-Control":"no-cache",Accept:"text/event-stream","API-Key":this.apiKey},this.standardHeaders);this.logDebug("SSE HTTP start request",this.url),this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url);for(let[d,T]of Object.entries(g))this.xhr.setRequestHeader(d,T);this.xhr.timeout=24*60*60*1e3,this.xhr.onerror=()=>{c("XMLHttpRequest error on SSE stream")},this.xhr.onabort=()=>{this.logDebug("SSE aborted"),this.closed||c(null)},this.xhr.ontimeout=()=>{c("SSE timeout")},this.xhr.onload=()=>{if(this.xhr.status>=400&&this.xhr.status<=599){c(`HTTP code ${this.xhr.status}`);return}this.stopFallBackPolling(),r()};let I=0,R=Date.now();this.xhr.onprogress=()=>{R=Date.now();let d=this.xhr.responseText.slice(I);I+=d.length,this.logDebug("SSE GOT: "+d),e(d)};let y=setInterval(()=>{R<Date.now()-pe&&(b("SSE read timeout"),this.xhr.abort())},pe);this.xhr.send()}close(){this.closed=!0,this.xhr&&this.xhr.abort(),this.stopFallBackPolling()}fallBackToPolling(){!this.fallbackPoller.isPolling()&&this.configurations.pollingEnabled&&(b("Falling back to polling mode while stream recovers"),this.fallbackPoller.start())}stopFallBackPolling(){this.fallbackPoller.isPolling()&&(b("Stopping fallback polling mode"),this.fallbackPoller.stop())}logDebug(e,...i){this.configurations.debug&&console.debug(`[FF-SDK] Streaming: ${e}`,...i)}};function ve(t,e,i,r,s){let c=t in i,g=c?i[t]:e;return c&&r(t,g),s?{value:g,isDefaultValue:!c}:g}var x=class{constructor(e,i,r){this.fetchFlagsFn=e;this.configurations=i;this.pollInterval=r;this.maxAttempts=5}start(){if(this.isPolling()){this.logDebug("Already polling.");return}this.configurations.pollingEnabled&&(this.isRunning=!0,window.setTimeout(()=>this.poll(),this.configurations.pollingInterval))}poll(){this.attemptFetch().finally(()=>{this.timeoutId=window.setTimeout(()=>this.poll(),this.configurations.pollingInterval)})}attemptFetch(){return D(this,null,function*(){for(let e=1;e<=this.maxAttempts;e++){let i=yield this.fetchFlagsFn();if(!i){this.logDebug("Successfully polled for flag updates");return}if(b("Error when polling for flag updates",i),e>=this.maxAttempts){this.logDebug(`Maximum attempts reached for polling for flags. Next poll in ${this.pollInterval}ms.`);return}this.logDebug(`Polling for flags attempt #${e} failed. Remaining attempts: ${this.maxAttempts-e}.`);let r=H(1e3,1e4);yield new Promise(s=>setTimeout(s,r))}})}stop(){this.timeoutId&&(window.clearTimeout(this.timeoutId),this.timeoutId=void 0,this.isRunning=!1)}isPolling(){return this.isRunning}logDebug(e,...i){this.configurations.debug&&console.debug(`[FF-SDK] Poller: ${e}`,...i)}};var Re="1.16.0",be=`Javascript ${Re} Client`,He=500,Le=globalThis.fetch,z=!!globalThis.Proxy,Q=t=>{let{value:e}=t;try{switch(t.kind.toLowerCase()){case"int":case"number":e=Number(e);break;case"boolean":e=e.toString().toLowerCase()==="true";break;case"json":e=JSON.parse(e);break}}catch(i){b(i)}return e},Ge=(t,e,i)=>{let r=!1,s,c,g,I,R,y,d=!0,T={},p=X(n=>n),Z=0,ee=!1,k=()=>{d=!1},V=()=>{d=!0},S=[],u=ue(),f=A(A({},fe),i);f.eventsSyncInterval<6e4&&(f.eventsSyncInterval=6e4),f.pollingInterval<6e4&&(f.pollingInterval=6e4);let E=(n,...a)=>{f.debug&&console.debug(`[FF-SDK] ${n}`,...a)},B=n=>{if(d){let a=Date.now();a-n.lastAccessed>He&&(n.count++,n.lastAccessed=a)}};globalThis.onbeforeunload=()=>{S.length&&globalThis.localStorage&&(k(),globalThis.localStorage.HARNESS_FF_METRICS=JSON.stringify(S),V())};let Se=(n,a)=>D(void 0,null,function*(){return(yield(yield Le(`${a.baseUrl}/client/auth`,{method:"POST",headers:{"Content-Type":"application/json","Harness-SDK-Info":be},body:JSON.stringify({apiKey:n,target:j(A({},e),{identifier:String(e.identifier)})})})).json()).authToken}),K=0,U=()=>{if(S.length){E("Sending metrics...",{metrics:S,evaluations:w});let n={metricsData:S.map(a=>({timestamp:Date.now(),count:a.count,metricsType:"FFMETRICS",attributes:[{key:"featureIdentifier",value:a.featureIdentifier},{key:"featureName",value:a.featureIdentifier},{key:"variationIdentifier",value:a.variationIdentifier},{key:"target",value:e.identifier},{key:"SDK_NAME",value:"JavaScript"},{key:"SDK_LANGUAGE",value:"JavaScript"},{key:"SDK_TYPE",value:"client"},{key:"SDK_VERSION",value:Re}]}))};p(`${f.eventUrl}/metrics/${s}?cluster=${c}`,{method:"POST",headers:A({"Content-Type":"application/json"},T),body:JSON.stringify(n)}).then(()=>{S=[],K=0}).catch(a=>{K++&&(S=[],K=0),E(a),u.emit("metrics error",a)}).finally(()=>{y=window.setTimeout(U,f.eventsSyncInterval)})}else y=window.setTimeout(U,f.eventsSyncInterval)},w={},Ie=n=>{E("Sending event for",n.flag),z?u.emit("changed",new Proxy(n,{get(a,l){var v;if(d&&a.hasOwnProperty(l)&&l==="value"){let m=a.flag,o=n.value,h=S.find(F=>F.featureIdentifier===m&&F.featureValue===o);h?(B(h),h.variationIdentifier=((v=w[m])==null?void 0:v.identifier)||""):S.push({featureIdentifier:m,featureValue:String(o),variationIdentifier:w[m].identifier||"",count:1,lastAccessed:Date.now()}),E("Metrics event: Flag",l,"has been read with value via stream update",o)}return l==="value"?Q(n):n[l]}})):u.emit("changed",{deleted:n.deleted,flag:n.flag,value:Q(n)})},te=function(){return z?new Proxy({},{get(n,a){var v,m,o;let l=n[a];if(d&&n.hasOwnProperty(a)){let h=n[a],F=S.find(re=>re.featureIdentifier===a&&h===re.featureValue);F?(F.variationIdentifier=((v=w[a])==null?void 0:v.identifier)||"",B(F)):S.push({featureIdentifier:a,featureValue:h,variationIdentifier:((m=w[a])==null?void 0:m.identifier)||"",count:1,lastAccessed:Date.now()}),E("Metrics event: Flag:",a,"has been read with value:",h,"variationIdentifier:",(o=w[a])==null?void 0:o.identifier)}return l}}):{}},C=te();Se(t,f).then(n=>D(void 0,null,function*(){if(r)return;R=n;let a=de(n);if(T={Authorization:`Bearer ${R}`,"Harness-AccountID":a.accountID,"Harness-EnvironmentID":a.environmentIdentifier,"Harness-SDK-Info":be},E("Authenticated",a),globalThis.localStorage&&globalThis.localStorage.HARNESS_FF_METRICS)try{delete globalThis.localStorage.HARNESS_FF_METRICS,E("Picking up metrics from previous session")}catch(m){}y=window.setTimeout(U,f.eventsSyncInterval),s=a.environment,c=a.clusterIdentifier;let l=!!Object.keys(w).length;if((yield N())||E("Fetch all flags ok",C),!r){if(f.streamEnabled?(E("Streaming mode enabled"),we()):f.pollingEnabled?(E("Polling mode enabled"),ye()):E("Streaming and polling mode disabled"),!l){k();let m=A({},C);V(),u.emit("ready",m)}ee=!0}})).catch(n=>{b("Authentication error: ",n),u.emit("auth error",n),u.emit("error",n)});let N=()=>D(void 0,null,function*(){try{let n=yield p(`${f.baseUrl}/client/env/${s}/target/${e.identifier}/evaluations?cluster=${c}`,{headers:T});if(n.ok){let a=yield n.json();a.forEach(O),u.emit("flags loaded",a)}else b("Features fetch operation error: ",n),u.emit("fetch flags error",n),u.emit("error",n)}catch(n){return b("Features fetch operation error: ",n),u.emit("fetch flags error",n),u.emit("error",n),n}}),ie=n=>D(void 0,null,function*(){try{let a=yield p(`${f.baseUrl}/client/env/${s}/target/${e.identifier}/evaluations/${n}?cluster=${c}`,{headers:T});if(a.ok){let l=yield a.json();O(l)}else b("Feature fetch operation error: ",a),u.emit("fetch flag error",a),u.emit("error",a)}catch(a){b("Feature fetch operation error: ",a),u.emit("fetch flag error",a),u.emit("error",a)}}),O=n=>{k();let a=Q(n);a!==C[n.flag]&&(E("Flag variation has changed for ",n.identifier),C[n.flag]=a,w[n.flag]=j(A({},n),{value:a}),Ie(n)),V()};I=new x(N,f,f.pollingInterval);let we=()=>{let n=o=>{switch(o.event){case"create":l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):setTimeout(()=>ie(o.identifier),1e3);break;case"patch":l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):ie(o.identifier);break;case"delete":delete C[o.identifier],u.emit("changed",{flag:o.identifier,value:void 0,deleted:!0}),E("Evaluation deleted",{message:o,storage:C});break}},a=o=>!(!o||!o.flag||!o.identifier||!o.kind||!o.value),l=o=>!(!o||o.length==0||!o.every(h=>a(h))),v=o=>{o.event==="patch"&&(l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):N())},m=`${f.baseUrl}/stream?cluster=${c}`;g=new $(u,f,m,t,T,I,o=>{o.domain==="flag"?n(o):o.domain==="target-segment"&&v(o)}),g.start()},ye=()=>{I.start()},q=(n,a)=>u.on(n,a),Te=(n,a)=>{n?u.off(n,a):ne()},Ae=(n,a)=>{var o;if(!d||z||a===void 0)return;let l=a,v=n,m=S.find(h=>h.featureIdentifier===v&&h.featureValue===l);m?(B(m),m.variationIdentifier=((o=w[v])==null?void 0:o.identifier)||""):S.push({featureIdentifier:v,featureValue:l,count:1,variationIdentifier:w[v].identifier||"",lastAccessed:Date.now()})},ne=()=>{r=!0,E("Closing event stream"),C=te(),w={},clearTimeout(y),u.all.clear(),typeof(g==null?void 0:g.close)=="function"&&g.close()},ae=(n,a=!0)=>{n.length&&W(()=>{let l=!!Object.keys(w).length;if(n.forEach(O),!l){k();let v=A({},C);V(),u.emit("ready",v)}},a)};if(f.cache&&"localStorage"in window){let n=!0,a=L(e.identifier,typeof f.cache=="boolean"?{}:f.cache);a!=null&&a.length&&W(()=>{E("loading from cache",a),ae(a,!1),u.emit("cache loaded",a)}),q("flags loaded",l=>{G(e.identifier,l),n=!1}),q("changed",l=>{n||(l.deleted?he(e.identifier,l.flag):ge(e.identifier,l))})}return{on:q,off:Te,close:ne,setEvaluations:ae,registerAPIRequestMiddleware:n=>{p=X(n)},refreshEvaluations:()=>{ee&&!r&&Date.now()-Z>=6e4&&(N(),Z=Date.now())},variation:(n,a,l=!1)=>ve(n,a,C,Ae,l)}};return Ne($e);})(); | ||
var HarnessFFSDK=(()=>{var _=Object.defineProperty,Ae=Object.defineProperties,Ce=Object.getOwnPropertyDescriptor,Oe=Object.getOwnPropertyDescriptors,Fe=Object.getOwnPropertyNames,oe=Object.getOwnPropertySymbols;var le=Object.prototype.hasOwnProperty,xe=Object.prototype.propertyIsEnumerable;var se=(t,e,i)=>e in t?_(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i,D=(t,e)=>{for(var i in e||(e={}))le.call(e,i)&&se(t,i,e[i]);if(oe)for(var i of oe(e))xe.call(e,i)&&se(t,i,e[i]);return t},j=(t,e)=>Ae(t,Oe(e));var ke=(t,e)=>{for(var i in e)_(t,i,{get:e[i],enumerable:!0})},Ve=(t,e,i,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Fe(e))!le.call(t,s)&&s!==i&&_(t,s,{get:()=>e[s],enumerable:!(r=Ce(e,s))||r.enumerable});return t};var Ne=t=>Ve(_({},"__esModule",{value:!0}),t);var C=(t,e,i)=>new Promise((r,s)=>{var c=b=>{try{S(i.next(b))}catch(y){s(y)}},g=b=>{try{S(i.throw(b))}catch(y){s(y)}},S=b=>b.done?r(b.value):Promise.resolve(b.value).then(c,g);S((i=i.apply(t,e)).next())});var $e={};ke($e,{Event:()=>P,initialize:()=>Ge});function J(t){this.message=t}J.prototype=new Error,J.prototype.name="InvalidCharacterError";var ce=typeof window!="undefined"&&window.atob&&window.atob.bind(window)||function(t){var e=String(t).replace(/=+$/,"");if(e.length%4==1)throw new J("'atob' failed: The string to be decoded is not correctly encoded.");for(var i,r,s=0,c=0,g="";r=e.charAt(c++);~r&&(i=s%4?64*i+r:r,s++%4)?g+=String.fromCharCode(255&i>>(-2*s&6)):0)r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(r);return g};function _e(t){var e=t.replace(/-/g,"+").replace(/_/g,"/");switch(e.length%4){case 0:break;case 2:e+="==";break;case 3:e+="=";break;default:throw"Illegal base64url string!"}try{return function(i){return decodeURIComponent(ce(i).replace(/(.)/g,function(r,s){var c=s.charCodeAt(0).toString(16).toUpperCase();return c.length<2&&(c="0"+c),"%"+c}))}(e)}catch(i){return ce(e)}}function M(t){this.message=t}function Me(t,e){if(typeof t!="string")throw new M("Invalid token specified");var i=(e=e||{}).header===!0?0:1;try{return JSON.parse(_e(t.split(".")[i]))}catch(r){throw new M("Invalid token specified: "+r.message)}}M.prototype=new Error,M.prototype.name="InvalidTokenError";var de=Me;function ue(t){return{all:t=t||new Map,on:function(e,i){var r=t.get(e);r&&r.push(i)||t.set(e,[i])},off:function(e,i){var r=t.get(e);r&&r.splice(r.indexOf(i)>>>0,1)},emit:function(e,i){(t.get(e)||[]).slice().map(function(r){r(i)}),(t.get("*")||[]).slice().map(function(r){r(e,i)})}}}var P=(p=>(p.READY="ready",p.CONNECTED="connected",p.DISCONNECTED="disconnected",p.FLAGS_LOADED="flags loaded",p.CACHE_LOADED="cache loaded",p.CHANGED="changed",p.ERROR="error",p.ERROR_METRICS="metrics error",p.ERROR_AUTH="auth error",p.ERROR_FETCH_FLAGS="fetch flags error",p.ERROR_FETCH_FLAG="fetch flag error",p.ERROR_STREAM="stream error",p))(P||{});var fe={debug:!1,baseUrl:"https://config.ff.harness.io/api/1.0",eventUrl:"https://events.ff.harness.io/api/1.0",eventsSyncInterval:6e4,pollingInterval:6e4,streamEnabled:!0,pollingEnabled:!1,allAttributesPrivate:!1,privateAttributeNames:[],cache:!1},w=(t,...e)=>console.error(`[FF-SDK] ${t}`,...e),W=(t,e=!0)=>{e?setTimeout(t,0):t()},H=(t,e)=>Math.round(Math.random()*(e-t)+t);function Y(t){return"HARNESS_FF_CACHE_"+t}function L(t,e={}){let i=Y(t),r=parseInt(window.localStorage.getItem(i+".ts"));if(e!=null&&e.ttl&&!isNaN(r)&&r+e.ttl<Date.now())return Pe(t),[];let s=window.localStorage.getItem(i);if(s)try{return JSON.parse(s)}catch(c){}return[]}function G(t,e){let i=Y(t);window.localStorage.setItem(i,JSON.stringify(e)),window.localStorage.setItem(i+".ts",Date.now().toString())}function ge(t,e){let i=L(t),r=i.find(({flag:s})=>s===e.flag);r?Object.assign(r,e):i.push(e),G(t,i)}function he(t,e){let i=L(t),r=i.findIndex(({flag:s})=>s===e);r>-1&&(i.splice(r,1),G(t,i))}function Pe(t){let e=Y(t);window.localStorage.removeItem(e),window.localStorage.removeItem(e+".ts")}function X(t){return function(...i){let[r,s]=t(i);return fetch(r,s)}}var pe=3e4,$=class{constructor(e,i,r,s,c,g,S){this.closed=!1;this.eventBus=e,this.configurations=i,this.url=r,this.apiKey=s,this.standardHeaders=c,this.eventCallback=S,this.fallbackPoller=g}start(){let e=d=>{d.toString().split(/\r?\n/).forEach(i)},i=d=>{if(d.startsWith("data:")){let T=JSON.parse(d.substring(5));this.logDebug("Received event from stream: ",T),this.eventCallback(T)}},r=()=>{this.logDebug("Stream connected"),this.eventBus.emit("connected")},s=()=>{clearInterval(y);let d=H(1e3,1e4);this.logDebug("Stream disconnected, will reconnect in "+d+"ms"),this.eventBus.emit("disconnected"),setTimeout(()=>this.start(),d)},c=d=>{d&&w("Stream has issue",d),this.fallBackToPolling(),this.eventBus.emit("stream error",d),this.eventBus.emit("error",d),s()},g=D({"Cache-Control":"no-cache",Accept:"text/event-stream","API-Key":this.apiKey},this.standardHeaders);this.logDebug("SSE HTTP start request",this.url),this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url);for(let[d,T]of Object.entries(g))this.xhr.setRequestHeader(d,T);this.xhr.timeout=24*60*60*1e3,this.xhr.onerror=()=>{c("XMLHttpRequest error on SSE stream")},this.xhr.onabort=()=>{this.logDebug("SSE aborted"),this.closed||c(null)},this.xhr.ontimeout=()=>{c("SSE timeout")},this.xhr.onload=()=>{if(this.xhr.status>=400&&this.xhr.status<=599){c(`HTTP code ${this.xhr.status}`);return}r()};let S=0,b=Date.now();this.xhr.onprogress=()=>{this.stopFallBackPolling(),b=Date.now();let d=this.xhr.responseText.slice(S);S+=d.length,this.logDebug("SSE GOT: "+d),e(d)};let y=setInterval(()=>{b<Date.now()-pe&&(w("SSE read timeout"),this.xhr.abort())},pe);this.xhr.send()}close(){this.closed=!0,this.xhr&&this.xhr.abort(),this.stopFallBackPolling()}fallBackToPolling(){!this.fallbackPoller.isPolling()&&this.configurations.pollingEnabled&&(this.logDebug("Falling back to polling mode while stream recovers"),this.fallbackPoller.start())}stopFallBackPolling(){this.fallbackPoller.isPolling()&&(this.logDebug("Stopping fallback polling mode"),this.fallbackPoller.stop())}logDebug(e,...i){this.configurations.debug&&console.debug(`[FF-SDK] Streaming: ${e}`,...i)}};function ve(t,e,i,r,s){let c=t in i,g=c?i[t]:e;return c&&r(t,g),s?{value:g,isDefaultValue:!c}:g}var x=class{constructor(e,i){this.fetchFlagsFn=e;this.configurations=i;this.maxAttempts=5}start(){if(this.isPolling()){this.logDebug("Already polling.");return}this.isRunning=!0,setTimeout(()=>this.poll(),this.configurations.pollingInterval)}poll(){this.attemptFetch().finally(()=>{this.timeoutId=setTimeout(()=>this.poll(),this.configurations.pollingInterval)})}attemptFetch(){return C(this,null,function*(){for(let e=1;e<=this.maxAttempts;e++){let i=yield this.fetchFlagsFn();if(!i){this.logDebug("Successfully polled for flag updates");return}if(w("Error when polling for flag updates",i),e>=this.maxAttempts){this.logDebug(`Maximum attempts reached for polling for flags. Next poll in ${this.configurations.pollingInterval}ms.`);return}this.logDebug(`Polling for flags attempt #${e} failed. Remaining attempts: ${this.maxAttempts-e}.`);let r=H(1e3,1e4);yield new Promise(s=>setTimeout(s,r))}})}stop(){this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=void 0,this.isRunning=!1)}isPolling(){return this.isRunning}logDebug(e,...i){this.configurations.debug&&console.debug(`[FF-SDK] Poller: ${e}`,...i)}};var Re="1.16.0",be=`Javascript ${Re} Client`,He=500,Le=globalThis.fetch,z=!!globalThis.Proxy,Q=t=>{let{value:e}=t;try{switch(t.kind.toLowerCase()){case"int":case"number":e=Number(e);break;case"boolean":e=e.toString().toLowerCase()==="true";break;case"json":e=JSON.parse(e);break}}catch(i){w(i)}return e},Ge=(t,e,i)=>{let r=!1,s,c,g,S,b,y,d=!0,T={},p=X(n=>n),Z=0,ee=!1,k=()=>{d=!1},V=()=>{d=!0},R=[],u=ue(),f=D(D({},fe),i);f.eventsSyncInterval<6e4&&(f.eventsSyncInterval=6e4),f.pollingInterval<6e4&&(f.pollingInterval=6e4);let E=(n,...a)=>{f.debug&&console.debug(`[FF-SDK] ${n}`,...a)},B=n=>{if(d){let a=Date.now();a-n.lastAccessed>He&&(n.count++,n.lastAccessed=a)}};globalThis.onbeforeunload=()=>{R.length&&globalThis.localStorage&&(k(),globalThis.localStorage.HARNESS_FF_METRICS=JSON.stringify(R),V())};let Se=(n,a)=>C(void 0,null,function*(){return(yield(yield Le(`${a.baseUrl}/client/auth`,{method:"POST",headers:{"Content-Type":"application/json","Harness-SDK-Info":be},body:JSON.stringify({apiKey:n,target:j(D({},e),{identifier:String(e.identifier)})})})).json()).authToken}),K=0,U=()=>{if(R.length){E("Sending metrics...",{metrics:R,evaluations:I});let n={metricsData:R.map(a=>({timestamp:Date.now(),count:a.count,metricsType:"FFMETRICS",attributes:[{key:"featureIdentifier",value:a.featureIdentifier},{key:"featureName",value:a.featureIdentifier},{key:"variationIdentifier",value:a.variationIdentifier},{key:"target",value:e.identifier},{key:"SDK_NAME",value:"JavaScript"},{key:"SDK_LANGUAGE",value:"JavaScript"},{key:"SDK_TYPE",value:"client"},{key:"SDK_VERSION",value:Re}]}))};p(`${f.eventUrl}/metrics/${s}?cluster=${c}`,{method:"POST",headers:D({"Content-Type":"application/json"},T),body:JSON.stringify(n)}).then(()=>{R=[],K=0}).catch(a=>{K++&&(R=[],K=0),E(a),u.emit("metrics error",a)}).finally(()=>{y=window.setTimeout(U,f.eventsSyncInterval)})}else y=window.setTimeout(U,f.eventsSyncInterval)},I={},Ie=n=>{E("Sending event for",n.flag),z?u.emit("changed",new Proxy(n,{get(a,l){var v;if(d&&a.hasOwnProperty(l)&&l==="value"){let m=a.flag,o=n.value,h=R.find(F=>F.featureIdentifier===m&&F.featureValue===o);h?(B(h),h.variationIdentifier=((v=I[m])==null?void 0:v.identifier)||""):R.push({featureIdentifier:m,featureValue:String(o),variationIdentifier:I[m].identifier||"",count:1,lastAccessed:Date.now()}),E("Metrics event: Flag",l,"has been read with value via stream update",o)}return l==="value"?Q(n):n[l]}})):u.emit("changed",{deleted:n.deleted,flag:n.flag,value:Q(n)})},te=function(){return z?new Proxy({},{get(n,a){var v,m,o;let l=n[a];if(d&&n.hasOwnProperty(a)){let h=n[a],F=R.find(re=>re.featureIdentifier===a&&h===re.featureValue);F?(F.variationIdentifier=((v=I[a])==null?void 0:v.identifier)||"",B(F)):R.push({featureIdentifier:a,featureValue:h,variationIdentifier:((m=I[a])==null?void 0:m.identifier)||"",count:1,lastAccessed:Date.now()}),E("Metrics event: Flag:",a,"has been read with value:",h,"variationIdentifier:",(o=I[a])==null?void 0:o.identifier)}return l}}):{}},A=te();Se(t,f).then(n=>C(void 0,null,function*(){if(r)return;b=n;let a=de(n);if(T={Authorization:`Bearer ${b}`,"Harness-AccountID":a.accountID,"Harness-EnvironmentID":a.environmentIdentifier,"Harness-SDK-Info":be},E("Authenticated",a),globalThis.localStorage&&globalThis.localStorage.HARNESS_FF_METRICS)try{delete globalThis.localStorage.HARNESS_FF_METRICS,E("Picking up metrics from previous session")}catch(m){}y=window.setTimeout(U,f.eventsSyncInterval),s=a.environment,c=a.clusterIdentifier;let l=!!Object.keys(I).length;if((yield N())||E("Fetch all flags ok",A),!r){if(f.streamEnabled?(E("Streaming mode enabled"),we()):f.pollingEnabled?(E("Polling mode enabled"),ye()):E("Streaming and polling mode disabled"),!l){k();let m=D({},A);V(),u.emit("ready",m)}ee=!0}})).catch(n=>{w("Authentication error: ",n),u.emit("auth error",n),u.emit("error",n)});let N=()=>C(void 0,null,function*(){try{let n=yield p(`${f.baseUrl}/client/env/${s}/target/${e.identifier}/evaluations?cluster=${c}`,{headers:T});if(n.ok){let a=yield n.json();a.forEach(O),u.emit("flags loaded",a)}else w("Features fetch operation error: ",n),u.emit("fetch flags error",n),u.emit("error",n)}catch(n){return w("Features fetch operation error: ",n),u.emit("fetch flags error",n),u.emit("error",n),n}}),ie=n=>C(void 0,null,function*(){try{let a=yield p(`${f.baseUrl}/client/env/${s}/target/${e.identifier}/evaluations/${n}?cluster=${c}`,{headers:T});if(a.ok){let l=yield a.json();O(l)}else w("Feature fetch operation error: ",a),u.emit("fetch flag error",a),u.emit("error",a)}catch(a){w("Feature fetch operation error: ",a),u.emit("fetch flag error",a),u.emit("error",a)}}),O=n=>{k();let a=Q(n);a!==A[n.flag]&&(E("Flag variation has changed for ",n.identifier),A[n.flag]=a,I[n.flag]=j(D({},n),{value:a}),Ie(n)),V()};S=new x(N,f);let we=()=>{let n=o=>{switch(o.event){case"create":l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):setTimeout(()=>ie(o.identifier),1e3);break;case"patch":l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):ie(o.identifier);break;case"delete":delete A[o.identifier],u.emit("changed",{flag:o.identifier,value:void 0,deleted:!0}),E("Evaluation deleted",{message:o,storage:A});break}},a=o=>!(!o||!o.flag||!o.identifier||!o.kind||!o.value),l=o=>!(!o||o.length==0||!o.every(h=>a(h))),v=o=>{o.event==="patch"&&(l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):N())},m=`${f.baseUrl}/stream?cluster=${c}`;g=new $(u,f,m,t,T,S,o=>{o.domain==="flag"?n(o):o.domain==="target-segment"&&v(o)}),g.start()},ye=()=>{S.start()},q=(n,a)=>u.on(n,a),Te=(n,a)=>{n?u.off(n,a):ne()},De=(n,a)=>{var o;if(!d||z||a===void 0)return;let l=a,v=n,m=R.find(h=>h.featureIdentifier===v&&h.featureValue===l);m?(B(m),m.variationIdentifier=((o=I[v])==null?void 0:o.identifier)||""):R.push({featureIdentifier:v,featureValue:l,count:1,variationIdentifier:I[v].identifier||"",lastAccessed:Date.now()})},ne=()=>{r=!0,E("Closing event stream"),A=te(),I={},clearTimeout(y),u.all.clear(),typeof(g==null?void 0:g.close)=="function"&&g.close()},ae=(n,a=!0)=>{n.length&&W(()=>{let l=!!Object.keys(I).length;if(n.forEach(O),!l){k();let v=D({},A);V(),u.emit("ready",v)}},a)};if(f.cache&&"localStorage"in window){let n=!0,a=L(e.identifier,typeof f.cache=="boolean"?{}:f.cache);a!=null&&a.length&&W(()=>{E("loading from cache",a),ae(a,!1),u.emit("cache loaded",a)}),q("flags loaded",l=>{G(e.identifier,l),n=!1}),q("changed",l=>{n||(l.deleted?he(e.identifier,l.flag):ge(e.identifier,l))})}return{on:q,off:Te,close:ne,setEvaluations:ae,registerAPIRequestMiddleware:n=>{p=X(n)},refreshEvaluations:()=>{ee&&!r&&Date.now()-Z>=6e4&&(N(),Z=Date.now())},variation:(n,a,l=!1)=>ve(n,a,A,De,l)}};return Ne($e);})(); | ||
//# sourceMappingURL=sdk.client-iife.js.map |
@@ -1,1 +0,1 @@ | ||
var Te=Object.defineProperty,Ae=Object.defineProperties;var Ce=Object.getOwnPropertyDescriptors;var re=Object.getOwnPropertySymbols;var De=Object.prototype.hasOwnProperty,Oe=Object.prototype.propertyIsEnumerable;var oe=(n,e,a)=>e in n?Te(n,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):n[e]=a,A=(n,e)=>{for(var a in e||(e={}))De.call(e,a)&&oe(n,a,e[a]);if(re)for(var a of re(e))Oe.call(e,a)&&oe(n,a,e[a]);return n},U=(n,e)=>Ae(n,Ce(e));var D=(n,e,a)=>new Promise((r,s)=>{var c=R=>{try{I(a.next(R))}catch(y){s(y)}},g=R=>{try{I(a.throw(R))}catch(y){s(y)}},I=R=>R.done?r(R.value):Promise.resolve(R.value).then(c,g);I((a=a.apply(n,e)).next())});function q(n){this.message=n}q.prototype=new Error,q.prototype.name="InvalidCharacterError";var se=typeof window!="undefined"&&window.atob&&window.atob.bind(window)||function(n){var e=String(n).replace(/=+$/,"");if(e.length%4==1)throw new q("'atob' failed: The string to be decoded is not correctly encoded.");for(var a,r,s=0,c=0,g="";r=e.charAt(c++);~r&&(a=s%4?64*a+r:r,s++%4)?g+=String.fromCharCode(255&a>>(-2*s&6)):0)r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(r);return g};function Fe(n){var e=n.replace(/-/g,"+").replace(/_/g,"/");switch(e.length%4){case 0:break;case 2:e+="==";break;case 3:e+="=";break;default:throw"Illegal base64url string!"}try{return function(a){return decodeURIComponent(se(a).replace(/(.)/g,function(r,s){var c=s.charCodeAt(0).toString(16).toUpperCase();return c.length<2&&(c="0"+c),"%"+c}))}(e)}catch(a){return se(e)}}function _(n){this.message=n}function xe(n,e){if(typeof n!="string")throw new _("Invalid token specified");var a=(e=e||{}).header===!0?0:1;try{return JSON.parse(Fe(n.split(".")[a]))}catch(r){throw new _("Invalid token specified: "+r.message)}}_.prototype=new Error,_.prototype.name="InvalidTokenError";var le=xe;function ce(n){return{all:n=n||new Map,on:function(e,a){var r=n.get(e);r&&r.push(a)||n.set(e,[a])},off:function(e,a){var r=n.get(e);r&&r.splice(r.indexOf(a)>>>0,1)},emit:function(e,a){(n.get(e)||[]).slice().map(function(r){r(a)}),(n.get("*")||[]).slice().map(function(r){r(e,a)})}}}var j=(p=>(p.READY="ready",p.CONNECTED="connected",p.DISCONNECTED="disconnected",p.FLAGS_LOADED="flags loaded",p.CACHE_LOADED="cache loaded",p.CHANGED="changed",p.ERROR="error",p.ERROR_METRICS="metrics error",p.ERROR_AUTH="auth error",p.ERROR_FETCH_FLAGS="fetch flags error",p.ERROR_FETCH_FLAG="fetch flag error",p.ERROR_STREAM="stream error",p))(j||{});var de={debug:!1,baseUrl:"https://config.ff.harness.io/api/1.0",eventUrl:"https://events.ff.harness.io/api/1.0",eventsSyncInterval:6e4,pollingInterval:6e4,streamEnabled:!0,pollingEnabled:!1,allAttributesPrivate:!1,privateAttributeNames:[],cache:!1},b=(n,...e)=>console.error(`[FF-SDK] ${n}`,...e),J=(n,e=!0)=>{e?setTimeout(n,0):n()},M=(n,e)=>Math.round(Math.random()*(e-n)+n);function W(n){return"HARNESS_FF_CACHE_"+n}function P(n,e={}){let a=W(n),r=parseInt(window.localStorage.getItem(a+".ts"));if(e!=null&&e.ttl&&!isNaN(r)&&r+e.ttl<Date.now())return ke(n),[];let s=window.localStorage.getItem(a);if(s)try{return JSON.parse(s)}catch(c){}return[]}function H(n,e){let a=W(n);window.localStorage.setItem(a,JSON.stringify(e)),window.localStorage.setItem(a+".ts",Date.now().toString())}function ue(n,e){let a=P(n),r=a.find(({flag:s})=>s===e.flag);r?Object.assign(r,e):a.push(e),H(n,a)}function fe(n,e){let a=P(n),r=a.findIndex(({flag:s})=>s===e);r>-1&&(a.splice(r,1),H(n,a))}function ke(n){let e=W(n);window.localStorage.removeItem(e),window.localStorage.removeItem(e+".ts")}function Y(n){return function(...a){let[r,s]=n(a);return fetch(r,s)}}var ge=3e4,L=class{constructor(e,a,r,s,c,g,I){this.closed=!1;this.eventBus=e,this.configurations=a,this.url=r,this.apiKey=s,this.standardHeaders=c,this.eventCallback=I,this.fallbackPoller=g}start(){let e=d=>{d.toString().split(/\r?\n/).forEach(a)},a=d=>{if(d.startsWith("data:")){let T=JSON.parse(d.substring(5));this.logDebug("Received event from stream: ",T),this.eventCallback(T)}},r=()=>{this.logDebug("Stream connected"),this.eventBus.emit("connected")},s=()=>{clearInterval(y);let d=M(1e3,1e4);this.logDebug("Stream disconnected, will reconnect in "+d+"ms"),this.eventBus.emit("disconnected"),setTimeout(()=>this.start(),d)},c=d=>{d&&b("Stream has issue",d),this.fallBackToPolling(),this.eventBus.emit("stream error",d),this.eventBus.emit("error",d),s()},g=A({"Cache-Control":"no-cache",Accept:"text/event-stream","API-Key":this.apiKey},this.standardHeaders);this.logDebug("SSE HTTP start request",this.url),this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url);for(let[d,T]of Object.entries(g))this.xhr.setRequestHeader(d,T);this.xhr.timeout=24*60*60*1e3,this.xhr.onerror=()=>{c("XMLHttpRequest error on SSE stream")},this.xhr.onabort=()=>{this.logDebug("SSE aborted"),this.closed||c(null)},this.xhr.ontimeout=()=>{c("SSE timeout")},this.xhr.onload=()=>{if(this.xhr.status>=400&&this.xhr.status<=599){c(`HTTP code ${this.xhr.status}`);return}this.stopFallBackPolling(),r()};let I=0,R=Date.now();this.xhr.onprogress=()=>{R=Date.now();let d=this.xhr.responseText.slice(I);I+=d.length,this.logDebug("SSE GOT: "+d),e(d)};let y=setInterval(()=>{R<Date.now()-ge&&(b("SSE read timeout"),this.xhr.abort())},ge);this.xhr.send()}close(){this.closed=!0,this.xhr&&this.xhr.abort(),this.stopFallBackPolling()}fallBackToPolling(){!this.fallbackPoller.isPolling()&&this.configurations.pollingEnabled&&(b("Falling back to polling mode while stream recovers"),this.fallbackPoller.start())}stopFallBackPolling(){this.fallbackPoller.isPolling()&&(b("Stopping fallback polling mode"),this.fallbackPoller.stop())}logDebug(e,...a){this.configurations.debug&&console.debug(`[FF-SDK] Streaming: ${e}`,...a)}};function he(n,e,a,r,s){let c=n in a,g=c?a[n]:e;return c&&r(n,g),s?{value:g,isDefaultValue:!c}:g}var x=class{constructor(e,a,r){this.fetchFlagsFn=e;this.configurations=a;this.pollInterval=r;this.maxAttempts=5}start(){if(this.isPolling()){this.logDebug("Already polling.");return}this.configurations.pollingEnabled&&(this.isRunning=!0,window.setTimeout(()=>this.poll(),this.configurations.pollingInterval))}poll(){this.attemptFetch().finally(()=>{this.timeoutId=window.setTimeout(()=>this.poll(),this.configurations.pollingInterval)})}attemptFetch(){return D(this,null,function*(){for(let e=1;e<=this.maxAttempts;e++){let a=yield this.fetchFlagsFn();if(!a){this.logDebug("Successfully polled for flag updates");return}if(b("Error when polling for flag updates",a),e>=this.maxAttempts){this.logDebug(`Maximum attempts reached for polling for flags. Next poll in ${this.pollInterval}ms.`);return}this.logDebug(`Polling for flags attempt #${e} failed. Remaining attempts: ${this.maxAttempts-e}.`);let r=M(1e3,1e4);yield new Promise(s=>setTimeout(s,r))}})}stop(){this.timeoutId&&(window.clearTimeout(this.timeoutId),this.timeoutId=void 0,this.isRunning=!1)}isPolling(){return this.isRunning}logDebug(e,...a){this.configurations.debug&&console.debug(`[FF-SDK] Poller: ${e}`,...a)}};var Ee="1.16.0",me=`Javascript ${Ee} Client`,Ve=500,Ne=globalThis.fetch,X=!!globalThis.Proxy,z=n=>{let{value:e}=n;try{switch(n.kind.toLowerCase()){case"int":case"number":e=Number(e);break;case"boolean":e=e.toString().toLowerCase()==="true";break;case"json":e=JSON.parse(e);break}}catch(a){b(a)}return e},ut=(n,e,a)=>{let r=!1,s,c,g,I,R,y,d=!0,T={},p=Y(t=>t),Q=0,Z=!1,k=()=>{d=!1},V=()=>{d=!0},S=[],u=ce(),f=A(A({},de),a);f.eventsSyncInterval<6e4&&(f.eventsSyncInterval=6e4),f.pollingInterval<6e4&&(f.pollingInterval=6e4);let E=(t,...i)=>{f.debug&&console.debug(`[FF-SDK] ${t}`,...i)},G=t=>{if(d){let i=Date.now();i-t.lastAccessed>Ve&&(t.count++,t.lastAccessed=i)}};globalThis.onbeforeunload=()=>{S.length&&globalThis.localStorage&&(k(),globalThis.localStorage.HARNESS_FF_METRICS=JSON.stringify(S),V())};let be=(t,i)=>D(void 0,null,function*(){return(yield(yield Ne(`${i.baseUrl}/client/auth`,{method:"POST",headers:{"Content-Type":"application/json","Harness-SDK-Info":me},body:JSON.stringify({apiKey:t,target:U(A({},e),{identifier:String(e.identifier)})})})).json()).authToken}),$=0,B=()=>{if(S.length){E("Sending metrics...",{metrics:S,evaluations:w});let t={metricsData:S.map(i=>({timestamp:Date.now(),count:i.count,metricsType:"FFMETRICS",attributes:[{key:"featureIdentifier",value:i.featureIdentifier},{key:"featureName",value:i.featureIdentifier},{key:"variationIdentifier",value:i.variationIdentifier},{key:"target",value:e.identifier},{key:"SDK_NAME",value:"JavaScript"},{key:"SDK_LANGUAGE",value:"JavaScript"},{key:"SDK_TYPE",value:"client"},{key:"SDK_VERSION",value:Ee}]}))};p(`${f.eventUrl}/metrics/${s}?cluster=${c}`,{method:"POST",headers:A({"Content-Type":"application/json"},T),body:JSON.stringify(t)}).then(()=>{S=[],$=0}).catch(i=>{$++&&(S=[],$=0),E(i),u.emit("metrics error",i)}).finally(()=>{y=window.setTimeout(B,f.eventsSyncInterval)})}else y=window.setTimeout(B,f.eventsSyncInterval)},w={},Re=t=>{E("Sending event for",t.flag),X?u.emit("changed",new Proxy(t,{get(i,l){var v;if(d&&i.hasOwnProperty(l)&&l==="value"){let m=i.flag,o=t.value,h=S.find(F=>F.featureIdentifier===m&&F.featureValue===o);h?(G(h),h.variationIdentifier=((v=w[m])==null?void 0:v.identifier)||""):S.push({featureIdentifier:m,featureValue:String(o),variationIdentifier:w[m].identifier||"",count:1,lastAccessed:Date.now()}),E("Metrics event: Flag",l,"has been read with value via stream update",o)}return l==="value"?z(t):t[l]}})):u.emit("changed",{deleted:t.deleted,flag:t.flag,value:z(t)})},ee=function(){return X?new Proxy({},{get(t,i){var v,m,o;let l=t[i];if(d&&t.hasOwnProperty(i)){let h=t[i],F=S.find(ae=>ae.featureIdentifier===i&&h===ae.featureValue);F?(F.variationIdentifier=((v=w[i])==null?void 0:v.identifier)||"",G(F)):S.push({featureIdentifier:i,featureValue:h,variationIdentifier:((m=w[i])==null?void 0:m.identifier)||"",count:1,lastAccessed:Date.now()}),E("Metrics event: Flag:",i,"has been read with value:",h,"variationIdentifier:",(o=w[i])==null?void 0:o.identifier)}return l}}):{}},C=ee();be(n,f).then(t=>D(void 0,null,function*(){if(r)return;R=t;let i=le(t);if(T={Authorization:`Bearer ${R}`,"Harness-AccountID":i.accountID,"Harness-EnvironmentID":i.environmentIdentifier,"Harness-SDK-Info":me},E("Authenticated",i),globalThis.localStorage&&globalThis.localStorage.HARNESS_FF_METRICS)try{delete globalThis.localStorage.HARNESS_FF_METRICS,E("Picking up metrics from previous session")}catch(m){}y=window.setTimeout(B,f.eventsSyncInterval),s=i.environment,c=i.clusterIdentifier;let l=!!Object.keys(w).length;if((yield N())||E("Fetch all flags ok",C),!r){if(f.streamEnabled?(E("Streaming mode enabled"),Se()):f.pollingEnabled?(E("Polling mode enabled"),Ie()):E("Streaming and polling mode disabled"),!l){k();let m=A({},C);V(),u.emit("ready",m)}Z=!0}})).catch(t=>{b("Authentication error: ",t),u.emit("auth error",t),u.emit("error",t)});let N=()=>D(void 0,null,function*(){try{let t=yield p(`${f.baseUrl}/client/env/${s}/target/${e.identifier}/evaluations?cluster=${c}`,{headers:T});if(t.ok){let i=yield t.json();i.forEach(O),u.emit("flags loaded",i)}else b("Features fetch operation error: ",t),u.emit("fetch flags error",t),u.emit("error",t)}catch(t){return b("Features fetch operation error: ",t),u.emit("fetch flags error",t),u.emit("error",t),t}}),te=t=>D(void 0,null,function*(){try{let i=yield p(`${f.baseUrl}/client/env/${s}/target/${e.identifier}/evaluations/${t}?cluster=${c}`,{headers:T});if(i.ok){let l=yield i.json();O(l)}else b("Feature fetch operation error: ",i),u.emit("fetch flag error",i),u.emit("error",i)}catch(i){b("Feature fetch operation error: ",i),u.emit("fetch flag error",i),u.emit("error",i)}}),O=t=>{k();let i=z(t);i!==C[t.flag]&&(E("Flag variation has changed for ",t.identifier),C[t.flag]=i,w[t.flag]=U(A({},t),{value:i}),Re(t)),V()};I=new x(N,f,f.pollingInterval);let Se=()=>{let t=o=>{switch(o.event){case"create":l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):setTimeout(()=>te(o.identifier),1e3);break;case"patch":l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):te(o.identifier);break;case"delete":delete C[o.identifier],u.emit("changed",{flag:o.identifier,value:void 0,deleted:!0}),E("Evaluation deleted",{message:o,storage:C});break}},i=o=>!(!o||!o.flag||!o.identifier||!o.kind||!o.value),l=o=>!(!o||o.length==0||!o.every(h=>i(h))),v=o=>{o.event==="patch"&&(l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):N())},m=`${f.baseUrl}/stream?cluster=${c}`;g=new L(u,f,m,n,T,I,o=>{o.domain==="flag"?t(o):o.domain==="target-segment"&&v(o)}),g.start()},Ie=()=>{I.start()},K=(t,i)=>u.on(t,i),we=(t,i)=>{t?u.off(t,i):ie()},ye=(t,i)=>{var o;if(!d||X||i===void 0)return;let l=i,v=t,m=S.find(h=>h.featureIdentifier===v&&h.featureValue===l);m?(G(m),m.variationIdentifier=((o=w[v])==null?void 0:o.identifier)||""):S.push({featureIdentifier:v,featureValue:l,count:1,variationIdentifier:w[v].identifier||"",lastAccessed:Date.now()})},ie=()=>{r=!0,E("Closing event stream"),C=ee(),w={},clearTimeout(y),u.all.clear(),typeof(g==null?void 0:g.close)=="function"&&g.close()},ne=(t,i=!0)=>{t.length&&J(()=>{let l=!!Object.keys(w).length;if(t.forEach(O),!l){k();let v=A({},C);V(),u.emit("ready",v)}},i)};if(f.cache&&"localStorage"in window){let t=!0,i=P(e.identifier,typeof f.cache=="boolean"?{}:f.cache);i!=null&&i.length&&J(()=>{E("loading from cache",i),ne(i,!1),u.emit("cache loaded",i)}),K("flags loaded",l=>{H(e.identifier,l),t=!1}),K("changed",l=>{t||(l.deleted?fe(e.identifier,l.flag):ue(e.identifier,l))})}return{on:K,off:we,close:ie,setEvaluations:ne,registerAPIRequestMiddleware:t=>{p=Y(t)},refreshEvaluations:()=>{Z&&!r&&Date.now()-Q>=6e4&&(N(),Q=Date.now())},variation:(t,i,l=!1)=>he(t,i,C,ye,l)}};export{j as Event,ut as initialize}; | ||
var Te=Object.defineProperty,De=Object.defineProperties;var Ae=Object.getOwnPropertyDescriptors;var re=Object.getOwnPropertySymbols;var Ce=Object.prototype.hasOwnProperty,Oe=Object.prototype.propertyIsEnumerable;var oe=(n,e,a)=>e in n?Te(n,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):n[e]=a,D=(n,e)=>{for(var a in e||(e={}))Ce.call(e,a)&&oe(n,a,e[a]);if(re)for(var a of re(e))Oe.call(e,a)&&oe(n,a,e[a]);return n},U=(n,e)=>De(n,Ae(e));var C=(n,e,a)=>new Promise((r,s)=>{var c=b=>{try{S(a.next(b))}catch(y){s(y)}},g=b=>{try{S(a.throw(b))}catch(y){s(y)}},S=b=>b.done?r(b.value):Promise.resolve(b.value).then(c,g);S((a=a.apply(n,e)).next())});function q(n){this.message=n}q.prototype=new Error,q.prototype.name="InvalidCharacterError";var se=typeof window!="undefined"&&window.atob&&window.atob.bind(window)||function(n){var e=String(n).replace(/=+$/,"");if(e.length%4==1)throw new q("'atob' failed: The string to be decoded is not correctly encoded.");for(var a,r,s=0,c=0,g="";r=e.charAt(c++);~r&&(a=s%4?64*a+r:r,s++%4)?g+=String.fromCharCode(255&a>>(-2*s&6)):0)r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(r);return g};function Fe(n){var e=n.replace(/-/g,"+").replace(/_/g,"/");switch(e.length%4){case 0:break;case 2:e+="==";break;case 3:e+="=";break;default:throw"Illegal base64url string!"}try{return function(a){return decodeURIComponent(se(a).replace(/(.)/g,function(r,s){var c=s.charCodeAt(0).toString(16).toUpperCase();return c.length<2&&(c="0"+c),"%"+c}))}(e)}catch(a){return se(e)}}function _(n){this.message=n}function xe(n,e){if(typeof n!="string")throw new _("Invalid token specified");var a=(e=e||{}).header===!0?0:1;try{return JSON.parse(Fe(n.split(".")[a]))}catch(r){throw new _("Invalid token specified: "+r.message)}}_.prototype=new Error,_.prototype.name="InvalidTokenError";var le=xe;function ce(n){return{all:n=n||new Map,on:function(e,a){var r=n.get(e);r&&r.push(a)||n.set(e,[a])},off:function(e,a){var r=n.get(e);r&&r.splice(r.indexOf(a)>>>0,1)},emit:function(e,a){(n.get(e)||[]).slice().map(function(r){r(a)}),(n.get("*")||[]).slice().map(function(r){r(e,a)})}}}var j=(p=>(p.READY="ready",p.CONNECTED="connected",p.DISCONNECTED="disconnected",p.FLAGS_LOADED="flags loaded",p.CACHE_LOADED="cache loaded",p.CHANGED="changed",p.ERROR="error",p.ERROR_METRICS="metrics error",p.ERROR_AUTH="auth error",p.ERROR_FETCH_FLAGS="fetch flags error",p.ERROR_FETCH_FLAG="fetch flag error",p.ERROR_STREAM="stream error",p))(j||{});var de={debug:!1,baseUrl:"https://config.ff.harness.io/api/1.0",eventUrl:"https://events.ff.harness.io/api/1.0",eventsSyncInterval:6e4,pollingInterval:6e4,streamEnabled:!0,pollingEnabled:!1,allAttributesPrivate:!1,privateAttributeNames:[],cache:!1},w=(n,...e)=>console.error(`[FF-SDK] ${n}`,...e),J=(n,e=!0)=>{e?setTimeout(n,0):n()},M=(n,e)=>Math.round(Math.random()*(e-n)+n);function W(n){return"HARNESS_FF_CACHE_"+n}function P(n,e={}){let a=W(n),r=parseInt(window.localStorage.getItem(a+".ts"));if(e!=null&&e.ttl&&!isNaN(r)&&r+e.ttl<Date.now())return ke(n),[];let s=window.localStorage.getItem(a);if(s)try{return JSON.parse(s)}catch(c){}return[]}function H(n,e){let a=W(n);window.localStorage.setItem(a,JSON.stringify(e)),window.localStorage.setItem(a+".ts",Date.now().toString())}function ue(n,e){let a=P(n),r=a.find(({flag:s})=>s===e.flag);r?Object.assign(r,e):a.push(e),H(n,a)}function fe(n,e){let a=P(n),r=a.findIndex(({flag:s})=>s===e);r>-1&&(a.splice(r,1),H(n,a))}function ke(n){let e=W(n);window.localStorage.removeItem(e),window.localStorage.removeItem(e+".ts")}function Y(n){return function(...a){let[r,s]=n(a);return fetch(r,s)}}var ge=3e4,L=class{constructor(e,a,r,s,c,g,S){this.closed=!1;this.eventBus=e,this.configurations=a,this.url=r,this.apiKey=s,this.standardHeaders=c,this.eventCallback=S,this.fallbackPoller=g}start(){let e=d=>{d.toString().split(/\r?\n/).forEach(a)},a=d=>{if(d.startsWith("data:")){let T=JSON.parse(d.substring(5));this.logDebug("Received event from stream: ",T),this.eventCallback(T)}},r=()=>{this.logDebug("Stream connected"),this.eventBus.emit("connected")},s=()=>{clearInterval(y);let d=M(1e3,1e4);this.logDebug("Stream disconnected, will reconnect in "+d+"ms"),this.eventBus.emit("disconnected"),setTimeout(()=>this.start(),d)},c=d=>{d&&w("Stream has issue",d),this.fallBackToPolling(),this.eventBus.emit("stream error",d),this.eventBus.emit("error",d),s()},g=D({"Cache-Control":"no-cache",Accept:"text/event-stream","API-Key":this.apiKey},this.standardHeaders);this.logDebug("SSE HTTP start request",this.url),this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url);for(let[d,T]of Object.entries(g))this.xhr.setRequestHeader(d,T);this.xhr.timeout=24*60*60*1e3,this.xhr.onerror=()=>{c("XMLHttpRequest error on SSE stream")},this.xhr.onabort=()=>{this.logDebug("SSE aborted"),this.closed||c(null)},this.xhr.ontimeout=()=>{c("SSE timeout")},this.xhr.onload=()=>{if(this.xhr.status>=400&&this.xhr.status<=599){c(`HTTP code ${this.xhr.status}`);return}r()};let S=0,b=Date.now();this.xhr.onprogress=()=>{this.stopFallBackPolling(),b=Date.now();let d=this.xhr.responseText.slice(S);S+=d.length,this.logDebug("SSE GOT: "+d),e(d)};let y=setInterval(()=>{b<Date.now()-ge&&(w("SSE read timeout"),this.xhr.abort())},ge);this.xhr.send()}close(){this.closed=!0,this.xhr&&this.xhr.abort(),this.stopFallBackPolling()}fallBackToPolling(){!this.fallbackPoller.isPolling()&&this.configurations.pollingEnabled&&(this.logDebug("Falling back to polling mode while stream recovers"),this.fallbackPoller.start())}stopFallBackPolling(){this.fallbackPoller.isPolling()&&(this.logDebug("Stopping fallback polling mode"),this.fallbackPoller.stop())}logDebug(e,...a){this.configurations.debug&&console.debug(`[FF-SDK] Streaming: ${e}`,...a)}};function he(n,e,a,r,s){let c=n in a,g=c?a[n]:e;return c&&r(n,g),s?{value:g,isDefaultValue:!c}:g}var x=class{constructor(e,a){this.fetchFlagsFn=e;this.configurations=a;this.maxAttempts=5}start(){if(this.isPolling()){this.logDebug("Already polling.");return}this.isRunning=!0,setTimeout(()=>this.poll(),this.configurations.pollingInterval)}poll(){this.attemptFetch().finally(()=>{this.timeoutId=setTimeout(()=>this.poll(),this.configurations.pollingInterval)})}attemptFetch(){return C(this,null,function*(){for(let e=1;e<=this.maxAttempts;e++){let a=yield this.fetchFlagsFn();if(!a){this.logDebug("Successfully polled for flag updates");return}if(w("Error when polling for flag updates",a),e>=this.maxAttempts){this.logDebug(`Maximum attempts reached for polling for flags. Next poll in ${this.configurations.pollingInterval}ms.`);return}this.logDebug(`Polling for flags attempt #${e} failed. Remaining attempts: ${this.maxAttempts-e}.`);let r=M(1e3,1e4);yield new Promise(s=>setTimeout(s,r))}})}stop(){this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=void 0,this.isRunning=!1)}isPolling(){return this.isRunning}logDebug(e,...a){this.configurations.debug&&console.debug(`[FF-SDK] Poller: ${e}`,...a)}};var Ee="1.16.0",me=`Javascript ${Ee} Client`,Ve=500,Ne=globalThis.fetch,X=!!globalThis.Proxy,z=n=>{let{value:e}=n;try{switch(n.kind.toLowerCase()){case"int":case"number":e=Number(e);break;case"boolean":e=e.toString().toLowerCase()==="true";break;case"json":e=JSON.parse(e);break}}catch(a){w(a)}return e},ut=(n,e,a)=>{let r=!1,s,c,g,S,b,y,d=!0,T={},p=Y(t=>t),Q=0,Z=!1,k=()=>{d=!1},V=()=>{d=!0},R=[],u=ce(),f=D(D({},de),a);f.eventsSyncInterval<6e4&&(f.eventsSyncInterval=6e4),f.pollingInterval<6e4&&(f.pollingInterval=6e4);let E=(t,...i)=>{f.debug&&console.debug(`[FF-SDK] ${t}`,...i)},G=t=>{if(d){let i=Date.now();i-t.lastAccessed>Ve&&(t.count++,t.lastAccessed=i)}};globalThis.onbeforeunload=()=>{R.length&&globalThis.localStorage&&(k(),globalThis.localStorage.HARNESS_FF_METRICS=JSON.stringify(R),V())};let be=(t,i)=>C(void 0,null,function*(){return(yield(yield Ne(`${i.baseUrl}/client/auth`,{method:"POST",headers:{"Content-Type":"application/json","Harness-SDK-Info":me},body:JSON.stringify({apiKey:t,target:U(D({},e),{identifier:String(e.identifier)})})})).json()).authToken}),$=0,B=()=>{if(R.length){E("Sending metrics...",{metrics:R,evaluations:I});let t={metricsData:R.map(i=>({timestamp:Date.now(),count:i.count,metricsType:"FFMETRICS",attributes:[{key:"featureIdentifier",value:i.featureIdentifier},{key:"featureName",value:i.featureIdentifier},{key:"variationIdentifier",value:i.variationIdentifier},{key:"target",value:e.identifier},{key:"SDK_NAME",value:"JavaScript"},{key:"SDK_LANGUAGE",value:"JavaScript"},{key:"SDK_TYPE",value:"client"},{key:"SDK_VERSION",value:Ee}]}))};p(`${f.eventUrl}/metrics/${s}?cluster=${c}`,{method:"POST",headers:D({"Content-Type":"application/json"},T),body:JSON.stringify(t)}).then(()=>{R=[],$=0}).catch(i=>{$++&&(R=[],$=0),E(i),u.emit("metrics error",i)}).finally(()=>{y=window.setTimeout(B,f.eventsSyncInterval)})}else y=window.setTimeout(B,f.eventsSyncInterval)},I={},Re=t=>{E("Sending event for",t.flag),X?u.emit("changed",new Proxy(t,{get(i,l){var v;if(d&&i.hasOwnProperty(l)&&l==="value"){let m=i.flag,o=t.value,h=R.find(F=>F.featureIdentifier===m&&F.featureValue===o);h?(G(h),h.variationIdentifier=((v=I[m])==null?void 0:v.identifier)||""):R.push({featureIdentifier:m,featureValue:String(o),variationIdentifier:I[m].identifier||"",count:1,lastAccessed:Date.now()}),E("Metrics event: Flag",l,"has been read with value via stream update",o)}return l==="value"?z(t):t[l]}})):u.emit("changed",{deleted:t.deleted,flag:t.flag,value:z(t)})},ee=function(){return X?new Proxy({},{get(t,i){var v,m,o;let l=t[i];if(d&&t.hasOwnProperty(i)){let h=t[i],F=R.find(ae=>ae.featureIdentifier===i&&h===ae.featureValue);F?(F.variationIdentifier=((v=I[i])==null?void 0:v.identifier)||"",G(F)):R.push({featureIdentifier:i,featureValue:h,variationIdentifier:((m=I[i])==null?void 0:m.identifier)||"",count:1,lastAccessed:Date.now()}),E("Metrics event: Flag:",i,"has been read with value:",h,"variationIdentifier:",(o=I[i])==null?void 0:o.identifier)}return l}}):{}},A=ee();be(n,f).then(t=>C(void 0,null,function*(){if(r)return;b=t;let i=le(t);if(T={Authorization:`Bearer ${b}`,"Harness-AccountID":i.accountID,"Harness-EnvironmentID":i.environmentIdentifier,"Harness-SDK-Info":me},E("Authenticated",i),globalThis.localStorage&&globalThis.localStorage.HARNESS_FF_METRICS)try{delete globalThis.localStorage.HARNESS_FF_METRICS,E("Picking up metrics from previous session")}catch(m){}y=window.setTimeout(B,f.eventsSyncInterval),s=i.environment,c=i.clusterIdentifier;let l=!!Object.keys(I).length;if((yield N())||E("Fetch all flags ok",A),!r){if(f.streamEnabled?(E("Streaming mode enabled"),Se()):f.pollingEnabled?(E("Polling mode enabled"),Ie()):E("Streaming and polling mode disabled"),!l){k();let m=D({},A);V(),u.emit("ready",m)}Z=!0}})).catch(t=>{w("Authentication error: ",t),u.emit("auth error",t),u.emit("error",t)});let N=()=>C(void 0,null,function*(){try{let t=yield p(`${f.baseUrl}/client/env/${s}/target/${e.identifier}/evaluations?cluster=${c}`,{headers:T});if(t.ok){let i=yield t.json();i.forEach(O),u.emit("flags loaded",i)}else w("Features fetch operation error: ",t),u.emit("fetch flags error",t),u.emit("error",t)}catch(t){return w("Features fetch operation error: ",t),u.emit("fetch flags error",t),u.emit("error",t),t}}),te=t=>C(void 0,null,function*(){try{let i=yield p(`${f.baseUrl}/client/env/${s}/target/${e.identifier}/evaluations/${t}?cluster=${c}`,{headers:T});if(i.ok){let l=yield i.json();O(l)}else w("Feature fetch operation error: ",i),u.emit("fetch flag error",i),u.emit("error",i)}catch(i){w("Feature fetch operation error: ",i),u.emit("fetch flag error",i),u.emit("error",i)}}),O=t=>{k();let i=z(t);i!==A[t.flag]&&(E("Flag variation has changed for ",t.identifier),A[t.flag]=i,I[t.flag]=U(D({},t),{value:i}),Re(t)),V()};S=new x(N,f);let Se=()=>{let t=o=>{switch(o.event){case"create":l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):setTimeout(()=>te(o.identifier),1e3);break;case"patch":l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):te(o.identifier);break;case"delete":delete A[o.identifier],u.emit("changed",{flag:o.identifier,value:void 0,deleted:!0}),E("Evaluation deleted",{message:o,storage:A});break}},i=o=>!(!o||!o.flag||!o.identifier||!o.kind||!o.value),l=o=>!(!o||o.length==0||!o.every(h=>i(h))),v=o=>{o.event==="patch"&&(l(o.evaluations)?o.evaluations.forEach(h=>{O(h)}):N())},m=`${f.baseUrl}/stream?cluster=${c}`;g=new L(u,f,m,n,T,S,o=>{o.domain==="flag"?t(o):o.domain==="target-segment"&&v(o)}),g.start()},Ie=()=>{S.start()},K=(t,i)=>u.on(t,i),we=(t,i)=>{t?u.off(t,i):ie()},ye=(t,i)=>{var o;if(!d||X||i===void 0)return;let l=i,v=t,m=R.find(h=>h.featureIdentifier===v&&h.featureValue===l);m?(G(m),m.variationIdentifier=((o=I[v])==null?void 0:o.identifier)||""):R.push({featureIdentifier:v,featureValue:l,count:1,variationIdentifier:I[v].identifier||"",lastAccessed:Date.now()})},ie=()=>{r=!0,E("Closing event stream"),A=ee(),I={},clearTimeout(y),u.all.clear(),typeof(g==null?void 0:g.close)=="function"&&g.close()},ne=(t,i=!0)=>{t.length&&J(()=>{let l=!!Object.keys(I).length;if(t.forEach(O),!l){k();let v=D({},A);V(),u.emit("ready",v)}},i)};if(f.cache&&"localStorage"in window){let t=!0,i=P(e.identifier,typeof f.cache=="boolean"?{}:f.cache);i!=null&&i.length&&J(()=>{E("loading from cache",i),ne(i,!1),u.emit("cache loaded",i)}),K("flags loaded",l=>{H(e.identifier,l),t=!1}),K("changed",l=>{t||(l.deleted?fe(e.identifier,l.flag):ue(e.identifier,l))})}return{on:K,off:we,close:ie,setEvaluations:ne,registerAPIRequestMiddleware:t=>{p=Y(t)},refreshEvaluations:()=>{Z&&!r&&Date.now()-Q>=6e4&&(N(),Q=Date.now())},variation:(t,i,l=!1)=>he(t,i,A,ye,l)}};export{j as Event,ut as initialize}; |
@@ -1,1 +0,1 @@ | ||
var be=Object.defineProperty,Se=Object.defineProperties;var Ie=Object.getOwnPropertyDescriptors;var ne=Object.getOwnPropertySymbols;var we=Object.prototype.hasOwnProperty,ye=Object.prototype.propertyIsEnumerable;var ae=(a,e,n)=>e in a?be(a,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):a[e]=n,D=(a,e)=>{for(var n in e||(e={}))we.call(e,n)&&ae(a,n,e[n]);if(ne)for(var n of ne(e))ye.call(e,n)&&ae(a,n,e[n]);return a},K=(a,e)=>Se(a,Ie(e));var C=(a,e,n)=>new Promise((s,c)=>{var f=b=>{try{I(n.next(b))}catch(y){c(y)}},v=b=>{try{I(n.throw(b))}catch(y){c(y)}},I=b=>b.done?s(b.value):Promise.resolve(b.value).then(f,v);I((n=n.apply(a,e)).next())});import De from"jwt-decode";import Ae from"mitt";var q=(h=>(h.READY="ready",h.CONNECTED="connected",h.DISCONNECTED="disconnected",h.FLAGS_LOADED="flags loaded",h.CACHE_LOADED="cache loaded",h.CHANGED="changed",h.ERROR="error",h.ERROR_METRICS="metrics error",h.ERROR_AUTH="auth error",h.ERROR_FETCH_FLAGS="fetch flags error",h.ERROR_FETCH_FLAG="fetch flag error",h.ERROR_STREAM="stream error",h))(q||{});var re={debug:!1,baseUrl:"https://config.ff.harness.io/api/1.0",eventUrl:"https://events.ff.harness.io/api/1.0",eventsSyncInterval:6e4,pollingInterval:6e4,streamEnabled:!0,pollingEnabled:!1,allAttributesPrivate:!1,privateAttributeNames:[],cache:!1},R=(a,...e)=>console.error(`[FF-SDK] ${a}`,...e),U=(a,e=!0)=>{e?setTimeout(a,0):a()},_=(a,e)=>Math.round(Math.random()*(e-a)+a);function j(a){return"HARNESS_FF_CACHE_"+a}function M(a,e={}){let n=j(a),s=parseInt(window.localStorage.getItem(n+".ts"));if(e!=null&&e.ttl&&!isNaN(s)&&s+e.ttl<Date.now())return Te(a),[];let c=window.localStorage.getItem(n);if(c)try{return JSON.parse(c)}catch(f){}return[]}function P(a,e){let n=j(a);window.localStorage.setItem(n,JSON.stringify(e)),window.localStorage.setItem(n+".ts",Date.now().toString())}function oe(a,e){let n=M(a),s=n.find(({flag:c})=>c===e.flag);s?Object.assign(s,e):n.push(e),P(a,n)}function se(a,e){let n=M(a),s=n.findIndex(({flag:c})=>c===e);s>-1&&(n.splice(s,1),P(a,n))}function Te(a){let e=j(a);window.localStorage.removeItem(e),window.localStorage.removeItem(e+".ts")}function W(a){return function(...n){let[s,c]=a(n);return fetch(s,c)}}var le=3e4,H=class{constructor(e,n,s,c,f,v,I){this.closed=!1;this.eventBus=e,this.configurations=n,this.url=s,this.apiKey=c,this.standardHeaders=f,this.eventCallback=I,this.fallbackPoller=v}start(){let e=l=>{l.toString().split(/\r?\n/).forEach(n)},n=l=>{if(l.startsWith("data:")){let T=JSON.parse(l.substring(5));this.logDebug("Received event from stream: ",T),this.eventCallback(T)}},s=()=>{this.logDebug("Stream connected"),this.eventBus.emit("connected")},c=()=>{clearInterval(y);let l=_(1e3,1e4);this.logDebug("Stream disconnected, will reconnect in "+l+"ms"),this.eventBus.emit("disconnected"),setTimeout(()=>this.start(),l)},f=l=>{l&&R("Stream has issue",l),this.fallBackToPolling(),this.eventBus.emit("stream error",l),this.eventBus.emit("error",l),c()},v=D({"Cache-Control":"no-cache",Accept:"text/event-stream","API-Key":this.apiKey},this.standardHeaders);this.logDebug("SSE HTTP start request",this.url),this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url);for(let[l,T]of Object.entries(v))this.xhr.setRequestHeader(l,T);this.xhr.timeout=24*60*60*1e3,this.xhr.onerror=()=>{f("XMLHttpRequest error on SSE stream")},this.xhr.onabort=()=>{this.logDebug("SSE aborted"),this.closed||f(null)},this.xhr.ontimeout=()=>{f("SSE timeout")},this.xhr.onload=()=>{if(this.xhr.status>=400&&this.xhr.status<=599){f(`HTTP code ${this.xhr.status}`);return}this.stopFallBackPolling(),s()};let I=0,b=Date.now();this.xhr.onprogress=()=>{b=Date.now();let l=this.xhr.responseText.slice(I);I+=l.length,this.logDebug("SSE GOT: "+l),e(l)};let y=setInterval(()=>{b<Date.now()-le&&(R("SSE read timeout"),this.xhr.abort())},le);this.xhr.send()}close(){this.closed=!0,this.xhr&&this.xhr.abort(),this.stopFallBackPolling()}fallBackToPolling(){!this.fallbackPoller.isPolling()&&this.configurations.pollingEnabled&&(R("Falling back to polling mode while stream recovers"),this.fallbackPoller.start())}stopFallBackPolling(){this.fallbackPoller.isPolling()&&(R("Stopping fallback polling mode"),this.fallbackPoller.stop())}logDebug(e,...n){this.configurations.debug&&console.debug(`[FF-SDK] Streaming: ${e}`,...n)}};function ce(a,e,n,s,c){let f=a in n,v=f?n[a]:e;return f&&s(a,v),c?{value:v,isDefaultValue:!f}:v}var x=class{constructor(e,n,s){this.fetchFlagsFn=e;this.configurations=n;this.pollInterval=s;this.maxAttempts=5}start(){if(this.isPolling()){this.logDebug("Already polling.");return}this.configurations.pollingEnabled&&(this.isRunning=!0,window.setTimeout(()=>this.poll(),this.configurations.pollingInterval))}poll(){this.attemptFetch().finally(()=>{this.timeoutId=window.setTimeout(()=>this.poll(),this.configurations.pollingInterval)})}attemptFetch(){return C(this,null,function*(){for(let e=1;e<=this.maxAttempts;e++){let n=yield this.fetchFlagsFn();if(!n){this.logDebug("Successfully polled for flag updates");return}if(R("Error when polling for flag updates",n),e>=this.maxAttempts){this.logDebug(`Maximum attempts reached for polling for flags. Next poll in ${this.pollInterval}ms.`);return}this.logDebug(`Polling for flags attempt #${e} failed. Remaining attempts: ${this.maxAttempts-e}.`);let s=_(1e3,1e4);yield new Promise(c=>setTimeout(c,s))}})}stop(){this.timeoutId&&(window.clearTimeout(this.timeoutId),this.timeoutId=void 0,this.isRunning=!1)}isPolling(){return this.isRunning}logDebug(e,...n){this.configurations.debug&&console.debug(`[FF-SDK] Poller: ${e}`,...n)}};var ge="1.16.0",fe=`Javascript ${ge} Client`,Ce=500,Oe=globalThis.fetch,J=!!globalThis.Proxy,Y=a=>{let{value:e}=a;try{switch(a.kind.toLowerCase()){case"int":case"number":e=Number(e);break;case"boolean":e=e.toString().toLowerCase()==="true";break;case"json":e=JSON.parse(e);break}}catch(n){R(n)}return e},at=(a,e,n)=>{let s=!1,c,f,v,I,b,y,l=!0,T={},h=W(t=>t),X=0,z=!1,V=()=>{l=!1},N=()=>{l=!0},S=[],d=Ae(),u=D(D({},re),n);u.eventsSyncInterval<6e4&&(u.eventsSyncInterval=6e4),u.pollingInterval<6e4&&(u.pollingInterval=6e4);let m=(t,...i)=>{u.debug&&console.debug(`[FF-SDK] ${t}`,...i)},L=t=>{if(l){let i=Date.now();i-t.lastAccessed>Ce&&(t.count++,t.lastAccessed=i)}};globalThis.onbeforeunload=()=>{S.length&&globalThis.localStorage&&(V(),globalThis.localStorage.HARNESS_FF_METRICS=JSON.stringify(S),N())};let he=(t,i)=>C(void 0,null,function*(){return(yield(yield Oe(`${i.baseUrl}/client/auth`,{method:"POST",headers:{"Content-Type":"application/json","Harness-SDK-Info":fe},body:JSON.stringify({apiKey:t,target:K(D({},e),{identifier:String(e.identifier)})})})).json()).authToken}),G=0,$=()=>{if(S.length){m("Sending metrics...",{metrics:S,evaluations:w});let t={metricsData:S.map(i=>({timestamp:Date.now(),count:i.count,metricsType:"FFMETRICS",attributes:[{key:"featureIdentifier",value:i.featureIdentifier},{key:"featureName",value:i.featureIdentifier},{key:"variationIdentifier",value:i.variationIdentifier},{key:"target",value:e.identifier},{key:"SDK_NAME",value:"JavaScript"},{key:"SDK_LANGUAGE",value:"JavaScript"},{key:"SDK_TYPE",value:"client"},{key:"SDK_VERSION",value:ge}]}))};h(`${u.eventUrl}/metrics/${c}?cluster=${f}`,{method:"POST",headers:D({"Content-Type":"application/json"},T),body:JSON.stringify(t)}).then(()=>{S=[],G=0}).catch(i=>{G++&&(S=[],G=0),m(i),d.emit("metrics error",i)}).finally(()=>{y=window.setTimeout($,u.eventsSyncInterval)})}else y=window.setTimeout($,u.eventsSyncInterval)},w={},ve=t=>{m("Sending event for",t.flag),J?d.emit("changed",new Proxy(t,{get(i,o){var p;if(l&&i.hasOwnProperty(o)&&o==="value"){let E=i.flag,r=t.value,g=S.find(F=>F.featureIdentifier===E&&F.featureValue===r);g?(L(g),g.variationIdentifier=((p=w[E])==null?void 0:p.identifier)||""):S.push({featureIdentifier:E,featureValue:String(r),variationIdentifier:w[E].identifier||"",count:1,lastAccessed:Date.now()}),m("Metrics event: Flag",o,"has been read with value via stream update",r)}return o==="value"?Y(t):t[o]}})):d.emit("changed",{deleted:t.deleted,flag:t.flag,value:Y(t)})},Q=function(){return J?new Proxy({},{get(t,i){var p,E,r;let o=t[i];if(l&&t.hasOwnProperty(i)){let g=t[i],F=S.find(ie=>ie.featureIdentifier===i&&g===ie.featureValue);F?(F.variationIdentifier=((p=w[i])==null?void 0:p.identifier)||"",L(F)):S.push({featureIdentifier:i,featureValue:g,variationIdentifier:((E=w[i])==null?void 0:E.identifier)||"",count:1,lastAccessed:Date.now()}),m("Metrics event: Flag:",i,"has been read with value:",g,"variationIdentifier:",(r=w[i])==null?void 0:r.identifier)}return o}}):{}},A=Q();he(a,u).then(t=>C(void 0,null,function*(){if(s)return;b=t;let i=De(t);if(T={Authorization:`Bearer ${b}`,"Harness-AccountID":i.accountID,"Harness-EnvironmentID":i.environmentIdentifier,"Harness-SDK-Info":fe},m("Authenticated",i),globalThis.localStorage&&globalThis.localStorage.HARNESS_FF_METRICS)try{delete globalThis.localStorage.HARNESS_FF_METRICS,m("Picking up metrics from previous session")}catch(E){}y=window.setTimeout($,u.eventsSyncInterval),c=i.environment,f=i.clusterIdentifier;let o=!!Object.keys(w).length;if((yield k())||m("Fetch all flags ok",A),!s){if(u.streamEnabled?(m("Streaming mode enabled"),pe()):u.pollingEnabled?(m("Polling mode enabled"),Ee()):m("Streaming and polling mode disabled"),!o){V();let E=D({},A);N(),d.emit("ready",E)}z=!0}})).catch(t=>{R("Authentication error: ",t),d.emit("auth error",t),d.emit("error",t)});let k=()=>C(void 0,null,function*(){try{let t=yield h(`${u.baseUrl}/client/env/${c}/target/${e.identifier}/evaluations?cluster=${f}`,{headers:T});if(t.ok){let i=yield t.json();i.forEach(O),d.emit("flags loaded",i)}else R("Features fetch operation error: ",t),d.emit("fetch flags error",t),d.emit("error",t)}catch(t){return R("Features fetch operation error: ",t),d.emit("fetch flags error",t),d.emit("error",t),t}}),Z=t=>C(void 0,null,function*(){try{let i=yield h(`${u.baseUrl}/client/env/${c}/target/${e.identifier}/evaluations/${t}?cluster=${f}`,{headers:T});if(i.ok){let o=yield i.json();O(o)}else R("Feature fetch operation error: ",i),d.emit("fetch flag error",i),d.emit("error",i)}catch(i){R("Feature fetch operation error: ",i),d.emit("fetch flag error",i),d.emit("error",i)}}),O=t=>{V();let i=Y(t);i!==A[t.flag]&&(m("Flag variation has changed for ",t.identifier),A[t.flag]=i,w[t.flag]=K(D({},t),{value:i}),ve(t)),N()};I=new x(k,u,u.pollingInterval);let pe=()=>{let t=r=>{switch(r.event){case"create":o(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):setTimeout(()=>Z(r.identifier),1e3);break;case"patch":o(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):Z(r.identifier);break;case"delete":delete A[r.identifier],d.emit("changed",{flag:r.identifier,value:void 0,deleted:!0}),m("Evaluation deleted",{message:r,storage:A});break}},i=r=>!(!r||!r.flag||!r.identifier||!r.kind||!r.value),o=r=>!(!r||r.length==0||!r.every(g=>i(g))),p=r=>{r.event==="patch"&&(o(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):k())},E=`${u.baseUrl}/stream?cluster=${f}`;v=new H(d,u,E,a,T,I,r=>{r.domain==="flag"?t(r):r.domain==="target-segment"&&p(r)}),v.start()},Ee=()=>{I.start()},B=(t,i)=>d.on(t,i),me=(t,i)=>{t?d.off(t,i):ee()},Re=(t,i)=>{var r;if(!l||J||i===void 0)return;let o=i,p=t,E=S.find(g=>g.featureIdentifier===p&&g.featureValue===o);E?(L(E),E.variationIdentifier=((r=w[p])==null?void 0:r.identifier)||""):S.push({featureIdentifier:p,featureValue:o,count:1,variationIdentifier:w[p].identifier||"",lastAccessed:Date.now()})},ee=()=>{s=!0,m("Closing event stream"),A=Q(),w={},clearTimeout(y),d.all.clear(),typeof(v==null?void 0:v.close)=="function"&&v.close()},te=(t,i=!0)=>{t.length&&U(()=>{let o=!!Object.keys(w).length;if(t.forEach(O),!o){V();let p=D({},A);N(),d.emit("ready",p)}},i)};if(u.cache&&"localStorage"in window){let t=!0,i=M(e.identifier,typeof u.cache=="boolean"?{}:u.cache);i!=null&&i.length&&U(()=>{m("loading from cache",i),te(i,!1),d.emit("cache loaded",i)}),B("flags loaded",o=>{P(e.identifier,o),t=!1}),B("changed",o=>{t||(o.deleted?se(e.identifier,o.flag):oe(e.identifier,o))})}return{on:B,off:me,close:ee,setEvaluations:te,registerAPIRequestMiddleware:t=>{h=W(t)},refreshEvaluations:()=>{z&&!s&&Date.now()-X>=6e4&&(k(),X=Date.now())},variation:(t,i,o=!1)=>ce(t,i,A,Re,o)}};export{q as Event,at as initialize}; | ||
var be=Object.defineProperty,Se=Object.defineProperties;var Ie=Object.getOwnPropertyDescriptors;var ne=Object.getOwnPropertySymbols;var ye=Object.prototype.hasOwnProperty,De=Object.prototype.propertyIsEnumerable;var ae=(a,e,n)=>e in a?be(a,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):a[e]=n,T=(a,e)=>{for(var n in e||(e={}))ye.call(e,n)&&ae(a,n,e[n]);if(ne)for(var n of ne(e))De.call(e,n)&&ae(a,n,e[n]);return a},K=(a,e)=>Se(a,Ie(e));var C=(a,e,n)=>new Promise((s,c)=>{var f=R=>{try{S(n.next(R))}catch(D){c(D)}},v=R=>{try{S(n.throw(R))}catch(D){c(D)}},S=R=>R.done?s(R.value):Promise.resolve(R.value).then(f,v);S((n=n.apply(a,e)).next())});import Te from"jwt-decode";import Ae from"mitt";var q=(h=>(h.READY="ready",h.CONNECTED="connected",h.DISCONNECTED="disconnected",h.FLAGS_LOADED="flags loaded",h.CACHE_LOADED="cache loaded",h.CHANGED="changed",h.ERROR="error",h.ERROR_METRICS="metrics error",h.ERROR_AUTH="auth error",h.ERROR_FETCH_FLAGS="fetch flags error",h.ERROR_FETCH_FLAG="fetch flag error",h.ERROR_STREAM="stream error",h))(q||{});var re={debug:!1,baseUrl:"https://config.ff.harness.io/api/1.0",eventUrl:"https://events.ff.harness.io/api/1.0",eventsSyncInterval:6e4,pollingInterval:6e4,streamEnabled:!0,pollingEnabled:!1,allAttributesPrivate:!1,privateAttributeNames:[],cache:!1},y=(a,...e)=>console.error(`[FF-SDK] ${a}`,...e),U=(a,e=!0)=>{e?setTimeout(a,0):a()},_=(a,e)=>Math.round(Math.random()*(e-a)+a);function j(a){return"HARNESS_FF_CACHE_"+a}function M(a,e={}){let n=j(a),s=parseInt(window.localStorage.getItem(n+".ts"));if(e!=null&&e.ttl&&!isNaN(s)&&s+e.ttl<Date.now())return we(a),[];let c=window.localStorage.getItem(n);if(c)try{return JSON.parse(c)}catch(f){}return[]}function P(a,e){let n=j(a);window.localStorage.setItem(n,JSON.stringify(e)),window.localStorage.setItem(n+".ts",Date.now().toString())}function oe(a,e){let n=M(a),s=n.find(({flag:c})=>c===e.flag);s?Object.assign(s,e):n.push(e),P(a,n)}function se(a,e){let n=M(a),s=n.findIndex(({flag:c})=>c===e);s>-1&&(n.splice(s,1),P(a,n))}function we(a){let e=j(a);window.localStorage.removeItem(e),window.localStorage.removeItem(e+".ts")}function W(a){return function(...n){let[s,c]=a(n);return fetch(s,c)}}var le=3e4,H=class{constructor(e,n,s,c,f,v,S){this.closed=!1;this.eventBus=e,this.configurations=n,this.url=s,this.apiKey=c,this.standardHeaders=f,this.eventCallback=S,this.fallbackPoller=v}start(){let e=l=>{l.toString().split(/\r?\n/).forEach(n)},n=l=>{if(l.startsWith("data:")){let w=JSON.parse(l.substring(5));this.logDebug("Received event from stream: ",w),this.eventCallback(w)}},s=()=>{this.logDebug("Stream connected"),this.eventBus.emit("connected")},c=()=>{clearInterval(D);let l=_(1e3,1e4);this.logDebug("Stream disconnected, will reconnect in "+l+"ms"),this.eventBus.emit("disconnected"),setTimeout(()=>this.start(),l)},f=l=>{l&&y("Stream has issue",l),this.fallBackToPolling(),this.eventBus.emit("stream error",l),this.eventBus.emit("error",l),c()},v=T({"Cache-Control":"no-cache",Accept:"text/event-stream","API-Key":this.apiKey},this.standardHeaders);this.logDebug("SSE HTTP start request",this.url),this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url);for(let[l,w]of Object.entries(v))this.xhr.setRequestHeader(l,w);this.xhr.timeout=24*60*60*1e3,this.xhr.onerror=()=>{f("XMLHttpRequest error on SSE stream")},this.xhr.onabort=()=>{this.logDebug("SSE aborted"),this.closed||f(null)},this.xhr.ontimeout=()=>{f("SSE timeout")},this.xhr.onload=()=>{if(this.xhr.status>=400&&this.xhr.status<=599){f(`HTTP code ${this.xhr.status}`);return}s()};let S=0,R=Date.now();this.xhr.onprogress=()=>{this.stopFallBackPolling(),R=Date.now();let l=this.xhr.responseText.slice(S);S+=l.length,this.logDebug("SSE GOT: "+l),e(l)};let D=setInterval(()=>{R<Date.now()-le&&(y("SSE read timeout"),this.xhr.abort())},le);this.xhr.send()}close(){this.closed=!0,this.xhr&&this.xhr.abort(),this.stopFallBackPolling()}fallBackToPolling(){!this.fallbackPoller.isPolling()&&this.configurations.pollingEnabled&&(this.logDebug("Falling back to polling mode while stream recovers"),this.fallbackPoller.start())}stopFallBackPolling(){this.fallbackPoller.isPolling()&&(this.logDebug("Stopping fallback polling mode"),this.fallbackPoller.stop())}logDebug(e,...n){this.configurations.debug&&console.debug(`[FF-SDK] Streaming: ${e}`,...n)}};function ce(a,e,n,s,c){let f=a in n,v=f?n[a]:e;return f&&s(a,v),c?{value:v,isDefaultValue:!f}:v}var x=class{constructor(e,n){this.fetchFlagsFn=e;this.configurations=n;this.maxAttempts=5}start(){if(this.isPolling()){this.logDebug("Already polling.");return}this.isRunning=!0,setTimeout(()=>this.poll(),this.configurations.pollingInterval)}poll(){this.attemptFetch().finally(()=>{this.timeoutId=setTimeout(()=>this.poll(),this.configurations.pollingInterval)})}attemptFetch(){return C(this,null,function*(){for(let e=1;e<=this.maxAttempts;e++){let n=yield this.fetchFlagsFn();if(!n){this.logDebug("Successfully polled for flag updates");return}if(y("Error when polling for flag updates",n),e>=this.maxAttempts){this.logDebug(`Maximum attempts reached for polling for flags. Next poll in ${this.configurations.pollingInterval}ms.`);return}this.logDebug(`Polling for flags attempt #${e} failed. Remaining attempts: ${this.maxAttempts-e}.`);let s=_(1e3,1e4);yield new Promise(c=>setTimeout(c,s))}})}stop(){this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=void 0,this.isRunning=!1)}isPolling(){return this.isRunning}logDebug(e,...n){this.configurations.debug&&console.debug(`[FF-SDK] Poller: ${e}`,...n)}};var ge="1.16.0",fe=`Javascript ${ge} Client`,Ce=500,Oe=globalThis.fetch,J=!!globalThis.Proxy,Y=a=>{let{value:e}=a;try{switch(a.kind.toLowerCase()){case"int":case"number":e=Number(e);break;case"boolean":e=e.toString().toLowerCase()==="true";break;case"json":e=JSON.parse(e);break}}catch(n){y(n)}return e},at=(a,e,n)=>{let s=!1,c,f,v,S,R,D,l=!0,w={},h=W(t=>t),X=0,z=!1,V=()=>{l=!1},N=()=>{l=!0},b=[],d=Ae(),u=T(T({},re),n);u.eventsSyncInterval<6e4&&(u.eventsSyncInterval=6e4),u.pollingInterval<6e4&&(u.pollingInterval=6e4);let m=(t,...i)=>{u.debug&&console.debug(`[FF-SDK] ${t}`,...i)},L=t=>{if(l){let i=Date.now();i-t.lastAccessed>Ce&&(t.count++,t.lastAccessed=i)}};globalThis.onbeforeunload=()=>{b.length&&globalThis.localStorage&&(V(),globalThis.localStorage.HARNESS_FF_METRICS=JSON.stringify(b),N())};let he=(t,i)=>C(void 0,null,function*(){return(yield(yield Oe(`${i.baseUrl}/client/auth`,{method:"POST",headers:{"Content-Type":"application/json","Harness-SDK-Info":fe},body:JSON.stringify({apiKey:t,target:K(T({},e),{identifier:String(e.identifier)})})})).json()).authToken}),G=0,$=()=>{if(b.length){m("Sending metrics...",{metrics:b,evaluations:I});let t={metricsData:b.map(i=>({timestamp:Date.now(),count:i.count,metricsType:"FFMETRICS",attributes:[{key:"featureIdentifier",value:i.featureIdentifier},{key:"featureName",value:i.featureIdentifier},{key:"variationIdentifier",value:i.variationIdentifier},{key:"target",value:e.identifier},{key:"SDK_NAME",value:"JavaScript"},{key:"SDK_LANGUAGE",value:"JavaScript"},{key:"SDK_TYPE",value:"client"},{key:"SDK_VERSION",value:ge}]}))};h(`${u.eventUrl}/metrics/${c}?cluster=${f}`,{method:"POST",headers:T({"Content-Type":"application/json"},w),body:JSON.stringify(t)}).then(()=>{b=[],G=0}).catch(i=>{G++&&(b=[],G=0),m(i),d.emit("metrics error",i)}).finally(()=>{D=window.setTimeout($,u.eventsSyncInterval)})}else D=window.setTimeout($,u.eventsSyncInterval)},I={},ve=t=>{m("Sending event for",t.flag),J?d.emit("changed",new Proxy(t,{get(i,o){var p;if(l&&i.hasOwnProperty(o)&&o==="value"){let E=i.flag,r=t.value,g=b.find(F=>F.featureIdentifier===E&&F.featureValue===r);g?(L(g),g.variationIdentifier=((p=I[E])==null?void 0:p.identifier)||""):b.push({featureIdentifier:E,featureValue:String(r),variationIdentifier:I[E].identifier||"",count:1,lastAccessed:Date.now()}),m("Metrics event: Flag",o,"has been read with value via stream update",r)}return o==="value"?Y(t):t[o]}})):d.emit("changed",{deleted:t.deleted,flag:t.flag,value:Y(t)})},Q=function(){return J?new Proxy({},{get(t,i){var p,E,r;let o=t[i];if(l&&t.hasOwnProperty(i)){let g=t[i],F=b.find(ie=>ie.featureIdentifier===i&&g===ie.featureValue);F?(F.variationIdentifier=((p=I[i])==null?void 0:p.identifier)||"",L(F)):b.push({featureIdentifier:i,featureValue:g,variationIdentifier:((E=I[i])==null?void 0:E.identifier)||"",count:1,lastAccessed:Date.now()}),m("Metrics event: Flag:",i,"has been read with value:",g,"variationIdentifier:",(r=I[i])==null?void 0:r.identifier)}return o}}):{}},A=Q();he(a,u).then(t=>C(void 0,null,function*(){if(s)return;R=t;let i=Te(t);if(w={Authorization:`Bearer ${R}`,"Harness-AccountID":i.accountID,"Harness-EnvironmentID":i.environmentIdentifier,"Harness-SDK-Info":fe},m("Authenticated",i),globalThis.localStorage&&globalThis.localStorage.HARNESS_FF_METRICS)try{delete globalThis.localStorage.HARNESS_FF_METRICS,m("Picking up metrics from previous session")}catch(E){}D=window.setTimeout($,u.eventsSyncInterval),c=i.environment,f=i.clusterIdentifier;let o=!!Object.keys(I).length;if((yield k())||m("Fetch all flags ok",A),!s){if(u.streamEnabled?(m("Streaming mode enabled"),pe()):u.pollingEnabled?(m("Polling mode enabled"),Ee()):m("Streaming and polling mode disabled"),!o){V();let E=T({},A);N(),d.emit("ready",E)}z=!0}})).catch(t=>{y("Authentication error: ",t),d.emit("auth error",t),d.emit("error",t)});let k=()=>C(void 0,null,function*(){try{let t=yield h(`${u.baseUrl}/client/env/${c}/target/${e.identifier}/evaluations?cluster=${f}`,{headers:w});if(t.ok){let i=yield t.json();i.forEach(O),d.emit("flags loaded",i)}else y("Features fetch operation error: ",t),d.emit("fetch flags error",t),d.emit("error",t)}catch(t){return y("Features fetch operation error: ",t),d.emit("fetch flags error",t),d.emit("error",t),t}}),Z=t=>C(void 0,null,function*(){try{let i=yield h(`${u.baseUrl}/client/env/${c}/target/${e.identifier}/evaluations/${t}?cluster=${f}`,{headers:w});if(i.ok){let o=yield i.json();O(o)}else y("Feature fetch operation error: ",i),d.emit("fetch flag error",i),d.emit("error",i)}catch(i){y("Feature fetch operation error: ",i),d.emit("fetch flag error",i),d.emit("error",i)}}),O=t=>{V();let i=Y(t);i!==A[t.flag]&&(m("Flag variation has changed for ",t.identifier),A[t.flag]=i,I[t.flag]=K(T({},t),{value:i}),ve(t)),N()};S=new x(k,u);let pe=()=>{let t=r=>{switch(r.event){case"create":o(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):setTimeout(()=>Z(r.identifier),1e3);break;case"patch":o(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):Z(r.identifier);break;case"delete":delete A[r.identifier],d.emit("changed",{flag:r.identifier,value:void 0,deleted:!0}),m("Evaluation deleted",{message:r,storage:A});break}},i=r=>!(!r||!r.flag||!r.identifier||!r.kind||!r.value),o=r=>!(!r||r.length==0||!r.every(g=>i(g))),p=r=>{r.event==="patch"&&(o(r.evaluations)?r.evaluations.forEach(g=>{O(g)}):k())},E=`${u.baseUrl}/stream?cluster=${f}`;v=new H(d,u,E,a,w,S,r=>{r.domain==="flag"?t(r):r.domain==="target-segment"&&p(r)}),v.start()},Ee=()=>{S.start()},B=(t,i)=>d.on(t,i),me=(t,i)=>{t?d.off(t,i):ee()},Re=(t,i)=>{var r;if(!l||J||i===void 0)return;let o=i,p=t,E=b.find(g=>g.featureIdentifier===p&&g.featureValue===o);E?(L(E),E.variationIdentifier=((r=I[p])==null?void 0:r.identifier)||""):b.push({featureIdentifier:p,featureValue:o,count:1,variationIdentifier:I[p].identifier||"",lastAccessed:Date.now()})},ee=()=>{s=!0,m("Closing event stream"),A=Q(),I={},clearTimeout(D),d.all.clear(),typeof(v==null?void 0:v.close)=="function"&&v.close()},te=(t,i=!0)=>{t.length&&U(()=>{let o=!!Object.keys(I).length;if(t.forEach(O),!o){V();let p=T({},A);N(),d.emit("ready",p)}},i)};if(u.cache&&"localStorage"in window){let t=!0,i=M(e.identifier,typeof u.cache=="boolean"?{}:u.cache);i!=null&&i.length&&U(()=>{m("loading from cache",i),te(i,!1),d.emit("cache loaded",i)}),B("flags loaded",o=>{P(e.identifier,o),t=!1}),B("changed",o=>{t||(o.deleted?se(e.identifier,o.flag):oe(e.identifier,o))})}return{on:B,off:me,close:ee,setEvaluations:te,registerAPIRequestMiddleware:t=>{h=W(t)},refreshEvaluations:()=>{z&&!s&&Date.now()-X>=6e4&&(k(),X=Date.now())},variation:(t,i,o=!1)=>ce(t,i,A,Re,o)}};export{q as Event,at as initialize}; |
{ | ||
"name": "@harnessio/ff-javascript-client-sdk", | ||
"version": "1.17.0-rc.3", | ||
"version": "1.17.0-rc.4", | ||
"author": "Harness", | ||
@@ -34,2 +34,3 @@ "license": "Apache-2.0", | ||
"ts-jest": "^29.1.1", | ||
"tslib": "^2.6.2", | ||
"typescript": "^5.2.2" | ||
@@ -44,4 +45,3 @@ }, | ||
"jwt-decode": "^3.1.2", | ||
"mitt": "^2.1.0", | ||
"tslib": "^2.6.2" | ||
"mitt": "^2.1.0" | ||
}, | ||
@@ -48,0 +48,0 @@ "keywords": [ |
@@ -56,2 +56,3 @@ # Before you Begin | ||
pollingInterval?: number | ||
pollingEnabled?: boolean | ||
streamEnabled?: boolean | ||
@@ -79,13 +80,18 @@ allAttributesPrivate?: boolean | ||
By default, Harness Feature Flags SDK has streaming enabled and polling disabled. Both modes can be toggled according to your preference using the SDK's configurations. | ||
By default, Harness Feature Flags SDK has streaming enabled and polling enabled. Both modes can be toggled according to your preference using the SDK's configuration. | ||
### Streaming Mode | ||
Streaming mode establishes a continuous connection between your application and Harness' servers. This allows for real-time updates on feature flags without requiring periodic checks. If an error occurs while streaming and `pollingEnabled` is set to `true`, the SDK will automatically fall back to polling mode until streaming can be reestablished. If `pollingEnabled` is `false`, streaming will attempt to reconnect without falling back to polling. | ||
Streaming mode establishes a continuous connection between your application and the Feature Flags service. | ||
This allows for real-time updates on feature flags without requiring periodic checks. | ||
If an error occurs while streaming and `pollingEnabled` is set to `true`, | ||
the SDK will automatically fall back to polling mode until streaming can be reestablished. | ||
If `pollingEnabled` is `false`, streaming will attempt to reconnect without falling back to polling. | ||
### Polling Mode | ||
In polling mode, the SDK will periodically check with the Harness servers to retrieve updates for feature flags. The frequency of these checks can be adjusted using the SDK's configurations. | ||
In polling mode, the SDK will periodically check with the Feature Flags service to retrieve updates for feature flags. The frequency of these checks can be adjusted using the SDK's configurations. | ||
### No Streaming or Polling | ||
If both streaming and polling modes are disabled (`streamEnabled: false` and `pollingEnabled: false`), | ||
the SDK will not automatically fetch feature flag updates after the initial fetch. This means that after the initial load, any changes made to the feature flags on the Harness server will not be reflected in the application until the SDK is re-initialized or one of the modes is re-enabled. | ||
the SDK will not automatically fetch feature flag updates after the initial fetch. | ||
This means that after the initial load, any changes made to the feature flags on the Harness server will not be reflected in the application until the SDK is re-initialized or one of the modes is re-enabled. | ||
@@ -95,8 +101,2 @@ This configuration might be useful in specific scenarios where you want to ensure a consistent set of feature flags | ||
To use the SDK with both modes disabled: | ||
### Configurations | ||
While both streaming and polling can be enabled, if both are active, streaming takes precedence. | ||
If streaming encounters an issue and `pollingEnabled` is set to `true`, the SDK will switch to polling mode as a backup until streaming is recovered. If `pollingEnabled` is set to `false`, the SDK will continue attempting to reconnect via streaming. | ||
To configure the modes: | ||
@@ -108,16 +108,15 @@ | ||
streamEnabled: true, // Enable or disable streaming - default is enabled | ||
pollingEnabled: false, // Enable or disable polling - default is disabled. Enable to fallback to polling if streaming is enabled and encounters an issue. | ||
pollingEnabled: true, // Enable or disable polling - default is enabled if stream is enabled. | ||
} | ||
const client = initialize( | ||
'YOUR_SDK_KEY', | ||
{ | ||
identifier: 'Harness1', | ||
attributes: { | ||
lastUpdated: Date(), | ||
host: location.href | ||
} | ||
}, | ||
options, | ||
'YOUR_SDK_KEY', | ||
{ | ||
identifier: 'Harness1', | ||
attributes: { | ||
lastUpdated: Date(), | ||
host: location.href | ||
} | ||
}, | ||
options | ||
) | ||
@@ -124,0 +123,0 @@ ``` |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
2
82204
10
352
313
- Removedtslib@^2.6.2
- Removedtslib@2.8.1(transitive)