@configdirector/nextjs-sdk 1.9.2 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/client/index.cjs +1 -1
  2. package/dist/client/index.d.cts +21 -8
  3. package/dist/client/index.d.cts.map +1 -1
  4. package/dist/client/index.d.mts +21 -8
  5. package/dist/client/index.d.mts.map +1 -1
  6. package/dist/client/index.mjs +1 -1
  7. package/dist/client/index.mjs.map +1 -1
  8. package/dist/client/installedTestClient-BhHUzJ9D.cjs +6 -0
  9. package/dist/client/installedTestClient-BwTUOOhP.mjs +7 -0
  10. package/dist/client/installedTestClient-BwTUOOhP.mjs.map +1 -0
  11. package/dist/client/testing.cjs +1 -1
  12. package/dist/client/testing.d.cts +7 -15
  13. package/dist/client/testing.d.cts.map +1 -1
  14. package/dist/client/testing.d.mts +7 -15
  15. package/dist/client/testing.d.mts.map +1 -1
  16. package/dist/client/testing.mjs +1 -1
  17. package/dist/client/testing.mjs.map +1 -1
  18. package/dist/client/{types-fL7X5zwg.d.cts → types-2Z0rA7lF.d.cts} +57 -16
  19. package/dist/client/types-2Z0rA7lF.d.cts.map +1 -0
  20. package/dist/client/{types-DA2VZKNX.d.mts → types-6a1uEkD0.d.mts} +57 -16
  21. package/dist/client/types-6a1uEkD0.d.mts.map +1 -0
  22. package/dist/server/DefaultConfigDirectorClient-BplPvnEk.mjs +6 -0
  23. package/dist/server/DefaultConfigDirectorClient-BplPvnEk.mjs.map +1 -0
  24. package/dist/server/DefaultConfigDirectorClient-oT53aH0F.cjs +5 -0
  25. package/dist/server/{types-DnzM2ukj.d.cts → errors-EfmnEmll.d.cts} +130 -47
  26. package/dist/server/errors-EfmnEmll.d.cts.map +1 -0
  27. package/dist/server/{types-qIeNbtNf.d.mts → errors-r1MHQ8L5.d.mts} +130 -47
  28. package/dist/server/errors-r1MHQ8L5.d.mts.map +1 -0
  29. package/dist/server/index.cjs +1 -1
  30. package/dist/server/index.d.cts +44 -9
  31. package/dist/server/index.d.cts.map +1 -1
  32. package/dist/server/index.d.mts +44 -9
  33. package/dist/server/index.d.mts.map +1 -1
  34. package/dist/server/index.mjs +1 -1
  35. package/dist/server/index.mjs.map +1 -1
  36. package/dist/server/native-values-CfqV9hAq.mjs +2 -0
  37. package/dist/server/native-values-CfqV9hAq.mjs.map +1 -0
  38. package/dist/server/native-values-UCK4hh1Z.cjs +1 -0
  39. package/dist/server/testing.cjs +1 -1
  40. package/dist/server/testing.d.cts +8 -26
  41. package/dist/server/testing.d.cts.map +1 -1
  42. package/dist/server/testing.d.mts +8 -26
  43. package/dist/server/testing.d.mts.map +1 -1
  44. package/dist/server/testing.mjs +1 -1
  45. package/dist/server/testing.mjs.map +1 -1
  46. package/package.json +1 -1
  47. package/dist/client/installedTestClient-CDdDsfVQ.mjs +0 -7
  48. package/dist/client/installedTestClient-CDdDsfVQ.mjs.map +0 -1
  49. package/dist/client/installedTestClient-DH7rRR-J.cjs +0 -6
  50. package/dist/client/types-DA2VZKNX.d.mts.map +0 -1
  51. package/dist/client/types-fL7X5zwg.d.cts.map +0 -1
  52. package/dist/server/DefaultConfigDirectorClient-BZwAj0iJ.cjs +0 -5
  53. package/dist/server/DefaultConfigDirectorClient-DyFVzSHP.mjs +0 -6
  54. package/dist/server/DefaultConfigDirectorClient-DyFVzSHP.mjs.map +0 -1
  55. package/dist/server/errors-BGpFuqOO.mjs +0 -2
  56. package/dist/server/errors-BGpFuqOO.mjs.map +0 -1
  57. package/dist/server/errors-CCbuIqT8.cjs +0 -1
  58. package/dist/server/types-DnzM2ukj.d.cts.map +0 -1
  59. package/dist/server/types-qIeNbtNf.d.mts.map +0 -1
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./installedTestClient-DH7rRR-J.cjs`);let l=require(`react`);l=s(l);let u=require(`react/jsx-runtime`);const d=e=>{if(e.type===`json`||e.type==null&&typeof e.value==`object`){if(e.valueId)return{valueId:e.valueId,type:`json`};try{return{value:JSON.stringify(e.value),type:`json`}}catch{return{value:e.value.toString(),type:`json`}}}let t=e.value?.toString();return t&&t.length<=500?{value:t}:e.valueId?{valueId:e.valueId}:{value:t}};var f=class{constructor(e){this.turnedOff=!1,this.pendingEvaluations=[],this.logger=e.logger,this.workerCloseTimeout=e.workerCloseTimeout??6e3,this.pendingEvaluationLimit=e.evaluationQueueLimit??1e3,this.initializeMessage={type:`Initialize`,payload:{sdkKey:e.sdkKey,sdkIdentity:e.sdkIdentity,metaContext:e.metaContext,baseUrl:e.baseUrl.toString(),evaluationQueueLimit:this.pendingEvaluationLimit,initialFlushIntervalDelay:e.initialFlushIntervalDelay??5e3,flushIntervalDelay:e.flushIntervalDelay??3e4}},this.visibilityHandler=()=>{document.visibilityState===`hidden`&&this.flush()}}createWorkerOrTurnOff(){if(typeof Worker>`u`){this.turnOff(`[WebWorkerTelemetryClient] Telemetry is off because Web Workers are not available in this environment.`);return}try{return new Worker(URL.createObjectURL(new Blob(["(function(){let e=async(e,t)=>e.valueId?{valueId:e.valueId}:e.value?e.value.length<=500&&e.type!=`json`?{value:e.value}:{valueId:await t(e.value)}:e,t=e=>{let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]?.length??0)>0)return!1;return!0},n=e=>{if(!e)return!0;let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]??0)>0)return!1;return!0},r=async(e,t,n,r)=>{let i=new AbortController,a=setTimeout(()=>{r.debug(`[fetchWithTimeout] Reached timeout, aborting request`),i.abort()},e);try{let e=await fetch(typeof t==`string`||t instanceof Request?t:t.toString(),{...n,signal:i.signal});return clearTimeout(a),e}catch(e){throw r.warn(`[fetchWithTimeout] Fetch error: `,e),clearTimeout(a),e}},i=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var a=class{constructor(e){this.executeRequests=!0,this.sdkKey=e.sdkKey,this.logger=e.logger,this.sdkIdentity=e.sdkIdentity,this.metaContext=e.metaContext,this.url=e.urlFactory(`client/telemetry/v1`,e.baseUrl)}async report({context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r}){if(!this.executeRequests)return{success:!1,fatalError:!0};let i={clientSdkKey:this.sdkKey,metaContext:{sdkName:this.sdkIdentity.sdkName,sdkVersion:this.sdkIdentity.sdkVersion,appName:this.metaContext.appName,appVersion:this.metaContext.appVersion},context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r};if(this.isReportEmpty(i))return{success:!0,fatalError:!1};let a=await this.sendReport(i);return a.fatalError&&(this.executeRequests=!1),a}isReportEmpty(e){return t(e.discreteEvents)&&t(e.aggregatedEvents)&&n(e.droppedEvents)}async sendReport(e){try{let t=await r(5e3,this.url,{method:`POST`,body:JSON.stringify(e),keepalive:!0},this.logger),n=this.isStatusFatal(t.status);return n&&this.logger.warn(`[EventReporter] Received a fatal status response (${t.status}) from the telemetry endpoint. No more telemetry data will be sent.`),{success:t.ok,fatalError:n}}catch(e){let t=i(e);return this.logger.warn(`[EventReporter] Error attempting to send telemetry data: ${e}`,{error:e}),{success:!1,fatalError:t}}}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}},o=class{aggregate(e){if(e.events.length==0)return[];let t=new Map;for(let n of e.events){let e=JSON.stringify(n),r=t.get(e)?.count||0;t.set(e,{event:n,count:r+1})}return Array.from(t).map(([,t])=>({startTime:e.startTime,endTime:e.endTime,count:t.count,event:t.event}))}},s=class{constructor(e){this._events=[],this._droppedEventCount=0,this.limit=e??1e3}get events(){return this._events}get reachedLimit(){return this._events.length>=this.limit}get droppedEventCount(){return this._droppedEventCount}push(...e){this.startTime||=new Date;let t=Math.max(0,e.length-this.limit),n=e.slice(t,e.length);if(this._droppedEventCount+=t,this._events.length+n.length>this.limit){let e=this._events.length+n.length-this.limit;this._events.splice(0,e),this._droppedEventCount+=e}return this._events.push(...n)}takeSnapshot(){let e=new Date,t=this.startTime??e,n=this._events.splice(0),r=this._droppedEventCount;return this.startTime=void 0,this._droppedEventCount=0,{startTime:t,endTime:e,events:n,droppedCount:r}}clear(){this._events=[],this.startTime=void 0,this._droppedEventCount=0}},c=class{constructor(e){this.aggregator=new o,this.collectEvents=!0,this.started=!1,this.logger=e.logger,this.evaluationEventQueue=new s(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4,this.initialFlushIntervalDelay=e.initialFlushIntervalDelay??5e3}start(){this.started||!this.collectEvents||(this.started=!0,this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.initialFlushIntervalDelay))}async flushAndScheduleNext(){if(!this.collectEvents)return;let e;try{e=await this.flush()}catch(t){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events: `,t),e={success:!1,fatalError:!1}}e.fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.collectEvents&&(this.cancelScheduledFlush(),this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay))}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout);try{await this.flush()}catch(e){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events during close: `,e)}this.evaluationEventQueue.clear()}dispose(){this.close()}},l=class{constructor(e){this.valueIdGenerator=e,this.valueIdGenerator=e}async process(t){let n=await Promise.all(t.events.map(async t=>({...t,defaultValue:await e(t.defaultValue,this.valueIdGenerator),evaluatedValue:await e(t.evaluatedValue,this.valueIdGenerator)})));return{...t,events:n}}},u=class extends c{constructor(e){super(e),this.reporter=new a(e),this.evaluationEventSnapshotPreprocessor=new l(e.valueIdGenerator)}async updateContext(e){this.cancelScheduledFlush(),await this.flush(),this._context=e,await this.flushAndScheduleNext()}evaluatedConfig(e){this.collectEvents&&this.evaluationEventQueue.push(e)}async forceFlush(){this.cancelScheduledFlush(),await this.flushAndScheduleNext()}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e)},droppedEvents:{evaluatedConfig:e.droppedCount}})}};let d=(e,t)=>new URL(e,t?.toString()),f=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},p=Math.ceil(128/Math.log2(62)),m=new TextEncoder,h=async e=>{if(typeof crypto>`u`||crypto.subtle==null)return;let t=await crypto.subtle.digest(`SHA-256`,m.encode(e?.toString()??``));return f(new Uint8Array(t,0,16),p)},g,_=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),v=e=>{try{self.postMessage(e)}catch{self.postMessage(_(e.payload.level,e.payload.message))}},y={debug:function(e,...t){v(_(`debug`,e,t))},info:function(e,...t){v(_(`info`,e,t))},warn:function(e,...t){v(_(`warn`,e,t))},error:function(e,...t){v(_(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!g){y.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(y.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:if(g){y.warn(`[TelemetryWorker] Received a duplicate Initialize event, ignoring it`);break}g=new u({...t.payload,baseUrl:d(t.payload.baseUrl),urlFactory:d,valueIdGenerator:h,logger:y}),g.start();break;case`EvaluatedConfigEvent`:g?.evaluatedConfig(t.payload);break;case`UpdateContext`:g?.updateContext(t.payload.context);break;case`Flush`:g?.forceFlush();break;case`Close`:(g?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"],{type:`application/javascript`})))}catch(e){this.turnOff(`[WebWorkerTelemetryClient] Telemetry is off because the telemetry Web Worker could not be created: `,e);return}}turnOff(e,...t){this.turnedOff=!0,this.pendingEvaluations.length=0,this.logger.warn(e,...t)}startWorker(){if(this.worker||this.turnedOff)return this.worker;let e=this.createWorkerOrTurnOff();if(e){e.onmessage=e=>{this.handleWorkerEvent(e.data)},e.postMessage(this.initializeMessage),this.worker=e;try{document.addEventListener(`visibilitychange`,this.visibilityHandler)}catch(e){this.logger.warn(`[TelemetryEventCollector] Could not configure 'visibilitychange' listener: `,e)}for(let t of this.pendingEvaluations)e.postMessage(t);return this.pendingEvaluations.length=0,e}}async updateContext(e){if(this.closePromise)return;let t={type:`UpdateContext`,payload:{context:e}};this.startWorker()?.postMessage(t)}evaluatedConfig(e){if(this.turnedOff)return;let t={type:`EvaluatedConfigEvent`,payload:this.sanitizeEvaluatedConfigEvent(e)};if(this.worker){this.worker.postMessage(t);return}this.pendingEvaluations.length>=this.pendingEvaluationLimit&&this.pendingEvaluations.shift(),this.pendingEvaluations.push(t)}sanitizeEvaluatedConfigEvent(e){return{...e,defaultValue:d({value:e.defaultValue,type:e.type}),evaluatedValue:d({value:e.evaluatedValue,valueId:e.evaluatedValueId,type:e.type})}}handleWorkerEvent(e){if(e.type===`Closed`){this.finishClose();return}if(!e.payload?.level||!e.payload?.message)return;let{level:t,message:n,args:r}=e.payload;switch(t){case`debug`:this.logger.debug(n,...r);break;case`info`:this.logger.info(n,...r);break;case`warn`:this.logger.warn(n,...r);break;case`error`:this.logger.error(n,...r);break}}flush(){this.worker?.postMessage({type:`Flush`})}close(){return this.closePromise?this.closePromise:this.performClose()}performClose(){let e=this.worker;if(!e)return this.pendingEvaluations.length=0,this.closePromise=Promise.resolve(),this.closePromise;try{document.removeEventListener(`visibilitychange`,this.visibilityHandler)}catch(e){this.logger.warn(`[WebWorkerTelemetryClient] Could not remove 'visibilitychange' listener: `,e)}return this.closePromise=new Promise(t=>{this.closeResolve=t,this.closeTimer=setTimeout(()=>{this.logger.warn(`[WebWorkerTelemetryClient] Timed out waiting for the telemetry worker to close. Terminating the worker.`),this.finishClose()},this.workerCloseTimeout),e.postMessage({type:`Close`})}),this.closePromise}finishClose(){clearTimeout(this.closeTimer),this.closeTimer=void 0,this.worker?.terminate(),this.closeResolve?.()}};const p=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},m=Math.ceil(128/Math.log2(62)),h=new TextEncoder,g=async e=>{if(typeof crypto>`u`||crypto.subtle==null)return;let t=await crypto.subtle.digest(`SHA-256`,h.encode(e?.toString()??``));return p(new Uint8Array(t,0,16),m)},_=(e,t,n)=>{let r=n?.logger??c.s(),i=c.o(n?.connection?.url)??`https://client-sdk-api.configdirector.com`;return new c.r(new f({sdkKey:e,sdkIdentity:{sdkName:t.sdkName,sdkVersion:t.sdkVersion},metaContext:{appName:n?.metadata?.appName,appVersion:n?.metadata?.appVersion},logger:r,baseUrl:i,urlFactory:c.a,valueIdGenerator:g}),e,t,{...n,logger:r})};var v=class{constructor(e){this.client=e,this.registrations=[]}on(e,t){this.client.on(e,t),this.registrations.push({event:e,handler:t})}registerHooks(e){for(let[t,n]of Object.entries(e??{})){let e=Array.isArray(n)?n:[n];for(let n of e)typeof n==`function`&&this.on(t,n)}}removeAll(){for(let{event:e,handler:t}of this.registrations)this.client.off(e,t);this.registrations=[]}};const y=(e,t)=>{if(Object.is(e,t))return!0;if(typeof e!=`object`||typeof t!=`object`||e===null||t===null||Object.getPrototypeOf(e)!==Object.getPrototypeOf(t))return!1;if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>y(e,t[n]));if(!b(e)||!b(t))return!1;let n=Object.keys(e),r=Object.keys(t);return n.length===r.length&&n.every(n=>Object.prototype.hasOwnProperty.call(t,n)&&y(e[n],t[n]))},b=e=>{let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},x=(e,t)=>e.isInitializing?`none`:e.isReady?t!==void 0&&!y(t,e.context)?`updateContext`:`none`:`initialize`,S=l.default.createContext({status:`loading`});var C=class{decorateMessage(e){return`[ConfigDirector:nextjs-sdk] ${e}`}};const w=e=>c.s(e,new C),T=e=>`client`in e&&e.client!==void 0;var E=class extends l.Component{constructor(e){super(e);let t=T(e)?e.client:c.n();this.ownsClient=t===void 0,this.client=t,this.state=t?{client:t,status:t.isReady?`ready`:`loading`}:{status:`loading`}}buildClient(){let e=this.props;return _(e.sdkKey,{sdkName:`nextjs-sdk`,sdkVersion:`1.9.2`},{connection:{url:e.url,timeout:e.timeout,mode:e.mode,pollingInterval:e.pollingInterval},metadata:{appName:e.appName,appVersion:e.appVersion},logger:w(e.logLevel??`warn`),hooks:e.hooks})}async componentDidMount(){let e=this.client;this.ownsClient&&(e=this.buildClient(),this.client=e,this.setState({client:e})),e&&(this.handlers=new v(e),this.handlers.on(`configsUpdated`,()=>{this.setState({updatedAt:new Date})}),this.handlers.on(`clientReady`,()=>{this.setState({status:`ready`})}),this.ownsClient||this.handlers.registerHooks(this.props.hooks),await this.connect(e,this.props.context))}async connect(e,t){switch(x(e,t)){case`initialize`:await e.initialize(t);break;case`updateContext`:this.setState({status:`loading`}),await e.updateContext(t);break;case`none`:return}this.client===e&&!e.isReady&&this.setState({status:`default`})}async componentDidUpdate(e){if(T(e)&&T(this.props)&&e.client!==this.props.client&&w(`warn`).warn(`The client prop of ConfigDirectorProvider changed after it mounted and is ignored. Remount the provider, for example with a new key, to use another client.`),!y(e.context,this.props.context)){let e=this.client;if(!e)return;this.setState({status:`loading`}),await e.updateContext(this.props.context??{}),this.client===e&&!e.isReady&&this.setState({status:`default`})}}componentWillUnmount(){this.handlers?.removeAll(),this.handlers=void 0,this.ownsClient&&this.client?.dispose(),this.client=void 0}render(){return(0,u.jsx)(S.Provider,{value:{...this.state,initialConfigs:this.props.initialConfigs},children:this.props.children})}},D=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorNextContextError`,Object.setPrototypeOf(this,e.prototype)}};const O=()=>new D(`The ConfigDirector client was not found in the React context. Make sure the component using this hook is inside a <ConfigDirectorProvider>.`),k=(e,t)=>{let n=(0,l.useContext)(S);if(!n)throw O();let r=n.initialConfigs?.[e];return{value:n.client?.isReady?n.client.getValue(e,t):r?c.c(r,t).parsedValue:t,readyStatus:n.status,loading:n.status===`loading`}},A=()=>{let e=(0,l.useContext)(S);if(!e)throw O();return{updateContext:async t=>{await e.client?.updateContext(t)}}},j=()=>{let e=(0,l.useContext)(S);if(!e?.client)throw O();return{client:e.client}},M=()=>{let e=(0,l.useContext)(S);if(!e)throw O();return{readyStatus:e.status,loading:e.status===`loading`}};exports.ConfigDirectorNextContextError=D,exports.ConfigDirectorProvider=E,exports.createConsoleLogger=w,exports.useClient=j,exports.useConfigDirectorStatus=M,exports.useConfigValue=k,exports.useContext=A;
2
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./installedTestClient-BhHUzJ9D.cjs`);let l=require(`react`);l=s(l);let u=require(`react/jsx-runtime`);const d=e=>{if(e.type===`json`||e.type==null&&typeof e.value==`object`){if(e.valueId)return{valueId:e.valueId,type:`json`};try{return{value:JSON.stringify(e.value),type:`json`}}catch{return{value:e.value.toString(),type:`json`}}}let t=e.value?.toString();return t&&t.length<=500?{value:t}:e.valueId?{valueId:e.valueId}:{value:t}};var f=class{constructor(){this.countsByKindSample=new Map,this.countBeyondSampleLimit=0}record(e){return this.startTime??=new Date,this.add(e,1)}absorb(e){for(let t of e)(this.startTime===void 0||t.startTime<this.startTime)&&(this.startTime=t.startTime),this.add(t.event.kindSample,t.count)}add(e,t){if(e!==void 0){let n=this.countsByKindSample.get(e);if(n!==void 0)return this.countsByKindSample.set(e,n+t),`known-kind-sample`;if(this.countsByKindSample.size<20)return this.countsByKindSample.set(e,t),`new-kind-sample`}let n=this.countBeyondSampleLimit===0;return this.countBeyondSampleLimit+=t,n?`first-beyond-sample-limit`:`beyond-sample-limit`}takeSnapshot(){let e=new Date,t=this.startTime??e,n=(n,r)=>({startTime:t,endTime:e,count:n,event:{reason:`invalid-context-kind`,kindSample:r}}),r=Array.from(this.countsByKindSample,([e,t])=>n(t,e)),i=this.countBeyondSampleLimit>0?[...r,n(this.countBeyondSampleLimit)]:r;return this.clear(),i}clear(){this.countsByKindSample.clear(),this.countBeyondSampleLimit=0,this.startTime=void 0}},p=class{constructor(e){this.turnedOff=!1,this.pendingEvaluations=[],this.pendingInvalidContextSubmissions=new f,this.logger=e.logger,this.workerCloseTimeout=e.workerCloseTimeout??6e3,this.pendingEvaluationLimit=e.evaluationQueueLimit??1e3,this.initializeMessage={type:`Initialize`,payload:{sdkKey:e.sdkKey,sdkIdentity:e.sdkIdentity,metaContext:e.metaContext,baseUrl:e.baseUrl.toString(),evaluationQueueLimit:this.pendingEvaluationLimit,initialFlushIntervalDelay:e.initialFlushIntervalDelay??5e3,flushIntervalDelay:e.flushIntervalDelay??3e4}},this.visibilityHandler=()=>{document.visibilityState===`hidden`&&this.flush()}}createWorkerOrTurnOff(){if(typeof Worker>`u`){this.turnOff(`[WebWorkerTelemetryClient] Telemetry is off because Web Workers are not available in this environment.`);return}try{return new Worker(URL.createObjectURL(new Blob(["(function(){let e=async(e,t)=>e.valueId?{valueId:e.valueId}:e.value?e.value.length<=500&&e.type!=`json`?{value:e.value}:{valueId:await t(e.value)}:e,t=e=>{let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]?.length??0)>0)return!1;return!0},n=e=>{if(!e)return!0;let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]??0)>0)return!1;return!0},r=async(e,t,n,r)=>{let i=new AbortController,a=setTimeout(()=>{r.debug(`[fetchWithTimeout] Reached timeout, aborting request`),i.abort()},e);try{let e=await fetch(typeof t==`string`||t instanceof Request?t:t.toString(),{...n,signal:i.signal});return clearTimeout(a),e}catch(e){throw r.warn(`[fetchWithTimeout] Fetch error: `,e),clearTimeout(a),e}},i=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var a=class{constructor(e){this.executeRequests=!0,this.sdkKey=e.sdkKey,this.logger=e.logger,this.sdkIdentity=e.sdkIdentity,this.metaContext=e.metaContext,this.url=e.urlFactory(`client/telemetry/v1`,e.baseUrl)}async report({context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r}){if(!this.executeRequests)return{success:!1,fatalError:!0};let i={clientSdkKey:this.sdkKey,metaContext:{sdkName:this.sdkIdentity.sdkName,sdkVersion:this.sdkIdentity.sdkVersion,appName:this.metaContext.appName,appVersion:this.metaContext.appVersion},context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r};if(this.isReportEmpty(i))return{success:!0,fatalError:!1};let a=await this.sendReport(i);return a.fatalError&&(this.executeRequests=!1),a}isReportEmpty(e){return t(e.discreteEvents)&&t(e.aggregatedEvents)&&n(e.droppedEvents)}async sendReport(e){try{let t=await r(5e3,this.url,{method:`POST`,body:JSON.stringify(e),keepalive:!0},this.logger),n=this.isStatusFatal(t.status);return n&&this.logger.warn(`[EventReporter] Received a fatal status response (${t.status}) from the telemetry endpoint. No more telemetry data will be sent.`),{success:t.ok,fatalError:n}}catch(e){let t=i(e);return this.logger.warn(`[EventReporter] Error attempting to send telemetry data: ${e}`,{error:e}),{success:!1,fatalError:t}}}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}},o=class{aggregate(e){if(e.events.length==0)return[];let t=new Map;for(let n of e.events){let e=JSON.stringify(n),r=t.get(e)?.count||0;t.set(e,{event:n,count:r+1})}return Array.from(t).map(([,t])=>({startTime:e.startTime,endTime:e.endTime,count:t.count,event:t.event}))}},s=class{constructor(e){this._events=[],this._droppedEventCount=0,this.limit=e??1e3}get events(){return this._events}get reachedLimit(){return this._events.length>=this.limit}get droppedEventCount(){return this._droppedEventCount}push(...e){this.startTime||=new Date;let t=Math.max(0,e.length-this.limit),n=e.slice(t,e.length);if(this._droppedEventCount+=t,this._events.length+n.length>this.limit){let e=this._events.length+n.length-this.limit;this._events.splice(0,e),this._droppedEventCount+=e}return this._events.push(...n)}takeSnapshot(){let e=new Date,t=this.startTime??e,n=this._events.splice(0),r=this._droppedEventCount;return this.startTime=void 0,this._droppedEventCount=0,{startTime:t,endTime:e,events:n,droppedCount:r}}clear(){this._events=[],this.startTime=void 0,this._droppedEventCount=0}},c=class{constructor(e){this.aggregator=new o,this.collectEvents=!0,this.started=!1,this.logger=e.logger,this.evaluationEventQueue=new s(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4,this.initialFlushIntervalDelay=e.initialFlushIntervalDelay??5e3}start(){this.started||!this.collectEvents||(this.started=!0,this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.initialFlushIntervalDelay))}async flushAndScheduleNext(){if(!this.collectEvents)return;let e;try{e=await this.flush()}catch(t){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events: `,t),e={success:!1,fatalError:!1}}e.fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.collectEvents&&(this.cancelScheduledFlush(),this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay))}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout);try{await this.flush()}catch(e){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events during close: `,e)}this.evaluationEventQueue.clear()}dispose(){this.close()}},l=class{constructor(e){this.valueIdGenerator=e,this.valueIdGenerator=e}async process(t){let n=await Promise.all(t.events.map(async t=>({...t,defaultValue:await e(t.defaultValue,this.valueIdGenerator),evaluatedValue:await e(t.evaluatedValue,this.valueIdGenerator)})));return{...t,events:n}}},u=class{constructor(){this.countsByKindSample=new Map,this.countBeyondSampleLimit=0}record(e){return this.startTime??=new Date,this.add(e,1)}absorb(e){for(let t of e)(this.startTime===void 0||t.startTime<this.startTime)&&(this.startTime=t.startTime),this.add(t.event.kindSample,t.count)}add(e,t){if(e!==void 0){let n=this.countsByKindSample.get(e);if(n!==void 0)return this.countsByKindSample.set(e,n+t),`known-kind-sample`;if(this.countsByKindSample.size<20)return this.countsByKindSample.set(e,t),`new-kind-sample`}let n=this.countBeyondSampleLimit===0;return this.countBeyondSampleLimit+=t,n?`first-beyond-sample-limit`:`beyond-sample-limit`}takeSnapshot(){let e=new Date,t=this.startTime??e,n=(n,r)=>({startTime:t,endTime:e,count:n,event:{reason:`invalid-context-kind`,kindSample:r}}),r=Array.from(this.countsByKindSample,([e,t])=>n(t,e)),i=this.countBeyondSampleLimit>0?[...r,n(this.countBeyondSampleLimit)]:r;return this.clear(),i}clear(){this.countsByKindSample.clear(),this.countBeyondSampleLimit=0,this.startTime=void 0}},d=class extends c{constructor(e){super(e),this.invalidContextSubmissions=new u,this.reporter=new a(e),this.evaluationEventSnapshotPreprocessor=new l(e.valueIdGenerator)}async updateContext(e){this.cancelScheduledFlush(),await this.flush(),this._context=e,await this.flushAndScheduleNext()}evaluatedConfig(e){this.collectEvents&&this.evaluationEventQueue.push(e)}recordInvalidContext(e){this.invalidContextSubmissions.record(e)}absorbInvalidContextSubmissions(e){this.invalidContextSubmissions.absorb(e)}async forceFlush(){this.cancelScheduledFlush(),await this.flushAndScheduleNext()}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e),invalidContext:this.invalidContextSubmissions.takeSnapshot()},droppedEvents:{evaluatedConfig:e.droppedCount}})}};let f=(e,t)=>new URL(e,t?.toString()),p=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},m=Math.ceil(128/Math.log2(62)),h=new TextEncoder,g=async e=>{if(typeof crypto>`u`||crypto.subtle==null)return;let t=await crypto.subtle.digest(`SHA-256`,h.encode(e?.toString()??``));return p(new Uint8Array(t,0,16),m)},_,v=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),y=e=>{try{self.postMessage(e)}catch{self.postMessage(v(e.payload.level,e.payload.message))}},b={debug:function(e,...t){y(v(`debug`,e,t))},info:function(e,...t){y(v(`info`,e,t))},warn:function(e,...t){y(v(`warn`,e,t))},error:function(e,...t){y(v(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!_){b.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(b.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:if(_){b.warn(`[TelemetryWorker] Received a duplicate Initialize event, ignoring it`);break}_=new d({...t.payload,baseUrl:f(t.payload.baseUrl),urlFactory:f,valueIdGenerator:g,logger:b}),_.start();break;case`EvaluatedConfigEvent`:_?.evaluatedConfig(t.payload);break;case`InvalidContextSubmissions`:_?.absorbInvalidContextSubmissions(t.payload.entries);break;case`UpdateContext`:_?.updateContext(t.payload.context);break;case`Flush`:_?.forceFlush();break;case`Close`:(_?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"],{type:`application/javascript`})))}catch(e){this.turnOff(`[WebWorkerTelemetryClient] Telemetry is off because the telemetry Web Worker could not be created: `,e);return}}turnOff(e,...t){this.turnedOff=!0,this.pendingEvaluations.length=0,this.logger.warn(e,...t)}startWorker(){if(this.worker||this.turnedOff)return this.worker;let e=this.createWorkerOrTurnOff();if(e){e.onmessage=e=>{this.handleWorkerEvent(e.data)},e.postMessage(this.initializeMessage),this.worker=e;try{document.addEventListener(`visibilitychange`,this.visibilityHandler)}catch(e){this.logger.warn(`[TelemetryEventCollector] Could not configure 'visibilitychange' listener: `,e)}for(let t of this.pendingEvaluations)e.postMessage(t);return this.pendingEvaluations.length=0,this.forwardInvalidContextSubmissions(e),e}}forwardInvalidContextSubmissions(e){if(!e)return;let t=this.pendingInvalidContextSubmissions.takeSnapshot();if(t.length===0)return;let n={type:`InvalidContextSubmissions`,payload:{entries:t}};e.postMessage(n)}async updateContext(e){if(this.closePromise)return;let t={type:`UpdateContext`,payload:{context:e}};this.startWorker()?.postMessage(t)}evaluatedConfig(e){if(this.turnedOff)return;let t={type:`EvaluatedConfigEvent`,payload:this.sanitizeEvaluatedConfigEvent(e)};if(this.worker){this.worker.postMessage(t);return}this.pendingEvaluations.length>=this.pendingEvaluationLimit&&this.pendingEvaluations.shift(),this.pendingEvaluations.push(t)}recordInvalidContext(e){this.pendingInvalidContextSubmissions.record(e),this.forwardInvalidContextSubmissions(this.worker)}sanitizeEvaluatedConfigEvent(e){return{...e,defaultValue:d({value:e.defaultValue,type:e.type}),evaluatedValue:d({value:e.evaluatedValue,valueId:e.evaluatedValueId,type:e.type})}}handleWorkerEvent(e){if(e.type===`Closed`){this.finishClose();return}if(!e.payload?.level||!e.payload?.message)return;let{level:t,message:n,args:r}=e.payload;switch(t){case`debug`:this.logger.debug(n,...r);break;case`info`:this.logger.info(n,...r);break;case`warn`:this.logger.warn(n,...r);break;case`error`:this.logger.error(n,...r);break}}flush(){this.worker?.postMessage({type:`Flush`})}close(){return this.closePromise?this.closePromise:this.performClose()}performClose(){let e=this.worker;if(!e)return this.pendingEvaluations.length=0,this.closePromise=Promise.resolve(),this.closePromise;try{document.removeEventListener(`visibilitychange`,this.visibilityHandler)}catch(e){this.logger.warn(`[WebWorkerTelemetryClient] Could not remove 'visibilitychange' listener: `,e)}return this.closePromise=new Promise(t=>{this.closeResolve=t,this.closeTimer=setTimeout(()=>{this.logger.warn(`[WebWorkerTelemetryClient] Timed out waiting for the telemetry worker to close. Terminating the worker.`),this.finishClose()},this.workerCloseTimeout),e.postMessage({type:`Close`})}),this.closePromise}finishClose(){clearTimeout(this.closeTimer),this.closeTimer=void 0,this.worker?.terminate(),this.closeResolve?.()}};const m=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},h=Math.ceil(128/Math.log2(62)),g=new TextEncoder,_=async e=>{if(typeof crypto>`u`||crypto.subtle==null)return;let t=await crypto.subtle.digest(`SHA-256`,g.encode(e?.toString()??``));return m(new Uint8Array(t,0,16),h)},v=(e,t,n)=>c.r.from(({clientSdkKey:e,baseUrl:n,logger:r,metadata:i})=>new p({sdkKey:e,sdkIdentity:{sdkName:t.sdkName,sdkVersion:t.sdkVersion},metaContext:{appName:i?.appName,appVersion:i?.appVersion},logger:r,baseUrl:n,urlFactory:c.i,valueIdGenerator:_}),e,t,n);var y=class{constructor(e){this.client=e,this.registrations=[]}on(e,t){this.client.on(e,t),this.registrations.push({event:e,handler:t})}registerHooks(e){for(let[t,n]of Object.entries(e??{})){let e=Array.isArray(n)?n:[n];for(let n of e)typeof n==`function`&&this.on(t,n)}}removeAll(){for(let{event:e,handler:t}of this.registrations)this.client.off(e,t);this.registrations=[]}};const b=(e,t)=>{if(Object.is(e,t))return!0;if(typeof e!=`object`||typeof t!=`object`||e===null||t===null||Object.getPrototypeOf(e)!==Object.getPrototypeOf(t))return!1;if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>b(e,t[n]));if(!x(e)||!x(t))return!1;let n=Object.keys(e),r=Object.keys(t);return n.length===r.length&&n.every(n=>Object.prototype.hasOwnProperty.call(t,n)&&b(e[n],t[n]))},x=e=>{let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},S=(e,t)=>e.isInitializing?`none`:e.isReady?t!==void 0&&!b(t,e.context)?`updateContext`:`none`:`initialize`,C=l.default.createContext({status:`loading`});var w=class{decorateMessage(e){return`[ConfigDirector:nextjs-sdk] ${e}`}};const T=e=>c.o(e,new w),E=e=>`client`in e&&e.client!==void 0,D=e=>e.isReady?`ready`:`default`;var O=class extends l.Component{constructor(e){super(e);let t=E(e)?e.client:c.n();this.ownsClient=t===void 0,this.client=t,this.state=t?{client:t,status:t.isReady?`ready`:`loading`}:{status:`loading`}}buildClient(){let e=this.props;return v(e.sdkKey,{sdkName:`nextjs-sdk`,sdkVersion:`1.11.0`},{connection:{url:e.url,timeout:e.timeout,mode:e.mode,pollingInterval:e.pollingInterval,values:e.values},metadata:{appName:e.appName,appVersion:e.appVersion},logger:T(e.logLevel??`warn`),hooks:e.hooks})}async componentDidMount(){let e=this.client;this.ownsClient&&(e=this.buildClient(),this.client=e,this.setState({client:e})),e&&(this.handlers=new y(e),this.handlers.on(`configsUpdated`,()=>{this.setState({updatedAt:new Date})}),this.handlers.on(`clientReady`,()=>{this.setState({status:`ready`})}),this.ownsClient||this.handlers.registerHooks(this.props.hooks),await this.connect(e,this.props.context))}async connect(e,t){switch(S(e,t)){case`initialize`:await e.initialize(t);break;case`updateContext`:this.setState({status:`loading`}),await e.updateContext(t);break;case`none`:return}this.client===e&&this.setState({status:D(e)})}async componentDidUpdate(e){if(E(e)&&E(this.props)&&e.client!==this.props.client&&T(`warn`).warn(`The client prop of ConfigDirectorProvider changed after it mounted and is ignored. Remount the provider, for example with a new key, to use another client.`),!b(e.context,this.props.context)){let e=this.client;if(!e)return;this.setState({status:`loading`}),await e.updateContext(this.props.context??{}),this.client===e&&this.setState({status:D(e)})}}componentWillUnmount(){this.handlers?.removeAll(),this.handlers=void 0,this.ownsClient&&(this.client?.dispose(),this.client=void 0)}render(){return(0,u.jsx)(C.Provider,{value:{...this.state,initialConfigs:this.props.initialConfigs},children:this.props.children})}},k=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorNextContextError`,Object.setPrototypeOf(this,e.prototype)}};const A=()=>new k(`The ConfigDirector client was not found in the React context. Make sure the component using this hook is inside a <ConfigDirectorProvider>.`),j=(e,t)=>{let n=(0,l.useContext)(C);if(!n)throw A();let r=n.initialConfigs?.[e];return{value:n.client?.isReady?n.client.getValue(e,t):r?c.s(r,t).parsedValue:t,readyStatus:n.status,loading:n.status===`loading`}},M=()=>{let e=(0,l.useContext)(C);if(!e)throw A();return{updateContext:async t=>{await e.client?.updateContext(t)}}},N=()=>{let e=(0,l.useContext)(C);if(!e?.client)throw A();return{client:e.client}},P=()=>{let e=(0,l.useContext)(C);if(!e)throw A();return{readyStatus:e.status,loading:e.status===`loading`}};exports.ConfigDirectorNextContextError=k,exports.ConfigDirectorProvider=O,exports.createConsoleLogger=T,exports.useClient=N,exports.useConfigDirectorStatus=P,exports.useConfigValue=j,exports.useContext=M;
@@ -1,5 +1,5 @@
1
1
 
2
- import { a as ConfigDirectorLoggingLevel, c as ConnectionMode, i as ConfigDirectorLogger, n as ConfigDirectorClient, o as ConfigState, r as ConfigDirectorContext, s as ConfigValueType, t as ClientHooks } from "./types-fL7X5zwg.cjs";
2
+ import { c as ConfigDirectorContext, d as ConfigState, f as ConfigValueType, i as OfflineValues, l as ConfigDirectorLogger, n as ConfigDirectorClient, p as ConnectionMode, r as OfflineValue, t as ClientHooks, u as ConfigDirectorLoggingLevel } from "./types-2Z0rA7lF.cjs";
3
3
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
4
  import { Component, PropsWithChildren } from "react";
5
5
 
@@ -14,9 +14,10 @@ interface ConfigDirectorContextData {
14
14
  type ConfigDirectorProviderState = Omit<ConfigDirectorContextData, "initialConfigs">;
15
15
  type ConfigDirectorProviderOptions = {
16
16
  /**
17
- * Your ConfigDirector Client SDK key. This is a public value safe for the browser.
17
+ * Your ConfigDirector Client SDK key. This is a public value safe for the browser. Required
18
+ * unless `mode` is `offline`.
18
19
  */
19
- sdkKey: string;
20
+ sdkKey?: string;
20
21
  appName?: string;
21
22
  appVersion?: string;
22
23
  /**
@@ -28,11 +29,23 @@ type ConfigDirectorProviderOptions = {
28
29
  */
29
30
  timeout?: number;
30
31
  /**
31
- * The connection mode, one of `streaming` or `polling`. In `streaming` mode the connection stays
32
- * open and receives config updates as they happen. In `polling` mode configs are fetched once during
33
- * initialization and then again on every `pollingInterval`. Defaults to `streaming`.
32
+ * The connection mode, one of `streaming`, `polling` or `offline`. In `streaming` mode the connection
33
+ * stays open and receives config updates as they happen. In `polling` mode configs are fetched once
34
+ * during initialization and then again on every `pollingInterval`. In `offline` mode the browser
35
+ * client never connects to ConfigDirector and sends nothing: it serves `values` to every context,
36
+ * or the in-code default values when none are given, and needs no `sdkKey`. Defaults to `streaming`.
37
+ *
38
+ * The server `ConfigDirectorProvider` sets `offline` and `values` for you when `register()` ran in
39
+ * `offline` mode and you give neither prop.
34
40
  */
35
41
  mode?: ConnectionMode;
42
+ /**
43
+ * The values to serve in `offline` mode, keyed by config key. The config type of each value follows
44
+ * from the value: a boolean, an integral number (`integer`), any other number (`float`), a string, or
45
+ * a plain object or array (`json`). Can be given only in `offline` mode; otherwise the client fails
46
+ * to initialize.
47
+ */
48
+ values?: OfflineValues;
36
49
  /**
37
50
  * The polling interval in seconds when `mode` is `polling`. Has no effect in `streaming` mode.
38
51
  * Defaults to 60 seconds. A value below the minimum of 30 seconds is raised to 30 seconds and a
@@ -156,7 +169,7 @@ declare const useClient: () => {
156
169
  * Returns the current connection status of the browser client.
157
170
  *
158
171
  * - `"loading"` — client is initializing
159
- * - `"ready"` — client received configs from the server
172
+ * - `"ready"` — client received configs from the server, or loaded its offline values
160
173
  * - `"default"` — initialization timed out; hooks return default or initial values
161
174
  *
162
175
  * Must be used inside a `<ConfigDirectorProvider>`.
@@ -175,5 +188,5 @@ declare class ConfigDirectorNextContextError extends Error {
175
188
  constructor(message: string);
176
189
  }
177
190
  //#endregion
178
- export { type ClientStatus, type ConfigDirectorClient, type ConfigDirectorClientProviderClientProps, type ConfigDirectorClientProviderProps, type ConfigDirectorContext, type ConfigDirectorLogger, type ConfigDirectorLoggingLevel, ConfigDirectorNextContextError, ConfigDirectorProvider, type ConfigDirectorProviderOptions, type ConfigValueType, type ConnectionMode, createConsoleLogger, useClient, useConfigDirectorStatus, useConfigValue, useContext };
191
+ export { type ClientStatus, type ConfigDirectorClient, type ConfigDirectorClientProviderClientProps, type ConfigDirectorClientProviderProps, type ConfigDirectorContext, type ConfigDirectorLogger, type ConfigDirectorLoggingLevel, ConfigDirectorNextContextError, ConfigDirectorProvider, type ConfigDirectorProviderOptions, type ConfigValueType, type ConnectionMode, type OfflineValue, type OfflineValues, createConsoleLogger, useClient, useConfigDirectorStatus, useConfigValue, useContext };
179
192
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/client/types.ts","../../src/client/ConfigDirectorProvider.tsx","../../src/client/hooks.tsx","../../src/client/logger.ts","../../src/client/errors.ts"],"mappings":";;;;;;KAWY,YAAA;AAAA,UAEK,yBAAA;EACf,MAAA,GAAS,oBAAA;EACT,SAAA,GAAY,IAAA;EACZ,MAAA,EAAQ,YAAA;EACR,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;AAAA,KAGtB,2BAAA,GAA8B,IAAA,CAAK,yBAAA;AAAA,KAEnC,6BAAA;;;;EAIV,MAAA;EACA,OAAA;EACA,UAAA;EAXuB;;;EAevB,GAAA;EAjBA;;;EAqBA,OAAA;EAnBA;;;;;EAyBA,IAAA,GAAO,cAAA;EAtB8B;;;;AAEvC;EA0BE,eAAA;;;;EAIA,OAAA,GAAU,qBAAA;EAMF;;;EAFR,QAAA,GAAW,0BAAA;EAEX,KAAA,GAAQ,WAAA;EAhCR;;;;;;;;;;EA2CA,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;;;;;KAOtB,uCAAA;EAPiC;;AAO7C;;;;EAOE,MAAA,EAAQ,oBAAA;EACR,OAAA,GAAU,qBAAA;EASsB;;;;EAJhC,KAAA,GAAQ,WAAA;EANA;;;EAUR,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;;;;;KAOtB,iCAAA,GAAoC,6BAAA,GAAgC,uCAAA;;;;;;AAzFhF;;;;;AAEA;;;;;;;;cCsBa,sBAAA,SAA+B,SAAA,CAC1C,iBAAA,CAAkB,iCAAA,GAClB,2BAAA;EAAA,QAEQ,MAAA;EAAA,iBACS,UAAA;EAAA,QACT,QAAA;cAEI,KAAA,EAAO,iBAAA,CAAkB,iCAAA;EAAA,QAU7B,WAAA;EAmBO,iBAAA,CAAA,GAAqB,OAAA;EAAA,QAwBtB,OAAA;EAiBC,kBAAA,CACb,SAAA,EAAW,iBAAA,CAAkB,iCAAA,IAC5B,OAAA;EAiBM,oBAAA,CAAA;EASA,MAAA,CAAA,GAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;;;ADlIjB;;;;;AAEA;;cEYa,cAAA,aAA4B,eAAA,EACvC,GAAA,UACA,YAAA,EAAc,CAAA;EACX,KAAA,EAAO,CAAA;EAAG,WAAA,EAAa,YAAA;EAAc,OAAA;AAAA;;;;;;;cA2B7B,UAAA;EAAmB,aAAA,GAAgB,OAAA,EAAS,qBAAA,KAA0B,OAAA;AAAA;;;;;;cAiBtE,SAAA;UAIZ,oBAAA;AAAA;;;AFtDD;;;;;;;cEiEa,uBAAA;EAAgC,WAAA,EAAa,YAAA;EAAc,OAAA;AAAA;;;cC1E3D,mBAAA,GAAuB,KAAA,EAAO,0BAAA,KAA6B,oBAAA;;;cCb3D,8BAAA,SAAuC,KAAA;EAAA,SACzB,IAAA;cAEb,OAAA;AAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/client/types.ts","../../src/client/ConfigDirectorProvider.tsx","../../src/client/hooks.tsx","../../src/client/logger.ts","../../src/client/errors.ts"],"mappings":";;;;;;KAaY,YAAA;AAAA,UAEK,yBAAA;EACf,MAAA,GAAS,oBAAA;EACT,SAAA,GAAY,IAAA;EACZ,MAAA,EAAQ,YAAA;EACR,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;AAAA,KAGtB,2BAAA,GAA8B,IAAA,CAAK,yBAAA;AAAA,KAEnC,6BAAA;;;;;EAKV,MAAA;EACA,OAAA;EACA,UAAA;EAZuB;;;EAgBvB,GAAA;EAlBY;;;EAsBZ,OAAA;EApBiB;;;;AAGnB;;;;;AAEA;EA0BE,IAAA,GAAO,cAAA;;;;;;;EAOP,MAAA,GAAS,aAAA;EA2BQ;;;;;EArBjB,eAAA;EA5BA;;;EAgCA,OAAA,GAAU,qBAAA;EAVV;;;EAcA,QAAA,GAAW,0BAAA;EAEX,KAAA,GAAQ,WAAA;EAFR;;;;;;;;;AAoBF;EAPE,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;;;;;KAOtB,uCAAA;EAiBa;;;;;;EAVvB,MAAA,EAAQ,oBAAA;EACR,OAAA,GAAU,qBAAA;EASV;;;;EAJA,KAAA,GAAQ,WAAA;EAWE;;;EAPV,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;;;;ACtElC;KD6EY,iCAAA,GAAoC,6BAAA,GAAgC,uCAAA;;;;;;AAtGhF;;;;;AAEA;;;;;;;;cCuBa,sBAAA,SAA+B,SAAA,CAC1C,iBAAA,CAAkB,iCAAA,GAClB,2BAAA;EAAA,QAEQ,MAAA;EAAA,iBACS,UAAA;EAAA,QACT,QAAA;cAEI,KAAA,EAAO,iBAAA,CAAkB,iCAAA;EAAA,QAU7B,WAAA;EAoBO,iBAAA,CAAA,GAAqB,OAAA;EAAA,QAwBtB,OAAA;EAiBC,kBAAA,CACb,SAAA,EAAW,iBAAA,CAAkB,iCAAA,IAC5B,OAAA;EAiBM,oBAAA,CAAA;EASA,MAAA,CAAA,GAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;;;ADpIjB;;;;;AAEA;;cEUa,cAAA,aAA4B,eAAA,EACvC,GAAA,UACA,YAAA,EAAc,CAAA;EACX,KAAA,EAAO,CAAA;EAAG,WAAA,EAAa,YAAA;EAAc,OAAA;AAAA;;;;;;;cA2B7B,UAAA;EAAmB,aAAA,GAAgB,OAAA,EAAS,qBAAA,KAA0B,OAAA;AAAA;;;;;;cAiBtE,SAAA;UAIZ,oBAAA;AAAA;;;AFpDD;;;;;;;cE+Da,uBAAA;EAAgC,WAAA,EAAa,YAAA;EAAc,OAAA;AAAA;;;cC1E3D,mBAAA,GAAuB,KAAA,EAAO,0BAAA,KAA6B,oBAAA;;;cCb3D,8BAAA,SAAuC,KAAA;EAAA,SACzB,IAAA;cAEb,OAAA;AAAA"}
@@ -1,5 +1,5 @@
1
1
 
2
- import { a as ConfigDirectorLoggingLevel, c as ConnectionMode, i as ConfigDirectorLogger, n as ConfigDirectorClient, o as ConfigState, r as ConfigDirectorContext, s as ConfigValueType, t as ClientHooks } from "./types-DA2VZKNX.mjs";
2
+ import { c as ConfigDirectorContext, d as ConfigState, f as ConfigValueType, i as OfflineValues, l as ConfigDirectorLogger, n as ConfigDirectorClient, p as ConnectionMode, r as OfflineValue, t as ClientHooks, u as ConfigDirectorLoggingLevel } from "./types-6a1uEkD0.mjs";
3
3
  import { Component, PropsWithChildren } from "react";
4
4
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
5
5
 
@@ -14,9 +14,10 @@ interface ConfigDirectorContextData {
14
14
  type ConfigDirectorProviderState = Omit<ConfigDirectorContextData, "initialConfigs">;
15
15
  type ConfigDirectorProviderOptions = {
16
16
  /**
17
- * Your ConfigDirector Client SDK key. This is a public value safe for the browser.
17
+ * Your ConfigDirector Client SDK key. This is a public value safe for the browser. Required
18
+ * unless `mode` is `offline`.
18
19
  */
19
- sdkKey: string;
20
+ sdkKey?: string;
20
21
  appName?: string;
21
22
  appVersion?: string;
22
23
  /**
@@ -28,11 +29,23 @@ type ConfigDirectorProviderOptions = {
28
29
  */
29
30
  timeout?: number;
30
31
  /**
31
- * The connection mode, one of `streaming` or `polling`. In `streaming` mode the connection stays
32
- * open and receives config updates as they happen. In `polling` mode configs are fetched once during
33
- * initialization and then again on every `pollingInterval`. Defaults to `streaming`.
32
+ * The connection mode, one of `streaming`, `polling` or `offline`. In `streaming` mode the connection
33
+ * stays open and receives config updates as they happen. In `polling` mode configs are fetched once
34
+ * during initialization and then again on every `pollingInterval`. In `offline` mode the browser
35
+ * client never connects to ConfigDirector and sends nothing: it serves `values` to every context,
36
+ * or the in-code default values when none are given, and needs no `sdkKey`. Defaults to `streaming`.
37
+ *
38
+ * The server `ConfigDirectorProvider` sets `offline` and `values` for you when `register()` ran in
39
+ * `offline` mode and you give neither prop.
34
40
  */
35
41
  mode?: ConnectionMode;
42
+ /**
43
+ * The values to serve in `offline` mode, keyed by config key. The config type of each value follows
44
+ * from the value: a boolean, an integral number (`integer`), any other number (`float`), a string, or
45
+ * a plain object or array (`json`). Can be given only in `offline` mode; otherwise the client fails
46
+ * to initialize.
47
+ */
48
+ values?: OfflineValues;
36
49
  /**
37
50
  * The polling interval in seconds when `mode` is `polling`. Has no effect in `streaming` mode.
38
51
  * Defaults to 60 seconds. A value below the minimum of 30 seconds is raised to 30 seconds and a
@@ -156,7 +169,7 @@ declare const useClient: () => {
156
169
  * Returns the current connection status of the browser client.
157
170
  *
158
171
  * - `"loading"` — client is initializing
159
- * - `"ready"` — client received configs from the server
172
+ * - `"ready"` — client received configs from the server, or loaded its offline values
160
173
  * - `"default"` — initialization timed out; hooks return default or initial values
161
174
  *
162
175
  * Must be used inside a `<ConfigDirectorProvider>`.
@@ -175,5 +188,5 @@ declare class ConfigDirectorNextContextError extends Error {
175
188
  constructor(message: string);
176
189
  }
177
190
  //#endregion
178
- export { type ClientStatus, type ConfigDirectorClient, type ConfigDirectorClientProviderClientProps, type ConfigDirectorClientProviderProps, type ConfigDirectorContext, type ConfigDirectorLogger, type ConfigDirectorLoggingLevel, ConfigDirectorNextContextError, ConfigDirectorProvider, type ConfigDirectorProviderOptions, type ConfigValueType, type ConnectionMode, createConsoleLogger, useClient, useConfigDirectorStatus, useConfigValue, useContext };
191
+ export { type ClientStatus, type ConfigDirectorClient, type ConfigDirectorClientProviderClientProps, type ConfigDirectorClientProviderProps, type ConfigDirectorContext, type ConfigDirectorLogger, type ConfigDirectorLoggingLevel, ConfigDirectorNextContextError, ConfigDirectorProvider, type ConfigDirectorProviderOptions, type ConfigValueType, type ConnectionMode, type OfflineValue, type OfflineValues, createConsoleLogger, useClient, useConfigDirectorStatus, useConfigValue, useContext };
179
192
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/client/types.ts","../../src/client/ConfigDirectorProvider.tsx","../../src/client/hooks.tsx","../../src/client/logger.ts","../../src/client/errors.ts"],"mappings":";;;;;;KAWY,YAAA;AAAA,UAEK,yBAAA;EACf,MAAA,GAAS,oBAAA;EACT,SAAA,GAAY,IAAA;EACZ,MAAA,EAAQ,YAAA;EACR,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;AAAA,KAGtB,2BAAA,GAA8B,IAAA,CAAK,yBAAA;AAAA,KAEnC,6BAAA;;;;EAIV,MAAA;EACA,OAAA;EACA,UAAA;EAXuB;;;EAevB,GAAA;EAjBA;;;EAqBA,OAAA;EAnBA;;;;;EAyBA,IAAA,GAAO,cAAA;EAtB8B;;;;AAEvC;EA0BE,eAAA;;;;EAIA,OAAA,GAAU,qBAAA;EAMF;;;EAFR,QAAA,GAAW,0BAAA;EAEX,KAAA,GAAQ,WAAA;EAhCR;;;;;;;;;;EA2CA,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;;;;;KAOtB,uCAAA;EAPiC;;AAO7C;;;;EAOE,MAAA,EAAQ,oBAAA;EACR,OAAA,GAAU,qBAAA;EASsB;;;;EAJhC,KAAA,GAAQ,WAAA;EANA;;;EAUR,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;;;;;KAOtB,iCAAA,GAAoC,6BAAA,GAAgC,uCAAA;;;;;;AAzFhF;;;;;AAEA;;;;;;;;cCsBa,sBAAA,SAA+B,SAAA,CAC1C,iBAAA,CAAkB,iCAAA,GAClB,2BAAA;EAAA,QAEQ,MAAA;EAAA,iBACS,UAAA;EAAA,QACT,QAAA;cAEI,KAAA,EAAO,iBAAA,CAAkB,iCAAA;EAAA,QAU7B,WAAA;EAmBO,iBAAA,CAAA,GAAqB,OAAA;EAAA,QAwBtB,OAAA;EAiBC,kBAAA,CACb,SAAA,EAAW,iBAAA,CAAkB,iCAAA,IAC5B,OAAA;EAiBM,oBAAA,CAAA;EASA,MAAA,CAAA,GAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;;;ADlIjB;;;;;AAEA;;cEYa,cAAA,aAA4B,eAAA,EACvC,GAAA,UACA,YAAA,EAAc,CAAA;EACX,KAAA,EAAO,CAAA;EAAG,WAAA,EAAa,YAAA;EAAc,OAAA;AAAA;;;;;;;cA2B7B,UAAA;EAAmB,aAAA,GAAgB,OAAA,EAAS,qBAAA,KAA0B,OAAA;AAAA;;;;;;cAiBtE,SAAA;UAIZ,oBAAA;AAAA;;;AFtDD;;;;;;;cEiEa,uBAAA;EAAgC,WAAA,EAAa,YAAA;EAAc,OAAA;AAAA;;;cC1E3D,mBAAA,GAAuB,KAAA,EAAO,0BAAA,KAA6B,oBAAA;;;cCb3D,8BAAA,SAAuC,KAAA;EAAA,SACzB,IAAA;cAEb,OAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/client/types.ts","../../src/client/ConfigDirectorProvider.tsx","../../src/client/hooks.tsx","../../src/client/logger.ts","../../src/client/errors.ts"],"mappings":";;;;;;KAaY,YAAA;AAAA,UAEK,yBAAA;EACf,MAAA,GAAS,oBAAA;EACT,SAAA,GAAY,IAAA;EACZ,MAAA,EAAQ,YAAA;EACR,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;AAAA,KAGtB,2BAAA,GAA8B,IAAA,CAAK,yBAAA;AAAA,KAEnC,6BAAA;;;;;EAKV,MAAA;EACA,OAAA;EACA,UAAA;EAZuB;;;EAgBvB,GAAA;EAlBY;;;EAsBZ,OAAA;EApBiB;;;;AAGnB;;;;;AAEA;EA0BE,IAAA,GAAO,cAAA;;;;;;;EAOP,MAAA,GAAS,aAAA;EA2BQ;;;;;EArBjB,eAAA;EA5BA;;;EAgCA,OAAA,GAAU,qBAAA;EAVV;;;EAcA,QAAA,GAAW,0BAAA;EAEX,KAAA,GAAQ,WAAA;EAFR;;;;;;;;;AAoBF;EAPE,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;;;;;KAOtB,uCAAA;EAiBa;;;;;;EAVvB,MAAA,EAAQ,oBAAA;EACR,OAAA,GAAU,qBAAA;EASV;;;;EAJA,KAAA,GAAQ,WAAA;EAWE;;;EAPV,cAAA,GAAiB,MAAA,SAAe,WAAA;AAAA;;;;ACtElC;KD6EY,iCAAA,GAAoC,6BAAA,GAAgC,uCAAA;;;;;;AAtGhF;;;;;AAEA;;;;;;;;cCuBa,sBAAA,SAA+B,SAAA,CAC1C,iBAAA,CAAkB,iCAAA,GAClB,2BAAA;EAAA,QAEQ,MAAA;EAAA,iBACS,UAAA;EAAA,QACT,QAAA;cAEI,KAAA,EAAO,iBAAA,CAAkB,iCAAA;EAAA,QAU7B,WAAA;EAoBO,iBAAA,CAAA,GAAqB,OAAA;EAAA,QAwBtB,OAAA;EAiBC,kBAAA,CACb,SAAA,EAAW,iBAAA,CAAkB,iCAAA,IAC5B,OAAA;EAiBM,oBAAA,CAAA;EASA,MAAA,CAAA,GAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;;;ADpIjB;;;;;AAEA;;cEUa,cAAA,aAA4B,eAAA,EACvC,GAAA,UACA,YAAA,EAAc,CAAA;EACX,KAAA,EAAO,CAAA;EAAG,WAAA,EAAa,YAAA;EAAc,OAAA;AAAA;;;;;;;cA2B7B,UAAA;EAAmB,aAAA,GAAgB,OAAA,EAAS,qBAAA,KAA0B,OAAA;AAAA;;;;;;cAiBtE,SAAA;UAIZ,oBAAA;AAAA;;;AFpDD;;;;;;;cE+Da,uBAAA;EAAgC,WAAA,EAAa,YAAA;EAAc,OAAA;AAAA;;;cC1E3D,mBAAA,GAAuB,KAAA,EAAO,0BAAA,KAA6B,oBAAA;;;cCb3D,8BAAA,SAAuC,KAAA;EAAA,SACzB,IAAA;cAEb,OAAA;AAAA"}
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s}from"./installedTestClient-CDdDsfVQ.mjs";import c,{Component as l,useContext as u}from"react";import{jsx as d}from"react/jsx-runtime";const f=e=>{var t;if(e.type===`json`||e.type==null&&typeof e.value==`object`){if(e.valueId)return{valueId:e.valueId,type:`json`};try{return{value:JSON.stringify(e.value),type:`json`}}catch(t){return{value:e.value.toString(),type:`json`}}}let n=(t=e.value)==null?void 0:t.toString();return n&&n.length<=500?{value:n}:e.valueId?{valueId:e.valueId}:{value:n}};var p=class{constructor(e){var t,n,r,i;this.turnedOff=!1,this.pendingEvaluations=[],this.logger=e.logger,this.workerCloseTimeout=(t=e.workerCloseTimeout)==null?6e3:t,this.pendingEvaluationLimit=(n=e.evaluationQueueLimit)==null?1e3:n,this.initializeMessage={type:`Initialize`,payload:{sdkKey:e.sdkKey,sdkIdentity:e.sdkIdentity,metaContext:e.metaContext,baseUrl:e.baseUrl.toString(),evaluationQueueLimit:this.pendingEvaluationLimit,initialFlushIntervalDelay:(r=e.initialFlushIntervalDelay)==null?5e3:r,flushIntervalDelay:(i=e.flushIntervalDelay)==null?3e4:i}},this.visibilityHandler=()=>{document.visibilityState===`hidden`&&this.flush()}}createWorkerOrTurnOff(){if(typeof Worker>`u`){this.turnOff(`[WebWorkerTelemetryClient] Telemetry is off because Web Workers are not available in this environment.`);return}try{return new Worker(URL.createObjectURL(new Blob(["(function(){let e=async(e,t)=>e.valueId?{valueId:e.valueId}:e.value?e.value.length<=500&&e.type!=`json`?{value:e.value}:{valueId:await t(e.value)}:e,t=e=>{let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]?.length??0)>0)return!1;return!0},n=e=>{if(!e)return!0;let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]??0)>0)return!1;return!0},r=async(e,t,n,r)=>{let i=new AbortController,a=setTimeout(()=>{r.debug(`[fetchWithTimeout] Reached timeout, aborting request`),i.abort()},e);try{let e=await fetch(typeof t==`string`||t instanceof Request?t:t.toString(),{...n,signal:i.signal});return clearTimeout(a),e}catch(e){throw r.warn(`[fetchWithTimeout] Fetch error: `,e),clearTimeout(a),e}},i=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var a=class{constructor(e){this.executeRequests=!0,this.sdkKey=e.sdkKey,this.logger=e.logger,this.sdkIdentity=e.sdkIdentity,this.metaContext=e.metaContext,this.url=e.urlFactory(`client/telemetry/v1`,e.baseUrl)}async report({context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r}){if(!this.executeRequests)return{success:!1,fatalError:!0};let i={clientSdkKey:this.sdkKey,metaContext:{sdkName:this.sdkIdentity.sdkName,sdkVersion:this.sdkIdentity.sdkVersion,appName:this.metaContext.appName,appVersion:this.metaContext.appVersion},context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r};if(this.isReportEmpty(i))return{success:!0,fatalError:!1};let a=await this.sendReport(i);return a.fatalError&&(this.executeRequests=!1),a}isReportEmpty(e){return t(e.discreteEvents)&&t(e.aggregatedEvents)&&n(e.droppedEvents)}async sendReport(e){try{let t=await r(5e3,this.url,{method:`POST`,body:JSON.stringify(e),keepalive:!0},this.logger),n=this.isStatusFatal(t.status);return n&&this.logger.warn(`[EventReporter] Received a fatal status response (${t.status}) from the telemetry endpoint. No more telemetry data will be sent.`),{success:t.ok,fatalError:n}}catch(e){let t=i(e);return this.logger.warn(`[EventReporter] Error attempting to send telemetry data: ${e}`,{error:e}),{success:!1,fatalError:t}}}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}},o=class{aggregate(e){if(e.events.length==0)return[];let t=new Map;for(let n of e.events){let e=JSON.stringify(n),r=t.get(e)?.count||0;t.set(e,{event:n,count:r+1})}return Array.from(t).map(([,t])=>({startTime:e.startTime,endTime:e.endTime,count:t.count,event:t.event}))}},s=class{constructor(e){this._events=[],this._droppedEventCount=0,this.limit=e??1e3}get events(){return this._events}get reachedLimit(){return this._events.length>=this.limit}get droppedEventCount(){return this._droppedEventCount}push(...e){this.startTime||=new Date;let t=Math.max(0,e.length-this.limit),n=e.slice(t,e.length);if(this._droppedEventCount+=t,this._events.length+n.length>this.limit){let e=this._events.length+n.length-this.limit;this._events.splice(0,e),this._droppedEventCount+=e}return this._events.push(...n)}takeSnapshot(){let e=new Date,t=this.startTime??e,n=this._events.splice(0),r=this._droppedEventCount;return this.startTime=void 0,this._droppedEventCount=0,{startTime:t,endTime:e,events:n,droppedCount:r}}clear(){this._events=[],this.startTime=void 0,this._droppedEventCount=0}},c=class{constructor(e){this.aggregator=new o,this.collectEvents=!0,this.started=!1,this.logger=e.logger,this.evaluationEventQueue=new s(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4,this.initialFlushIntervalDelay=e.initialFlushIntervalDelay??5e3}start(){this.started||!this.collectEvents||(this.started=!0,this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.initialFlushIntervalDelay))}async flushAndScheduleNext(){if(!this.collectEvents)return;let e;try{e=await this.flush()}catch(t){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events: `,t),e={success:!1,fatalError:!1}}e.fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.collectEvents&&(this.cancelScheduledFlush(),this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay))}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout);try{await this.flush()}catch(e){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events during close: `,e)}this.evaluationEventQueue.clear()}dispose(){this.close()}},l=class{constructor(e){this.valueIdGenerator=e,this.valueIdGenerator=e}async process(t){let n=await Promise.all(t.events.map(async t=>({...t,defaultValue:await e(t.defaultValue,this.valueIdGenerator),evaluatedValue:await e(t.evaluatedValue,this.valueIdGenerator)})));return{...t,events:n}}},u=class extends c{constructor(e){super(e),this.reporter=new a(e),this.evaluationEventSnapshotPreprocessor=new l(e.valueIdGenerator)}async updateContext(e){this.cancelScheduledFlush(),await this.flush(),this._context=e,await this.flushAndScheduleNext()}evaluatedConfig(e){this.collectEvents&&this.evaluationEventQueue.push(e)}async forceFlush(){this.cancelScheduledFlush(),await this.flushAndScheduleNext()}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e)},droppedEvents:{evaluatedConfig:e.droppedCount}})}};let d=(e,t)=>new URL(e,t?.toString()),f=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},p=Math.ceil(128/Math.log2(62)),m=new TextEncoder,h=async e=>{if(typeof crypto>`u`||crypto.subtle==null)return;let t=await crypto.subtle.digest(`SHA-256`,m.encode(e?.toString()??``));return f(new Uint8Array(t,0,16),p)},g,_=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),v=e=>{try{self.postMessage(e)}catch{self.postMessage(_(e.payload.level,e.payload.message))}},y={debug:function(e,...t){v(_(`debug`,e,t))},info:function(e,...t){v(_(`info`,e,t))},warn:function(e,...t){v(_(`warn`,e,t))},error:function(e,...t){v(_(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!g){y.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(y.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:if(g){y.warn(`[TelemetryWorker] Received a duplicate Initialize event, ignoring it`);break}g=new u({...t.payload,baseUrl:d(t.payload.baseUrl),urlFactory:d,valueIdGenerator:h,logger:y}),g.start();break;case`EvaluatedConfigEvent`:g?.evaluatedConfig(t.payload);break;case`UpdateContext`:g?.updateContext(t.payload.context);break;case`Flush`:g?.forceFlush();break;case`Close`:(g?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"],{type:`application/javascript`})))}catch(e){this.turnOff(`[WebWorkerTelemetryClient] Telemetry is off because the telemetry Web Worker could not be created: `,e);return}}turnOff(e,...t){this.turnedOff=!0,this.pendingEvaluations.length=0,this.logger.warn(e,...t)}startWorker(){if(this.worker||this.turnedOff)return this.worker;let e=this.createWorkerOrTurnOff();if(e){e.onmessage=e=>{this.handleWorkerEvent(e.data)},e.postMessage(this.initializeMessage),this.worker=e;try{document.addEventListener(`visibilitychange`,this.visibilityHandler)}catch(e){this.logger.warn(`[TelemetryEventCollector] Could not configure 'visibilitychange' listener: `,e)}for(let t of this.pendingEvaluations)e.postMessage(t);return this.pendingEvaluations.length=0,e}}async updateContext(e){var t=this,n;if(t.closePromise)return;let r={type:`UpdateContext`,payload:{context:e}};(n=t.startWorker())==null||n.postMessage(r)}evaluatedConfig(e){if(this.turnedOff)return;let t={type:`EvaluatedConfigEvent`,payload:this.sanitizeEvaluatedConfigEvent(e)};if(this.worker){this.worker.postMessage(t);return}this.pendingEvaluations.length>=this.pendingEvaluationLimit&&this.pendingEvaluations.shift(),this.pendingEvaluations.push(t)}sanitizeEvaluatedConfigEvent(e){return r(r({},e),{},{defaultValue:f({value:e.defaultValue,type:e.type}),evaluatedValue:f({value:e.evaluatedValue,valueId:e.evaluatedValueId,type:e.type})})}handleWorkerEvent(e){var t,n;if(e.type===`Closed`){this.finishClose();return}if(!((t=e.payload)!=null&&t.level)||!((n=e.payload)!=null&&n.message))return;let{level:r,message:i,args:a}=e.payload;switch(r){case`debug`:this.logger.debug(i,...a);break;case`info`:this.logger.info(i,...a);break;case`warn`:this.logger.warn(i,...a);break;case`error`:this.logger.error(i,...a);break}}flush(){var e;(e=this.worker)==null||e.postMessage({type:`Flush`})}close(){return this.closePromise?this.closePromise:this.performClose()}performClose(){let e=this.worker;if(!e)return this.pendingEvaluations.length=0,this.closePromise=Promise.resolve(),this.closePromise;try{document.removeEventListener(`visibilitychange`,this.visibilityHandler)}catch(e){this.logger.warn(`[WebWorkerTelemetryClient] Could not remove 'visibilitychange' listener: `,e)}return this.closePromise=new Promise(t=>{this.closeResolve=t,this.closeTimer=setTimeout(()=>{this.logger.warn(`[WebWorkerTelemetryClient] Timed out waiting for the telemetry worker to close. Terminating the worker.`),this.finishClose()},this.workerCloseTimeout),e.postMessage({type:`Close`})}),this.closePromise}finishClose(){var e,t;clearTimeout(this.closeTimer),this.closeTimer=void 0,(e=this.worker)==null||e.terminate(),(t=this.closeResolve)==null||t.call(this)}};const m=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},h=Math.ceil(128/Math.log2(62)),g=new TextEncoder,_=async e=>{var t;if(typeof crypto>`u`||crypto.subtle==null)return;let n=await crypto.subtle.digest(`SHA-256`,g.encode((t=e==null?void 0:e.toString())==null?``:t));return m(new Uint8Array(n,0,16),h)},v=(t,i,c)=>{var l,u,d,f,m;let h=(l=c==null?void 0:c.logger)==null?s():l,g=(u=a(c==null||(d=c.connection)==null?void 0:d.url))==null?n:u;return new o(new p({sdkKey:t,sdkIdentity:{sdkName:i.sdkName,sdkVersion:i.sdkVersion},metaContext:{appName:c==null||(f=c.metadata)==null?void 0:f.appName,appVersion:c==null||(m=c.metadata)==null?void 0:m.appVersion},logger:h,baseUrl:g,urlFactory:e,valueIdGenerator:_}),t,i,r(r({},c),{},{logger:h}))};var y=class{constructor(e){this.client=e,this.registrations=[]}on(e,t){this.client.on(e,t),this.registrations.push({event:e,handler:t})}registerHooks(e){for(let[t,n]of Object.entries(e==null?{}:e)){let e=Array.isArray(n)?n:[n];for(let n of e)typeof n==`function`&&this.on(t,n)}}removeAll(){for(let{event:e,handler:t}of this.registrations)this.client.off(e,t);this.registrations=[]}};const b=(e,t)=>{if(Object.is(e,t))return!0;if(typeof e!=`object`||typeof t!=`object`||e===null||t===null||Object.getPrototypeOf(e)!==Object.getPrototypeOf(t))return!1;if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>b(e,t[n]));if(!x(e)||!x(t))return!1;let n=Object.keys(e),r=Object.keys(t);return n.length===r.length&&n.every(n=>Object.prototype.hasOwnProperty.call(t,n)&&b(e[n],t[n]))},x=e=>{let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},S=(e,t)=>e.isInitializing?`none`:e.isReady?t!==void 0&&!b(t,e.context)?`updateContext`:`none`:`initialize`,C=c.createContext({status:`loading`});var w=class{decorateMessage(e){return`[ConfigDirector:nextjs-sdk] ${e}`}};const T=e=>s(e,new w),E=e=>`client`in e&&e.client!==void 0;var D=class extends l{constructor(e){super(e);let t=E(e)?e.client:i();this.ownsClient=t===void 0,this.client=t,this.state=t?{client:t,status:t.isReady?`ready`:`loading`}:{status:`loading`}}buildClient(){var e;let t=this.props;return v(t.sdkKey,{sdkName:`nextjs-sdk`,sdkVersion:`1.9.2`},{connection:{url:t.url,timeout:t.timeout,mode:t.mode,pollingInterval:t.pollingInterval},metadata:{appName:t.appName,appVersion:t.appVersion},logger:T((e=t.logLevel)==null?`warn`:e),hooks:t.hooks})}async componentDidMount(){var e=this;let t=e.client;e.ownsClient&&(t=e.buildClient(),e.client=t,e.setState({client:t})),t&&(e.handlers=new y(t),e.handlers.on(`configsUpdated`,()=>{e.setState({updatedAt:new Date})}),e.handlers.on(`clientReady`,()=>{e.setState({status:`ready`})}),e.ownsClient||e.handlers.registerHooks(e.props.hooks),await e.connect(t,e.props.context))}async connect(e,t){var n=this;switch(S(e,t)){case`initialize`:await e.initialize(t);break;case`updateContext`:n.setState({status:`loading`}),await e.updateContext(t);break;case`none`:return}n.client===e&&!e.isReady&&n.setState({status:`default`})}async componentDidUpdate(e){var t=this;if(E(e)&&E(t.props)&&e.client!==t.props.client&&T(`warn`).warn(`The client prop of ConfigDirectorProvider changed after it mounted and is ignored. Remount the provider, for example with a new key, to use another client.`),!b(e.context,t.props.context)){var n;let e=t.client;if(!e)return;t.setState({status:`loading`}),await e.updateContext((n=t.props.context)==null?{}:n),t.client===e&&!e.isReady&&t.setState({status:`default`})}}componentWillUnmount(){var e;if((e=this.handlers)==null||e.removeAll(),this.handlers=void 0,this.ownsClient){var t;(t=this.client)==null||t.dispose()}this.client=void 0}render(){return d(C.Provider,{value:r(r({},this.state),{},{initialConfigs:this.props.initialConfigs}),children:this.props.children})}},O=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorNextContextError`,Object.setPrototypeOf(this,e.prototype)}};const k=()=>new O(`The ConfigDirector client was not found in the React context. Make sure the component using this hook is inside a <ConfigDirectorProvider>.`),A=(e,n)=>{var r,i;let a=u(C);if(!a)throw k();let o=(r=a.initialConfigs)==null?void 0:r[e];return{value:(i=a.client)!=null&&i.isReady?a.client.getValue(e,n):o?t(o,n).parsedValue:n,readyStatus:a.status,loading:a.status===`loading`}},j=()=>{let e=u(C);if(!e)throw k();return{updateContext:async t=>{var n;await((n=e.client)==null?void 0:n.updateContext(t))}}},M=()=>{let e=u(C);if(!(e!=null&&e.client))throw k();return{client:e.client}},N=()=>{let e=u(C);if(!e)throw k();return{readyStatus:e.status,loading:e.status===`loading`}};export{O as ConfigDirectorNextContextError,D as ConfigDirectorProvider,T as createConsoleLogger,M as useClient,N as useConfigDirectorStatus,A as useConfigValue,j as useContext};
2
+ import{f as e,i as t,n,o as r,r as i,s as a}from"./installedTestClient-BwTUOOhP.mjs";import o,{Component as s,useContext as c}from"react";import{jsx as l}from"react/jsx-runtime";const u=e=>{var t;if(e.type===`json`||e.type==null&&typeof e.value==`object`){if(e.valueId)return{valueId:e.valueId,type:`json`};try{return{value:JSON.stringify(e.value),type:`json`}}catch(t){return{value:e.value.toString(),type:`json`}}}let n=(t=e.value)==null?void 0:t.toString();return n&&n.length<=500?{value:n}:e.valueId?{valueId:e.valueId}:{value:n}};var d=class{constructor(){this.countsByKindSample=new Map,this.countBeyondSampleLimit=0}record(e){return this.startTime!=null||(this.startTime=new Date),this.add(e,1)}absorb(e){for(let t of e)(this.startTime===void 0||t.startTime<this.startTime)&&(this.startTime=t.startTime),this.add(t.event.kindSample,t.count)}add(e,t){if(e!==void 0){let n=this.countsByKindSample.get(e);if(n!==void 0)return this.countsByKindSample.set(e,n+t),`known-kind-sample`;if(this.countsByKindSample.size<20)return this.countsByKindSample.set(e,t),`new-kind-sample`}let n=this.countBeyondSampleLimit===0;return this.countBeyondSampleLimit+=t,n?`first-beyond-sample-limit`:`beyond-sample-limit`}takeSnapshot(){var e;let t=new Date,n=(e=this.startTime)==null?t:e,r=(e,r)=>({startTime:n,endTime:t,count:e,event:{reason:`invalid-context-kind`,kindSample:r}}),i=Array.from(this.countsByKindSample,([e,t])=>r(t,e)),a=this.countBeyondSampleLimit>0?[...i,r(this.countBeyondSampleLimit)]:i;return this.clear(),a}clear(){this.countsByKindSample.clear(),this.countBeyondSampleLimit=0,this.startTime=void 0}},f=class{constructor(e){var t,n,r,i;this.turnedOff=!1,this.pendingEvaluations=[],this.pendingInvalidContextSubmissions=new d,this.logger=e.logger,this.workerCloseTimeout=(t=e.workerCloseTimeout)==null?6e3:t,this.pendingEvaluationLimit=(n=e.evaluationQueueLimit)==null?1e3:n,this.initializeMessage={type:`Initialize`,payload:{sdkKey:e.sdkKey,sdkIdentity:e.sdkIdentity,metaContext:e.metaContext,baseUrl:e.baseUrl.toString(),evaluationQueueLimit:this.pendingEvaluationLimit,initialFlushIntervalDelay:(r=e.initialFlushIntervalDelay)==null?5e3:r,flushIntervalDelay:(i=e.flushIntervalDelay)==null?3e4:i}},this.visibilityHandler=()=>{document.visibilityState===`hidden`&&this.flush()}}createWorkerOrTurnOff(){if(typeof Worker>`u`){this.turnOff(`[WebWorkerTelemetryClient] Telemetry is off because Web Workers are not available in this environment.`);return}try{return new Worker(URL.createObjectURL(new Blob(["(function(){let e=async(e,t)=>e.valueId?{valueId:e.valueId}:e.value?e.value.length<=500&&e.type!=`json`?{value:e.value}:{valueId:await t(e.value)}:e,t=e=>{let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]?.length??0)>0)return!1;return!0},n=e=>{if(!e)return!0;let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]??0)>0)return!1;return!0},r=async(e,t,n,r)=>{let i=new AbortController,a=setTimeout(()=>{r.debug(`[fetchWithTimeout] Reached timeout, aborting request`),i.abort()},e);try{let e=await fetch(typeof t==`string`||t instanceof Request?t:t.toString(),{...n,signal:i.signal});return clearTimeout(a),e}catch(e){throw r.warn(`[fetchWithTimeout] Fetch error: `,e),clearTimeout(a),e}},i=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var a=class{constructor(e){this.executeRequests=!0,this.sdkKey=e.sdkKey,this.logger=e.logger,this.sdkIdentity=e.sdkIdentity,this.metaContext=e.metaContext,this.url=e.urlFactory(`client/telemetry/v1`,e.baseUrl)}async report({context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r}){if(!this.executeRequests)return{success:!1,fatalError:!0};let i={clientSdkKey:this.sdkKey,metaContext:{sdkName:this.sdkIdentity.sdkName,sdkVersion:this.sdkIdentity.sdkVersion,appName:this.metaContext.appName,appVersion:this.metaContext.appVersion},context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r};if(this.isReportEmpty(i))return{success:!0,fatalError:!1};let a=await this.sendReport(i);return a.fatalError&&(this.executeRequests=!1),a}isReportEmpty(e){return t(e.discreteEvents)&&t(e.aggregatedEvents)&&n(e.droppedEvents)}async sendReport(e){try{let t=await r(5e3,this.url,{method:`POST`,body:JSON.stringify(e),keepalive:!0},this.logger),n=this.isStatusFatal(t.status);return n&&this.logger.warn(`[EventReporter] Received a fatal status response (${t.status}) from the telemetry endpoint. No more telemetry data will be sent.`),{success:t.ok,fatalError:n}}catch(e){let t=i(e);return this.logger.warn(`[EventReporter] Error attempting to send telemetry data: ${e}`,{error:e}),{success:!1,fatalError:t}}}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}},o=class{aggregate(e){if(e.events.length==0)return[];let t=new Map;for(let n of e.events){let e=JSON.stringify(n),r=t.get(e)?.count||0;t.set(e,{event:n,count:r+1})}return Array.from(t).map(([,t])=>({startTime:e.startTime,endTime:e.endTime,count:t.count,event:t.event}))}},s=class{constructor(e){this._events=[],this._droppedEventCount=0,this.limit=e??1e3}get events(){return this._events}get reachedLimit(){return this._events.length>=this.limit}get droppedEventCount(){return this._droppedEventCount}push(...e){this.startTime||=new Date;let t=Math.max(0,e.length-this.limit),n=e.slice(t,e.length);if(this._droppedEventCount+=t,this._events.length+n.length>this.limit){let e=this._events.length+n.length-this.limit;this._events.splice(0,e),this._droppedEventCount+=e}return this._events.push(...n)}takeSnapshot(){let e=new Date,t=this.startTime??e,n=this._events.splice(0),r=this._droppedEventCount;return this.startTime=void 0,this._droppedEventCount=0,{startTime:t,endTime:e,events:n,droppedCount:r}}clear(){this._events=[],this.startTime=void 0,this._droppedEventCount=0}},c=class{constructor(e){this.aggregator=new o,this.collectEvents=!0,this.started=!1,this.logger=e.logger,this.evaluationEventQueue=new s(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4,this.initialFlushIntervalDelay=e.initialFlushIntervalDelay??5e3}start(){this.started||!this.collectEvents||(this.started=!0,this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.initialFlushIntervalDelay))}async flushAndScheduleNext(){if(!this.collectEvents)return;let e;try{e=await this.flush()}catch(t){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events: `,t),e={success:!1,fatalError:!1}}e.fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.collectEvents&&(this.cancelScheduledFlush(),this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay))}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout);try{await this.flush()}catch(e){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events during close: `,e)}this.evaluationEventQueue.clear()}dispose(){this.close()}},l=class{constructor(e){this.valueIdGenerator=e,this.valueIdGenerator=e}async process(t){let n=await Promise.all(t.events.map(async t=>({...t,defaultValue:await e(t.defaultValue,this.valueIdGenerator),evaluatedValue:await e(t.evaluatedValue,this.valueIdGenerator)})));return{...t,events:n}}},u=class{constructor(){this.countsByKindSample=new Map,this.countBeyondSampleLimit=0}record(e){return this.startTime??=new Date,this.add(e,1)}absorb(e){for(let t of e)(this.startTime===void 0||t.startTime<this.startTime)&&(this.startTime=t.startTime),this.add(t.event.kindSample,t.count)}add(e,t){if(e!==void 0){let n=this.countsByKindSample.get(e);if(n!==void 0)return this.countsByKindSample.set(e,n+t),`known-kind-sample`;if(this.countsByKindSample.size<20)return this.countsByKindSample.set(e,t),`new-kind-sample`}let n=this.countBeyondSampleLimit===0;return this.countBeyondSampleLimit+=t,n?`first-beyond-sample-limit`:`beyond-sample-limit`}takeSnapshot(){let e=new Date,t=this.startTime??e,n=(n,r)=>({startTime:t,endTime:e,count:n,event:{reason:`invalid-context-kind`,kindSample:r}}),r=Array.from(this.countsByKindSample,([e,t])=>n(t,e)),i=this.countBeyondSampleLimit>0?[...r,n(this.countBeyondSampleLimit)]:r;return this.clear(),i}clear(){this.countsByKindSample.clear(),this.countBeyondSampleLimit=0,this.startTime=void 0}},d=class extends c{constructor(e){super(e),this.invalidContextSubmissions=new u,this.reporter=new a(e),this.evaluationEventSnapshotPreprocessor=new l(e.valueIdGenerator)}async updateContext(e){this.cancelScheduledFlush(),await this.flush(),this._context=e,await this.flushAndScheduleNext()}evaluatedConfig(e){this.collectEvents&&this.evaluationEventQueue.push(e)}recordInvalidContext(e){this.invalidContextSubmissions.record(e)}absorbInvalidContextSubmissions(e){this.invalidContextSubmissions.absorb(e)}async forceFlush(){this.cancelScheduledFlush(),await this.flushAndScheduleNext()}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e),invalidContext:this.invalidContextSubmissions.takeSnapshot()},droppedEvents:{evaluatedConfig:e.droppedCount}})}};let f=(e,t)=>new URL(e,t?.toString()),p=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},m=Math.ceil(128/Math.log2(62)),h=new TextEncoder,g=async e=>{if(typeof crypto>`u`||crypto.subtle==null)return;let t=await crypto.subtle.digest(`SHA-256`,h.encode(e?.toString()??``));return p(new Uint8Array(t,0,16),m)},_,v=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),y=e=>{try{self.postMessage(e)}catch{self.postMessage(v(e.payload.level,e.payload.message))}},b={debug:function(e,...t){y(v(`debug`,e,t))},info:function(e,...t){y(v(`info`,e,t))},warn:function(e,...t){y(v(`warn`,e,t))},error:function(e,...t){y(v(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!_){b.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(b.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:if(_){b.warn(`[TelemetryWorker] Received a duplicate Initialize event, ignoring it`);break}_=new d({...t.payload,baseUrl:f(t.payload.baseUrl),urlFactory:f,valueIdGenerator:g,logger:b}),_.start();break;case`EvaluatedConfigEvent`:_?.evaluatedConfig(t.payload);break;case`InvalidContextSubmissions`:_?.absorbInvalidContextSubmissions(t.payload.entries);break;case`UpdateContext`:_?.updateContext(t.payload.context);break;case`Flush`:_?.forceFlush();break;case`Close`:(_?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"],{type:`application/javascript`})))}catch(e){this.turnOff(`[WebWorkerTelemetryClient] Telemetry is off because the telemetry Web Worker could not be created: `,e);return}}turnOff(e,...t){this.turnedOff=!0,this.pendingEvaluations.length=0,this.logger.warn(e,...t)}startWorker(){if(this.worker||this.turnedOff)return this.worker;let e=this.createWorkerOrTurnOff();if(e){e.onmessage=e=>{this.handleWorkerEvent(e.data)},e.postMessage(this.initializeMessage),this.worker=e;try{document.addEventListener(`visibilitychange`,this.visibilityHandler)}catch(e){this.logger.warn(`[TelemetryEventCollector] Could not configure 'visibilitychange' listener: `,e)}for(let t of this.pendingEvaluations)e.postMessage(t);return this.pendingEvaluations.length=0,this.forwardInvalidContextSubmissions(e),e}}forwardInvalidContextSubmissions(e){if(!e)return;let t=this.pendingInvalidContextSubmissions.takeSnapshot();if(t.length===0)return;let n={type:`InvalidContextSubmissions`,payload:{entries:t}};e.postMessage(n)}async updateContext(e){var t=this,n;if(t.closePromise)return;let r={type:`UpdateContext`,payload:{context:e}};(n=t.startWorker())==null||n.postMessage(r)}evaluatedConfig(e){if(this.turnedOff)return;let t={type:`EvaluatedConfigEvent`,payload:this.sanitizeEvaluatedConfigEvent(e)};if(this.worker){this.worker.postMessage(t);return}this.pendingEvaluations.length>=this.pendingEvaluationLimit&&this.pendingEvaluations.shift(),this.pendingEvaluations.push(t)}recordInvalidContext(e){this.pendingInvalidContextSubmissions.record(e),this.forwardInvalidContextSubmissions(this.worker)}sanitizeEvaluatedConfigEvent(t){return e(e({},t),{},{defaultValue:u({value:t.defaultValue,type:t.type}),evaluatedValue:u({value:t.evaluatedValue,valueId:t.evaluatedValueId,type:t.type})})}handleWorkerEvent(e){var t,n;if(e.type===`Closed`){this.finishClose();return}if(!((t=e.payload)!=null&&t.level)||!((n=e.payload)!=null&&n.message))return;let{level:r,message:i,args:a}=e.payload;switch(r){case`debug`:this.logger.debug(i,...a);break;case`info`:this.logger.info(i,...a);break;case`warn`:this.logger.warn(i,...a);break;case`error`:this.logger.error(i,...a);break}}flush(){var e;(e=this.worker)==null||e.postMessage({type:`Flush`})}close(){return this.closePromise?this.closePromise:this.performClose()}performClose(){let e=this.worker;if(!e)return this.pendingEvaluations.length=0,this.closePromise=Promise.resolve(),this.closePromise;try{document.removeEventListener(`visibilitychange`,this.visibilityHandler)}catch(e){this.logger.warn(`[WebWorkerTelemetryClient] Could not remove 'visibilitychange' listener: `,e)}return this.closePromise=new Promise(t=>{this.closeResolve=t,this.closeTimer=setTimeout(()=>{this.logger.warn(`[WebWorkerTelemetryClient] Timed out waiting for the telemetry worker to close. Terminating the worker.`),this.finishClose()},this.workerCloseTimeout),e.postMessage({type:`Close`})}),this.closePromise}finishClose(){var e,t;clearTimeout(this.closeTimer),this.closeTimer=void 0,(e=this.worker)==null||e.terminate(),(t=this.closeResolve)==null||t.call(this)}};const p=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},m=Math.ceil(128/Math.log2(62)),h=new TextEncoder,g=async e=>{var t;if(typeof crypto>`u`||crypto.subtle==null)return;let n=await crypto.subtle.digest(`SHA-256`,h.encode((t=e==null?void 0:e.toString())==null?``:t));return p(new Uint8Array(n,0,16),m)},_=(e,n,r)=>i.from(({clientSdkKey:e,baseUrl:r,logger:i,metadata:a})=>new f({sdkKey:e,sdkIdentity:{sdkName:n.sdkName,sdkVersion:n.sdkVersion},metaContext:{appName:a==null?void 0:a.appName,appVersion:a==null?void 0:a.appVersion},logger:i,baseUrl:r,urlFactory:t,valueIdGenerator:g}),e,n,r);var v=class{constructor(e){this.client=e,this.registrations=[]}on(e,t){this.client.on(e,t),this.registrations.push({event:e,handler:t})}registerHooks(e){for(let[t,n]of Object.entries(e==null?{}:e)){let e=Array.isArray(n)?n:[n];for(let n of e)typeof n==`function`&&this.on(t,n)}}removeAll(){for(let{event:e,handler:t}of this.registrations)this.client.off(e,t);this.registrations=[]}};const y=(e,t)=>{if(Object.is(e,t))return!0;if(typeof e!=`object`||typeof t!=`object`||e===null||t===null||Object.getPrototypeOf(e)!==Object.getPrototypeOf(t))return!1;if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>y(e,t[n]));if(!b(e)||!b(t))return!1;let n=Object.keys(e),r=Object.keys(t);return n.length===r.length&&n.every(n=>Object.prototype.hasOwnProperty.call(t,n)&&y(e[n],t[n]))},b=e=>{let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},x=(e,t)=>e.isInitializing?`none`:e.isReady?t!==void 0&&!y(t,e.context)?`updateContext`:`none`:`initialize`,S=o.createContext({status:`loading`});var C=class{decorateMessage(e){return`[ConfigDirector:nextjs-sdk] ${e}`}};const w=e=>r(e,new C),T=e=>`client`in e&&e.client!==void 0,E=e=>e.isReady?`ready`:`default`;var D=class extends s{constructor(e){super(e);let t=T(e)?e.client:n();this.ownsClient=t===void 0,this.client=t,this.state=t?{client:t,status:t.isReady?`ready`:`loading`}:{status:`loading`}}buildClient(){var e;let t=this.props;return _(t.sdkKey,{sdkName:`nextjs-sdk`,sdkVersion:`1.11.0`},{connection:{url:t.url,timeout:t.timeout,mode:t.mode,pollingInterval:t.pollingInterval,values:t.values},metadata:{appName:t.appName,appVersion:t.appVersion},logger:w((e=t.logLevel)==null?`warn`:e),hooks:t.hooks})}async componentDidMount(){var e=this;let t=e.client;e.ownsClient&&(t=e.buildClient(),e.client=t,e.setState({client:t})),t&&(e.handlers=new v(t),e.handlers.on(`configsUpdated`,()=>{e.setState({updatedAt:new Date})}),e.handlers.on(`clientReady`,()=>{e.setState({status:`ready`})}),e.ownsClient||e.handlers.registerHooks(e.props.hooks),await e.connect(t,e.props.context))}async connect(e,t){var n=this;switch(x(e,t)){case`initialize`:await e.initialize(t);break;case`updateContext`:n.setState({status:`loading`}),await e.updateContext(t);break;case`none`:return}n.client===e&&n.setState({status:E(e)})}async componentDidUpdate(e){var t=this;if(T(e)&&T(t.props)&&e.client!==t.props.client&&w(`warn`).warn(`The client prop of ConfigDirectorProvider changed after it mounted and is ignored. Remount the provider, for example with a new key, to use another client.`),!y(e.context,t.props.context)){var n;let e=t.client;if(!e)return;t.setState({status:`loading`}),await e.updateContext((n=t.props.context)==null?{}:n),t.client===e&&t.setState({status:E(e)})}}componentWillUnmount(){var e;if((e=this.handlers)==null||e.removeAll(),this.handlers=void 0,this.ownsClient){var t;(t=this.client)==null||t.dispose(),this.client=void 0}}render(){return l(S.Provider,{value:e(e({},this.state),{},{initialConfigs:this.props.initialConfigs}),children:this.props.children})}},O=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorNextContextError`,Object.setPrototypeOf(this,e.prototype)}};const k=()=>new O(`The ConfigDirector client was not found in the React context. Make sure the component using this hook is inside a <ConfigDirectorProvider>.`),A=(e,t)=>{var n,r;let i=c(S);if(!i)throw k();let o=(n=i.initialConfigs)==null?void 0:n[e];return{value:(r=i.client)!=null&&r.isReady?i.client.getValue(e,t):o?a(o,t).parsedValue:t,readyStatus:i.status,loading:i.status===`loading`}},j=()=>{let e=c(S);if(!e)throw k();return{updateContext:async t=>{var n;await((n=e.client)==null?void 0:n.updateContext(t))}}},M=()=>{let e=c(S);if(!(e!=null&&e.client))throw k();return{client:e.client}},N=()=>{let e=c(S);if(!e)throw k();return{readyStatus:e.status,loading:e.status===`loading`}};export{O as ConfigDirectorNextContextError,D as ConfigDirectorProvider,w as createConsoleLogger,M as useClient,N as useConfigDirectorStatus,A as useConfigValue,j as useContext};
3
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["createJsSdkLogger","useReactContext"],"sources":["../../../shared/src/telemetry/utils.ts","../../../js-browser-client/src/telemetry/WebWorkerTelemetryClient.ts","../../../shared/src/base62-encoder.ts","../../../shared/src/value-id.ts","../../../js-browser-client/src/telemetry/value-id-generator.ts","../../../js-browser-client/src/BrowserConfigDirectorClient.ts","../../../js-client-core/src/clientHandlers.ts","../../../shared/src/deepEqual.ts","../../../js-client-core/src/mountAction.ts","../../src/client/context.tsx","../../src/client/logger.ts","../../src/client/ConfigDirectorProvider.tsx","../../src/client/errors.ts","../../src/client/hooks.tsx"],"sourcesContent":["import type { ConfigType, ConfigValueType } from \"../types\";\nimport type { ValueIdGenerator, DroppedEvents } from \"./types\";\n\nconst CONFIG_VALUE_MAX_LENGTH = 500;\n\nexport type TelemetryValue = {\n value?: string;\n valueId?: string;\n type?: ConfigType;\n};\n\nexport type TelemetryEvaluationValue<TV extends ConfigValueType> = {\n value: TV;\n valueId?: string | null | undefined;\n type?: ConfigType;\n};\n\nexport const compactTelemetryValue = async (\n tv: TelemetryValue,\n valueIdGenerator: ValueIdGenerator,\n): Promise<TelemetryValue> => {\n if (tv.valueId) {\n return { valueId: tv.valueId };\n }\n if (tv.value) {\n if (tv.value.length <= CONFIG_VALUE_MAX_LENGTH && tv.type != \"json\") {\n return { value: tv.value };\n }\n\n return { valueId: await valueIdGenerator(tv.value) };\n }\n\n return tv;\n};\n\nexport const mapToTelemetryValue = <TV extends ConfigValueType>(\n ev: TelemetryEvaluationValue<TV>,\n): TelemetryValue => {\n if (ev.type === \"json\" || (ev.type == null && typeof ev.value === \"object\")) {\n if (ev.valueId) {\n return { valueId: ev.valueId, type: \"json\" };\n }\n try {\n const json = JSON.stringify(ev.value);\n return { value: json, type: \"json\" };\n } catch {\n return { value: ev.value.toString(), type: \"json\" };\n }\n }\n\n const stringValue = ev.value?.toString();\n if (stringValue && stringValue.length <= CONFIG_VALUE_MAX_LENGTH) {\n return { value: stringValue };\n }\n\n return ev.valueId ? { valueId: ev.valueId } : { value: stringValue };\n};\n\nexport const djb2Hash = (data: string): string => {\n const hash = djb2(new TextEncoder().encode(data));\n return hash.toString(16).padStart(8, \"0\");\n};\n\nconst djb2 = (bytes: Uint8Array): number => {\n let hash = 5381;\n for (let i = 0; i < bytes.length; i++) {\n hash = (hash << 5) + hash + (bytes[i] ?? 0);\n hash = hash >>> 0;\n }\n return hash;\n};\n\nexport const isEventListEmpty = <T extends Record<string | symbol, any[]>>(eventList: T): boolean => {\n const keys = Object.keys(eventList);\n if (keys.length == 0) {\n return true;\n }\n\n for (const key of keys) {\n if ((eventList[key]?.length ?? 0) > 0) {\n return false;\n }\n }\n\n return true;\n};\n\nexport const isDroppedEventsEmpty = (droppedEvents?: DroppedEvents): boolean => {\n if (!droppedEvents) {\n return true;\n }\n const keys = Object.keys(droppedEvents);\n if (keys.length == 0) {\n return true;\n }\n\n for (const key of keys) {\n if ((droppedEvents[key] ?? 0) > 0) {\n return false;\n }\n }\n\n return true;\n};\n","import { type TelemetryEventCollectorOptions } from \"@shared/telemetry/TelemetryEventCollector\";\nimport type { ConfigDirectorContext, ConfigDirectorLogger, ConfigValueType } from \"@js-client-core/types\";\nimport type { TelemetryClient, EvaluatedConfigEvent } from \"@js-client-core/telemetry\";\nimport type {\n TelemetryCloseEvent,\n TelemetryEvaluatedConfigEvent,\n TelemetryFlushEvent,\n TelemetryInitializeEvent,\n TelemetryUpdateContextEvent,\n TelemetryWorkerResponseEvent,\n} from \"./types\";\nimport type { TelemetryValue } from \"@shared/telemetry/utils\";\nimport { mapToTelemetryValue } from \"@shared/telemetry/utils\";\n\nconst DEFAULT_WORKER_CLOSE_TIMEOUT = 6_000;\n\nexport type WebWorkerTelemetryClientOptions = TelemetryEventCollectorOptions & {\n workerCloseTimeout?: number;\n};\n\nexport class WebWorkerTelemetryClient implements TelemetryClient {\n private readonly logger: ConfigDirectorLogger;\n private readonly initializeMessage: TelemetryInitializeEvent;\n private worker: Worker | undefined;\n private turnedOff = false;\n private readonly pendingEvaluations: TelemetryEvaluatedConfigEvent[] = [];\n private readonly pendingEvaluationLimit: number;\n private closePromise: Promise<void> | undefined;\n private closeResolve: (() => void) | undefined;\n private closeTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly workerCloseTimeout: number;\n private readonly visibilityHandler: () => void;\n\n constructor(options: WebWorkerTelemetryClientOptions) {\n this.logger = options.logger;\n this.workerCloseTimeout = options.workerCloseTimeout ?? DEFAULT_WORKER_CLOSE_TIMEOUT;\n this.pendingEvaluationLimit = options.evaluationQueueLimit ?? 1_000;\n\n this.initializeMessage = {\n type: \"Initialize\",\n payload: {\n sdkKey: options.sdkKey,\n sdkIdentity: options.sdkIdentity,\n metaContext: options.metaContext,\n baseUrl: options.baseUrl.toString(),\n evaluationQueueLimit: this.pendingEvaluationLimit,\n initialFlushIntervalDelay: options.initialFlushIntervalDelay ?? 5_000,\n flushIntervalDelay: options.flushIntervalDelay ?? 30_000,\n },\n };\n\n this.visibilityHandler = () => {\n if (document.visibilityState === \"hidden\") {\n this.flush();\n }\n };\n }\n\n private createWorkerOrTurnOff(): Worker | undefined {\n if (typeof Worker === \"undefined\") {\n this.turnOff(\n \"[WebWorkerTelemetryClient] Telemetry is off because Web Workers are not available in this environment.\",\n );\n return undefined;\n }\n try {\n return new Worker(new URL(\"./worker.ts\", import.meta.url), { type: \"module\" });\n } catch (error) {\n this.turnOff(\n \"[WebWorkerTelemetryClient] Telemetry is off because the telemetry Web Worker could not be created: \",\n error,\n );\n return undefined;\n }\n }\n\n private turnOff(warning: string, ...details: unknown[]) {\n this.turnedOff = true;\n this.pendingEvaluations.length = 0;\n this.logger.warn(warning, ...details);\n }\n\n private startWorker(): Worker | undefined {\n if (this.worker || this.turnedOff) {\n return this.worker;\n }\n const worker = this.createWorkerOrTurnOff();\n if (!worker) {\n return undefined;\n }\n worker.onmessage = (message: MessageEvent<TelemetryWorkerResponseEvent>) => {\n this.handleWorkerEvent(message.data);\n };\n worker.postMessage(this.initializeMessage);\n this.worker = worker;\n\n try {\n document.addEventListener(\"visibilitychange\", this.visibilityHandler);\n } catch (error) {\n this.logger.warn(\"[TelemetryEventCollector] Could not configure 'visibilitychange' listener: \", error);\n }\n\n for (const evaluation of this.pendingEvaluations) {\n worker.postMessage(evaluation);\n }\n this.pendingEvaluations.length = 0;\n return worker;\n }\n\n public async updateContext(value: ConfigDirectorContext | undefined) {\n if (this.closePromise) {\n return;\n }\n const updateContextMessage: TelemetryUpdateContextEvent = {\n type: \"UpdateContext\",\n payload: {\n context: value,\n },\n };\n this.startWorker()?.postMessage(updateContextMessage);\n }\n\n public evaluatedConfig<T extends ConfigValueType>(event: EvaluatedConfigEvent<T>): void {\n if (this.turnedOff) {\n return;\n }\n const evaluatedConfigMessage: TelemetryEvaluatedConfigEvent = {\n type: \"EvaluatedConfigEvent\",\n payload: this.sanitizeEvaluatedConfigEvent(event),\n };\n if (this.worker) {\n this.worker.postMessage(evaluatedConfigMessage);\n return;\n }\n if (this.pendingEvaluations.length >= this.pendingEvaluationLimit) {\n this.pendingEvaluations.shift();\n }\n this.pendingEvaluations.push(evaluatedConfigMessage);\n }\n\n private sanitizeEvaluatedConfigEvent<T extends ConfigValueType>(\n event: EvaluatedConfigEvent<T>,\n ): EvaluatedConfigEvent<TelemetryValue> {\n return {\n ...event,\n defaultValue: mapToTelemetryValue({ value: event.defaultValue, type: event.type }),\n evaluatedValue: mapToTelemetryValue({\n value: event.evaluatedValue,\n valueId: event.evaluatedValueId,\n type: event.type,\n }),\n };\n }\n\n private handleWorkerEvent(event: TelemetryWorkerResponseEvent) {\n if (event.type === \"Closed\") {\n this.finishClose();\n return;\n }\n if (!event.payload?.level || !event.payload?.message) {\n return;\n }\n const { level, message, args } = event.payload;\n\n switch (level) {\n case \"debug\":\n this.logger.debug(message, ...args);\n break;\n case \"info\":\n this.logger.info(message, ...args);\n break;\n case \"warn\":\n this.logger.warn(message, ...args);\n break;\n case \"error\":\n this.logger.error(message, ...args);\n break;\n }\n }\n\n private flush() {\n const flushMessage: TelemetryFlushEvent = {\n type: \"Flush\",\n };\n this.worker?.postMessage(flushMessage);\n }\n\n public close(): Promise<void> {\n if (this.closePromise) {\n return this.closePromise;\n }\n\n return this.performClose();\n }\n\n private performClose(): Promise<void> {\n const worker = this.worker;\n if (!worker) {\n this.pendingEvaluations.length = 0;\n this.closePromise = Promise.resolve();\n return this.closePromise;\n }\n try {\n document.removeEventListener(\"visibilitychange\", this.visibilityHandler);\n } catch (error) {\n this.logger.warn(\"[WebWorkerTelemetryClient] Could not remove 'visibilitychange' listener: \", error);\n }\n this.closePromise = new Promise<void>((resolve) => {\n this.closeResolve = resolve;\n this.closeTimer = setTimeout(() => {\n this.logger.warn(\n \"[WebWorkerTelemetryClient] Timed out waiting for the telemetry worker to close. Terminating the worker.\",\n );\n this.finishClose();\n }, this.workerCloseTimeout);\n const closeMessage: TelemetryCloseEvent = { type: \"Close\" };\n worker.postMessage(closeMessage);\n });\n return this.closePromise;\n }\n\n private finishClose() {\n clearTimeout(this.closeTimer);\n this.closeTimer = undefined;\n this.worker?.terminate();\n this.closeResolve?.();\n }\n}\n","const BASE62 = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n\nexport const toBase62 = (buf: Uint8Array, length: number): string => {\n const ZERO = BigInt(0);\n const BASE = BigInt(62);\n const hex = Array.from(buf)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n let n = BigInt(\"0x\" + hex);\n let result = \"\";\n while (n > ZERO) {\n result = BASE62[Number(n % BASE)] + result;\n n /= BASE;\n }\n return result.padStart(length, \"0\");\n};\n","export const DIGEST_BYTES = 16;\nexport const BASE62_LENGTH = Math.ceil((DIGEST_BYTES * 8) / Math.log2(62));\n","import { toBase62 } from \"@shared/base62-encoder\";\nimport { DIGEST_BYTES, BASE62_LENGTH } from \"@shared/value-id\";\n\nconst encoder = new TextEncoder();\n\nexport const generateValueId = async (\n v: string | number | boolean | null | undefined,\n): Promise<string | undefined> => {\n if (typeof crypto === \"undefined\" || crypto.subtle == null) {\n return undefined;\n }\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encoder.encode(v?.toString() ?? \"\"));\n return toBase62(new Uint8Array(hashBuffer, 0, DIGEST_BYTES), BASE62_LENGTH);\n};\n","import {\n type ConfigDirectorClientOptions,\n type ConfigDirectorClient,\n type IdentifyingSdkOptions,\n createDefaultLogger,\n} from \"@js-client-core/index\";\nimport { WebWorkerTelemetryClient } from \"./telemetry/WebWorkerTelemetryClient\";\nimport { DefaultConfigDirectorClient } from \"@js-client-core/DefaultConfigDirectorClient\";\nimport { defaultUrlFactory, parseUrl } from \"@shared/url\";\nimport { CLIENT_BASE_URL } from \"@shared/constants\";\nimport { generateValueId } from \"./telemetry/value-id-generator\";\n\nexport const createBrowserClient = (\n clientSdkKey: string,\n sdkOptions: IdentifyingSdkOptions,\n clientOptions?: ConfigDirectorClientOptions,\n): ConfigDirectorClient => {\n const logger = clientOptions?.logger ?? createDefaultLogger();\n const baseUrl = parseUrl(clientOptions?.connection?.url) ?? CLIENT_BASE_URL;\n const telemetryClient = new WebWorkerTelemetryClient({\n sdkKey: clientSdkKey,\n sdkIdentity: {\n sdkName: sdkOptions.sdkName,\n sdkVersion: sdkOptions.sdkVersion,\n },\n metaContext: {\n appName: clientOptions?.metadata?.appName,\n appVersion: clientOptions?.metadata?.appVersion,\n },\n logger: logger,\n baseUrl,\n urlFactory: defaultUrlFactory,\n valueIdGenerator: generateValueId,\n });\n\n return new DefaultConfigDirectorClient(telemetryClient, clientSdkKey, sdkOptions, {\n ...clientOptions,\n logger,\n });\n};\n","import type { ClientEvents, ClientHooks, ConfigDirectorClient } from \"./types\";\n\ntype Registration = { event: keyof ClientEvents; handler: (payload: any) => void };\n\nexport class ClientHandlers {\n private registrations: Registration[] = [];\n\n constructor(private readonly client: ConfigDirectorClient) {}\n\n public on<T extends keyof ClientEvents>(event: T, handler: (payload: ClientEvents[T]) => void) {\n this.client.on(event, handler);\n this.registrations.push({ event, handler });\n }\n\n public registerHooks(hooks: ClientHooks | undefined) {\n for (const [event, handlerOrHandlers] of Object.entries(hooks ?? {})) {\n const handlers = Array.isArray(handlerOrHandlers) ? handlerOrHandlers : [handlerOrHandlers];\n for (const handler of handlers) {\n if (typeof handler === \"function\") {\n this.on(event as keyof ClientEvents, handler as (payload: unknown) => void);\n }\n }\n }\n }\n\n public removeAll() {\n for (const { event, handler } of this.registrations) {\n this.client.off(event, handler);\n }\n this.registrations = [];\n }\n}\n","export const deepEqual = (left: unknown, right: unknown): boolean => {\n if (Object.is(left, right)) {\n return true;\n }\n if (typeof left !== \"object\" || typeof right !== \"object\" || left === null || right === null) {\n return false;\n }\n if (Object.getPrototypeOf(left) !== Object.getPrototypeOf(right)) {\n return false;\n }\n if (left instanceof Date && right instanceof Date) {\n return left.getTime() === right.getTime();\n }\n if (Array.isArray(left) && Array.isArray(right)) {\n return left.length === right.length && left.every((item, index) => deepEqual(item, right[index]));\n }\n if (!isPlainObject(left) || !isPlainObject(right)) {\n return false;\n }\n const leftKeys = Object.keys(left);\n const rightKeys = Object.keys(right);\n return (\n leftKeys.length === rightKeys.length &&\n leftKeys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && deepEqual(left[key], right[key]))\n );\n};\n\nconst isPlainObject = (value: object): value is Record<string, unknown> => {\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n","import type { ConfigDirectorClient, ConfigDirectorContext } from \"./types\";\nimport { deepEqual } from \"@shared/deepEqual\";\n\nexport type MountAction = \"initialize\" | \"updateContext\" | \"none\";\n\nexport const decideMountAction = (\n client: ConfigDirectorClient,\n context: ConfigDirectorContext | undefined,\n): MountAction => {\n if (client.isInitializing) {\n return \"none\";\n }\n if (!client.isReady) {\n return \"initialize\";\n }\n if (context !== undefined && !deepEqual(context, client.context)) {\n return \"updateContext\";\n }\n return \"none\";\n};\n","\"use client\";\n\nimport React from \"react\";\nimport type { ConfigDirectorContextData } from \"./types\";\n\nconst createReactContext = () => React.createContext<ConfigDirectorContextData>({ status: \"loading\" });\nexport const reactContext = createReactContext();\n","import type {\n ConfigDirectorLogMessageDecorator,\n ConfigDirectorLoggingLevel,\n ConfigDirectorLogger,\n} from \"@js-browser-client/index\";\nimport { createDefaultLogger as createJsSdkLogger } from \"@js-browser-client/index\";\n\nclass LogMessageDecorator implements ConfigDirectorLogMessageDecorator {\n decorateMessage(message: string): string {\n return `[ConfigDirector:nextjs-sdk] ${message}`;\n }\n}\n\nexport const createConsoleLogger = (level: ConfigDirectorLoggingLevel): ConfigDirectorLogger => {\n return createJsSdkLogger(level, new LogMessageDecorator());\n};\n","\"use client\";\n\nimport { Component, type PropsWithChildren } from \"react\";\nimport { createBrowserClient, type ConfigDirectorClient, type ConfigDirectorContext } from \"@js-browser-client/index\";\nimport { ClientHandlers } from \"@js-client-core/clientHandlers\";\nimport { readInstalledTestClient } from \"@js-client-core/installedTestClient\";\nimport { decideMountAction } from \"@js-client-core/mountAction\";\nimport { deepEqual } from \"@shared/deepEqual\";\nimport { reactContext } from \"./context\";\nimport { createConsoleLogger } from \"./logger\";\nimport type {\n ConfigDirectorClientProviderProps,\n ConfigDirectorProviderOptions,\n ConfigDirectorProviderState,\n} from \"./types\";\n\nconst hasGivenClient = (props: ConfigDirectorClientProviderProps): props is { client: ConfigDirectorClient } =>\n \"client\" in props && props.client !== undefined;\n\n/**\n * Initializes the ConfigDirector browser client and provides it to all descendant hooks.\n *\n * Place this in your root layout, wrapping your application. In most cases prefer the\n * `ConfigDirectorProvider` exported from `@configdirector/nextjs-sdk/server` — it is a React\n * Server Component that populates `initialConfigs` automatically, ensuring Client Components\n * render the correct values during SSR without any extra wiring.\n *\n * This component itself is a Client Component, so if you use it directly (rather than through\n * the server provider) any `sdkKey` sourced from `process.env` must use the `NEXT_PUBLIC_`\n * prefix — Next.js only exposes prefixed variables to code that runs in the browser.\n *\n * Given a `client` prop, or while a test client is installed from\n * `@configdirector/nextjs-sdk/client/testing`, the provider provides that client from its first\n * render instead of building one, and never disposes it.\n */\nexport class ConfigDirectorProvider extends Component<\n PropsWithChildren<ConfigDirectorClientProviderProps>,\n ConfigDirectorProviderState\n> {\n private client: ConfigDirectorClient | undefined;\n private readonly ownsClient: boolean;\n private handlers: ClientHandlers | undefined;\n\n constructor(props: PropsWithChildren<ConfigDirectorClientProviderProps>) {\n super(props);\n const givenClient = hasGivenClient(props) ? props.client : readInstalledTestClient();\n this.ownsClient = givenClient === undefined;\n this.client = givenClient;\n this.state = givenClient\n ? { client: givenClient, status: givenClient.isReady ? \"ready\" : \"loading\" }\n : { status: \"loading\" };\n }\n\n private buildClient(): ConfigDirectorClient {\n const options = this.props as ConfigDirectorProviderOptions;\n return createBrowserClient(\n options.sdkKey,\n { sdkName: \"nextjs-sdk\", sdkVersion: \"__VERSION__\" },\n {\n connection: {\n url: options.url,\n timeout: options.timeout,\n mode: options.mode,\n pollingInterval: options.pollingInterval,\n },\n metadata: { appName: options.appName, appVersion: options.appVersion },\n logger: createConsoleLogger(options.logLevel ?? \"warn\"),\n hooks: options.hooks,\n },\n );\n }\n\n override async componentDidMount(): Promise<void> {\n let client = this.client;\n if (this.ownsClient) {\n client = this.buildClient();\n this.client = client;\n this.setState({ client });\n }\n if (!client) {\n return;\n }\n\n this.handlers = new ClientHandlers(client);\n this.handlers.on(\"configsUpdated\", () => {\n this.setState({ updatedAt: new Date() });\n });\n this.handlers.on(\"clientReady\", () => {\n this.setState({ status: \"ready\" });\n });\n if (!this.ownsClient) {\n this.handlers.registerHooks(this.props.hooks);\n }\n await this.connect(client, this.props.context);\n }\n\n private async connect(client: ConfigDirectorClient, context: ConfigDirectorContext | undefined): Promise<void> {\n switch (decideMountAction(client, context)) {\n case \"initialize\":\n await client.initialize(context);\n break;\n case \"updateContext\":\n this.setState({ status: \"loading\" });\n await client.updateContext(context as ConfigDirectorContext);\n break;\n case \"none\":\n return;\n }\n if (this.client === client && !client.isReady) {\n this.setState({ status: \"default\" });\n }\n }\n\n override async componentDidUpdate(\n prevProps: PropsWithChildren<ConfigDirectorClientProviderProps>,\n ): Promise<void> {\n if (hasGivenClient(prevProps) && hasGivenClient(this.props) && prevProps.client !== this.props.client) {\n createConsoleLogger(\"warn\").warn(\n \"The client prop of ConfigDirectorProvider changed after it mounted and is ignored. Remount the provider, for example with a new key, to use another client.\",\n );\n }\n if (!deepEqual(prevProps.context, this.props.context)) {\n const client = this.client;\n if (!client) return;\n this.setState({ status: \"loading\" });\n await client.updateContext(this.props.context ?? {});\n if (this.client === client && !client.isReady) {\n this.setState({ status: \"default\" });\n }\n }\n }\n\n override componentWillUnmount(): void {\n this.handlers?.removeAll();\n this.handlers = undefined;\n if (this.ownsClient) {\n this.client?.dispose();\n }\n this.client = undefined;\n }\n\n override render() {\n return (\n <reactContext.Provider value={{ ...this.state, initialConfigs: this.props.initialConfigs }}>\n {this.props.children}\n </reactContext.Provider>\n );\n }\n}\n","export class ConfigDirectorNextContextError extends Error {\n public override readonly name: string = \"ConfigDirectorNextContextError\";\n\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, ConfigDirectorNextContextError.prototype);\n }\n}\n","\"use client\";\n\nimport { useContext as useReactContext } from \"react\";\nimport { reactContext } from \"./context\";\nimport type { ConfigDirectorContext, ConfigValueType } from \"@js-browser-client/index\";\nimport { parseConfigValue } from \"@shared/value-parser\";\nimport { ConfigDirectorNextContextError } from \"./errors\";\nimport type { ClientStatus } from \"./types\";\n\nconst noContextError = () =>\n new ConfigDirectorNextContextError(\n \"The ConfigDirector client was not found in the React context. \" +\n \"Make sure the component using this hook is inside a <ConfigDirectorProvider>.\",\n );\n\n/**\n * Returns the evaluated value of a config key.\n *\n * During SSR and before the browser client finishes initializing, returns the value from\n * `initialConfigs` (if provided to the provider) to avoid a flash of wrong content on hydration.\n * Once the browser client is ready, returns live-evaluated values and re-renders whenever configs\n * change.\n *\n * Must be used inside a `<ConfigDirectorProvider>`.\n */\nexport const useConfigValue = <T extends ConfigValueType>(\n key: string,\n defaultValue: T,\n): { value: T; readyStatus: ClientStatus; loading: boolean } => {\n const configDirectorReactContext = useReactContext(reactContext);\n if (!configDirectorReactContext) throw noContextError();\n\n // The client is undefined during SSR and briefly during the first client render before componentDidMount\n // fires. Fall through to initialConfigs in both cases so the rendered output matches the server HTML,\n // avoiding a hydration mismatch.\n const initialConfigState = configDirectorReactContext.initialConfigs?.[key];\n const value = configDirectorReactContext.client?.isReady\n ? configDirectorReactContext.client.getValue(key, defaultValue)\n : initialConfigState\n ? parseConfigValue(initialConfigState, defaultValue).parsedValue\n : defaultValue;\n\n return {\n value,\n readyStatus: configDirectorReactContext.status,\n loading: configDirectorReactContext.status === \"loading\",\n };\n};\n\n/**\n * Returns an `updateContext` function to update the user context on the browser client.\n * Triggers re-evaluation of all watched config values.\n *\n * Must be used inside a `<ConfigDirectorProvider>`.\n */\nexport const useContext = (): { updateContext: (context: ConfigDirectorContext) => Promise<void> } => {\n const configDirectorReactContext = useReactContext(reactContext);\n if (!configDirectorReactContext) throw noContextError();\n\n return {\n // client is undefined during SSR and briefly before componentDidMount; no-op until ready\n updateContext: async (context: ConfigDirectorContext) => {\n await configDirectorReactContext.client?.updateContext(context);\n },\n };\n};\n\n/**\n * Returns the raw browser client for advanced use cases.\n *\n * Must be used inside a `<ConfigDirectorProvider>`.\n */\nexport const useClient = () => {\n const configDirectorReactContext = useReactContext(reactContext);\n if (!configDirectorReactContext?.client) throw noContextError();\n return { client: configDirectorReactContext.client };\n};\n\n/**\n * Returns the current connection status of the browser client.\n *\n * - `\"loading\"` — client is initializing\n * - `\"ready\"` — client received configs from the server\n * - `\"default\"` — initialization timed out; hooks return default or initial values\n *\n * Must be used inside a `<ConfigDirectorProvider>`.\n */\nexport const useConfigDirectorStatus = (): { readyStatus: ClientStatus; loading: boolean } => {\n const configDirectorReactContext = useReactContext(reactContext);\n if (!configDirectorReactContext) throw noContextError();\n return {\n readyStatus: configDirectorReactContext.status,\n loading: configDirectorReactContext.status === \"loading\",\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["createJsSdkLogger","useReactContext"],"sources":["../../../shared/src/telemetry/utils.ts","../../../shared/src/telemetry/InvalidContextSubmissions.ts","../../../js-browser-client/src/telemetry/WebWorkerTelemetryClient.ts","../../../shared/src/base62-encoder.ts","../../../shared/src/value-id.ts","../../../js-browser-client/src/telemetry/value-id-generator.ts","../../../js-browser-client/src/BrowserConfigDirectorClient.ts","../../../js-client-core/src/clientHandlers.ts","../../../shared/src/deepEqual.ts","../../../js-client-core/src/mountAction.ts","../../src/client/context.tsx","../../src/client/logger.ts","../../src/client/ConfigDirectorProvider.tsx","../../src/client/errors.ts","../../src/client/hooks.tsx"],"sourcesContent":["import type { ConfigType, ConfigValueType } from \"../types\";\nimport type { ValueIdGenerator, DroppedEvents } from \"./types\";\n\nconst CONFIG_VALUE_MAX_LENGTH = 500;\n\nexport type TelemetryValue = {\n value?: string;\n valueId?: string;\n type?: ConfigType;\n};\n\nexport type TelemetryEvaluationValue<TV extends ConfigValueType> = {\n value: TV;\n valueId?: string | null | undefined;\n type?: ConfigType;\n};\n\nexport const compactTelemetryValue = async (\n tv: TelemetryValue,\n valueIdGenerator: ValueIdGenerator,\n): Promise<TelemetryValue> => {\n if (tv.valueId) {\n return { valueId: tv.valueId };\n }\n if (tv.value) {\n if (tv.value.length <= CONFIG_VALUE_MAX_LENGTH && tv.type != \"json\") {\n return { value: tv.value };\n }\n\n return { valueId: await valueIdGenerator(tv.value) };\n }\n\n return tv;\n};\n\nexport const mapToTelemetryValue = <TV extends ConfigValueType>(\n ev: TelemetryEvaluationValue<TV>,\n): TelemetryValue => {\n if (ev.type === \"json\" || (ev.type == null && typeof ev.value === \"object\")) {\n if (ev.valueId) {\n return { valueId: ev.valueId, type: \"json\" };\n }\n try {\n const json = JSON.stringify(ev.value);\n return { value: json, type: \"json\" };\n } catch {\n return { value: ev.value.toString(), type: \"json\" };\n }\n }\n\n const stringValue = ev.value?.toString();\n if (stringValue && stringValue.length <= CONFIG_VALUE_MAX_LENGTH) {\n return { value: stringValue };\n }\n\n return ev.valueId ? { valueId: ev.valueId } : { value: stringValue };\n};\n\nexport const djb2Hash = (data: string): string => {\n const hash = djb2(new TextEncoder().encode(data));\n return hash.toString(16).padStart(8, \"0\");\n};\n\nconst djb2 = (bytes: Uint8Array): number => {\n let hash = 5381;\n for (let i = 0; i < bytes.length; i++) {\n hash = (hash << 5) + hash + (bytes[i] ?? 0);\n hash = hash >>> 0;\n }\n return hash;\n};\n\nexport const isEventListEmpty = <T extends Record<string | symbol, any[]>>(eventList: T): boolean => {\n const keys = Object.keys(eventList);\n if (keys.length == 0) {\n return true;\n }\n\n for (const key of keys) {\n if ((eventList[key]?.length ?? 0) > 0) {\n return false;\n }\n }\n\n return true;\n};\n\nexport const isDroppedEventsEmpty = (droppedEvents?: DroppedEvents): boolean => {\n if (!droppedEvents) {\n return true;\n }\n const keys = Object.keys(droppedEvents);\n if (keys.length == 0) {\n return true;\n }\n\n for (const key of keys) {\n if ((droppedEvents[key] ?? 0) > 0) {\n return false;\n }\n }\n\n return true;\n};\n","import type { InvalidContextEvent } from \"./telemetry-events\";\nimport type { AggregatedEvent } from \"./types\";\n\nexport const DISTINCT_KIND_SAMPLE_LIMIT = 20;\n\nexport type InvalidContextRecording =\n | \"new-kind-sample\"\n | \"known-kind-sample\"\n | \"first-beyond-sample-limit\"\n | \"beyond-sample-limit\";\n\nexport class InvalidContextSubmissions {\n private readonly countsByKindSample = new Map<string, number>();\n private countBeyondSampleLimit = 0;\n private startTime: Date | undefined;\n\n public record(kindSample: string): InvalidContextRecording {\n this.startTime ??= new Date();\n return this.add(kindSample, 1);\n }\n\n public absorb(entries: AggregatedEvent<InvalidContextEvent>[]): void {\n for (const entry of entries) {\n if (this.startTime === undefined || entry.startTime < this.startTime) {\n this.startTime = entry.startTime;\n }\n this.add(entry.event.kindSample, entry.count);\n }\n }\n\n private add(kindSample: string | undefined, count: number): InvalidContextRecording {\n if (kindSample !== undefined) {\n const knownCount = this.countsByKindSample.get(kindSample);\n if (knownCount !== undefined) {\n this.countsByKindSample.set(kindSample, knownCount + count);\n return \"known-kind-sample\";\n }\n if (this.countsByKindSample.size < DISTINCT_KIND_SAMPLE_LIMIT) {\n this.countsByKindSample.set(kindSample, count);\n return \"new-kind-sample\";\n }\n }\n const firstBeyondSampleLimit = this.countBeyondSampleLimit === 0;\n this.countBeyondSampleLimit += count;\n return firstBeyondSampleLimit ? \"first-beyond-sample-limit\" : \"beyond-sample-limit\";\n }\n\n public takeSnapshot(): AggregatedEvent<InvalidContextEvent>[] {\n const endTime = new Date();\n const startTime = this.startTime ?? endTime;\n const entryOf = (count: number, kindSample?: string): AggregatedEvent<InvalidContextEvent> => ({\n startTime,\n endTime,\n count,\n event: { reason: \"invalid-context-kind\", kindSample },\n });\n const sampledEntries = Array.from(this.countsByKindSample, ([kindSample, count]) =>\n entryOf(count, kindSample),\n );\n const entries =\n this.countBeyondSampleLimit > 0\n ? [...sampledEntries, entryOf(this.countBeyondSampleLimit)]\n : sampledEntries;\n this.clear();\n return entries;\n }\n\n private clear() {\n this.countsByKindSample.clear();\n this.countBeyondSampleLimit = 0;\n this.startTime = undefined;\n }\n}\n","import { type TelemetryEventCollectorOptions } from \"@shared/telemetry/TelemetryEventCollector\";\nimport type { ConfigDirectorContext, ConfigDirectorLogger, ConfigValueType } from \"@js-client-core/types\";\nimport type { TelemetryClient, EvaluatedConfigEvent } from \"@js-client-core/telemetry\";\nimport type {\n TelemetryCloseEvent,\n TelemetryEvaluatedConfigEvent,\n TelemetryFlushEvent,\n TelemetryInitializeEvent,\n TelemetryInvalidContextSubmissionsEvent,\n TelemetryUpdateContextEvent,\n TelemetryWorkerResponseEvent,\n} from \"./types\";\nimport type { TelemetryValue } from \"@shared/telemetry/utils\";\nimport { mapToTelemetryValue } from \"@shared/telemetry/utils\";\nimport { InvalidContextSubmissions } from \"@shared/telemetry/InvalidContextSubmissions\";\n\nconst DEFAULT_WORKER_CLOSE_TIMEOUT = 6_000;\n\nexport type WebWorkerTelemetryClientOptions = TelemetryEventCollectorOptions & {\n workerCloseTimeout?: number;\n};\n\nexport class WebWorkerTelemetryClient implements TelemetryClient {\n private readonly logger: ConfigDirectorLogger;\n private readonly initializeMessage: TelemetryInitializeEvent;\n private worker: Worker | undefined;\n private turnedOff = false;\n private readonly pendingEvaluations: TelemetryEvaluatedConfigEvent[] = [];\n private readonly pendingEvaluationLimit: number;\n private readonly pendingInvalidContextSubmissions = new InvalidContextSubmissions();\n private closePromise: Promise<void> | undefined;\n private closeResolve: (() => void) | undefined;\n private closeTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly workerCloseTimeout: number;\n private readonly visibilityHandler: () => void;\n\n constructor(options: WebWorkerTelemetryClientOptions) {\n this.logger = options.logger;\n this.workerCloseTimeout = options.workerCloseTimeout ?? DEFAULT_WORKER_CLOSE_TIMEOUT;\n this.pendingEvaluationLimit = options.evaluationQueueLimit ?? 1_000;\n\n this.initializeMessage = {\n type: \"Initialize\",\n payload: {\n sdkKey: options.sdkKey,\n sdkIdentity: options.sdkIdentity,\n metaContext: options.metaContext,\n baseUrl: options.baseUrl.toString(),\n evaluationQueueLimit: this.pendingEvaluationLimit,\n initialFlushIntervalDelay: options.initialFlushIntervalDelay ?? 5_000,\n flushIntervalDelay: options.flushIntervalDelay ?? 30_000,\n },\n };\n\n this.visibilityHandler = () => {\n if (document.visibilityState === \"hidden\") {\n this.flush();\n }\n };\n }\n\n private createWorkerOrTurnOff(): Worker | undefined {\n if (typeof Worker === \"undefined\") {\n this.turnOff(\n \"[WebWorkerTelemetryClient] Telemetry is off because Web Workers are not available in this environment.\",\n );\n return undefined;\n }\n try {\n return new Worker(new URL(\"./worker.ts\", import.meta.url), { type: \"module\" });\n } catch (error) {\n this.turnOff(\n \"[WebWorkerTelemetryClient] Telemetry is off because the telemetry Web Worker could not be created: \",\n error,\n );\n return undefined;\n }\n }\n\n private turnOff(warning: string, ...details: unknown[]) {\n this.turnedOff = true;\n this.pendingEvaluations.length = 0;\n this.logger.warn(warning, ...details);\n }\n\n private startWorker(): Worker | undefined {\n if (this.worker || this.turnedOff) {\n return this.worker;\n }\n const worker = this.createWorkerOrTurnOff();\n if (!worker) {\n return undefined;\n }\n worker.onmessage = (message: MessageEvent<TelemetryWorkerResponseEvent>) => {\n this.handleWorkerEvent(message.data);\n };\n worker.postMessage(this.initializeMessage);\n this.worker = worker;\n\n try {\n document.addEventListener(\"visibilitychange\", this.visibilityHandler);\n } catch (error) {\n this.logger.warn(\"[TelemetryEventCollector] Could not configure 'visibilitychange' listener: \", error);\n }\n\n for (const evaluation of this.pendingEvaluations) {\n worker.postMessage(evaluation);\n }\n this.pendingEvaluations.length = 0;\n this.forwardInvalidContextSubmissions(worker);\n return worker;\n }\n\n private forwardInvalidContextSubmissions(worker: Worker | undefined) {\n if (!worker) {\n return;\n }\n const entries = this.pendingInvalidContextSubmissions.takeSnapshot();\n if (entries.length === 0) {\n return;\n }\n const submissionsMessage: TelemetryInvalidContextSubmissionsEvent = {\n type: \"InvalidContextSubmissions\",\n payload: { entries },\n };\n worker.postMessage(submissionsMessage);\n }\n\n public async updateContext(value: ConfigDirectorContext | undefined) {\n if (this.closePromise) {\n return;\n }\n const updateContextMessage: TelemetryUpdateContextEvent = {\n type: \"UpdateContext\",\n payload: {\n context: value,\n },\n };\n this.startWorker()?.postMessage(updateContextMessage);\n }\n\n public evaluatedConfig<T extends ConfigValueType>(event: EvaluatedConfigEvent<T>): void {\n if (this.turnedOff) {\n return;\n }\n const evaluatedConfigMessage: TelemetryEvaluatedConfigEvent = {\n type: \"EvaluatedConfigEvent\",\n payload: this.sanitizeEvaluatedConfigEvent(event),\n };\n if (this.worker) {\n this.worker.postMessage(evaluatedConfigMessage);\n return;\n }\n if (this.pendingEvaluations.length >= this.pendingEvaluationLimit) {\n this.pendingEvaluations.shift();\n }\n this.pendingEvaluations.push(evaluatedConfigMessage);\n }\n\n public recordInvalidContext(kindSample: string): void {\n this.pendingInvalidContextSubmissions.record(kindSample);\n this.forwardInvalidContextSubmissions(this.worker);\n }\n\n private sanitizeEvaluatedConfigEvent<T extends ConfigValueType>(\n event: EvaluatedConfigEvent<T>,\n ): EvaluatedConfigEvent<TelemetryValue> {\n return {\n ...event,\n defaultValue: mapToTelemetryValue({ value: event.defaultValue, type: event.type }),\n evaluatedValue: mapToTelemetryValue({\n value: event.evaluatedValue,\n valueId: event.evaluatedValueId,\n type: event.type,\n }),\n };\n }\n\n private handleWorkerEvent(event: TelemetryWorkerResponseEvent) {\n if (event.type === \"Closed\") {\n this.finishClose();\n return;\n }\n if (!event.payload?.level || !event.payload?.message) {\n return;\n }\n const { level, message, args } = event.payload;\n\n switch (level) {\n case \"debug\":\n this.logger.debug(message, ...args);\n break;\n case \"info\":\n this.logger.info(message, ...args);\n break;\n case \"warn\":\n this.logger.warn(message, ...args);\n break;\n case \"error\":\n this.logger.error(message, ...args);\n break;\n }\n }\n\n private flush() {\n const flushMessage: TelemetryFlushEvent = {\n type: \"Flush\",\n };\n this.worker?.postMessage(flushMessage);\n }\n\n public close(): Promise<void> {\n if (this.closePromise) {\n return this.closePromise;\n }\n\n return this.performClose();\n }\n\n private performClose(): Promise<void> {\n const worker = this.worker;\n if (!worker) {\n this.pendingEvaluations.length = 0;\n this.closePromise = Promise.resolve();\n return this.closePromise;\n }\n try {\n document.removeEventListener(\"visibilitychange\", this.visibilityHandler);\n } catch (error) {\n this.logger.warn(\"[WebWorkerTelemetryClient] Could not remove 'visibilitychange' listener: \", error);\n }\n this.closePromise = new Promise<void>((resolve) => {\n this.closeResolve = resolve;\n this.closeTimer = setTimeout(() => {\n this.logger.warn(\n \"[WebWorkerTelemetryClient] Timed out waiting for the telemetry worker to close. Terminating the worker.\",\n );\n this.finishClose();\n }, this.workerCloseTimeout);\n const closeMessage: TelemetryCloseEvent = { type: \"Close\" };\n worker.postMessage(closeMessage);\n });\n return this.closePromise;\n }\n\n private finishClose() {\n clearTimeout(this.closeTimer);\n this.closeTimer = undefined;\n this.worker?.terminate();\n this.closeResolve?.();\n }\n}\n","const BASE62 = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n\nexport const toBase62 = (buf: Uint8Array, length: number): string => {\n const ZERO = BigInt(0);\n const BASE = BigInt(62);\n const hex = Array.from(buf)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n let n = BigInt(\"0x\" + hex);\n let result = \"\";\n while (n > ZERO) {\n result = BASE62[Number(n % BASE)] + result;\n n /= BASE;\n }\n return result.padStart(length, \"0\");\n};\n","export const DIGEST_BYTES = 16;\nexport const BASE62_LENGTH = Math.ceil((DIGEST_BYTES * 8) / Math.log2(62));\n","import { toBase62 } from \"@shared/base62-encoder\";\nimport { DIGEST_BYTES, BASE62_LENGTH } from \"@shared/value-id\";\n\nconst encoder = new TextEncoder();\n\nexport const generateValueId = async (\n v: string | number | boolean | null | undefined,\n): Promise<string | undefined> => {\n if (typeof crypto === \"undefined\" || crypto.subtle == null) {\n return undefined;\n }\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encoder.encode(v?.toString() ?? \"\"));\n return toBase62(new Uint8Array(hashBuffer, 0, DIGEST_BYTES), BASE62_LENGTH);\n};\n","import {\n type ConfigDirectorClientOptions,\n type ConfigDirectorClient,\n type IdentifyingSdkOptions,\n type OfflineClientOptions,\n} from \"@js-client-core/index\";\nimport { WebWorkerTelemetryClient } from \"./telemetry/WebWorkerTelemetryClient\";\nimport { DefaultConfigDirectorClient } from \"@js-client-core/DefaultConfigDirectorClient\";\nimport { defaultUrlFactory } from \"@shared/url\";\nimport { generateValueId } from \"./telemetry/value-id-generator\";\n\n/**\n * Creates a browser client. With a client SDK key it connects to ConfigDirector; with\n * {@link OfflineClientOptions} alone it runs in `offline` mode and serves `connection.values`. An\n * absent key with `clientOptions` is the same as the options alone when their mode is `offline`,\n * and fails like a missing key otherwise.\n */\nexport const createBrowserClient = (\n clientSdkKeyOrOptions: string | OfflineClientOptions | undefined,\n sdkOptions: IdentifyingSdkOptions,\n clientOptions?: ConfigDirectorClientOptions,\n): ConfigDirectorClient => {\n return DefaultConfigDirectorClient.from(\n ({ clientSdkKey, baseUrl, logger, metadata }) =>\n new WebWorkerTelemetryClient({\n sdkKey: clientSdkKey,\n sdkIdentity: {\n sdkName: sdkOptions.sdkName,\n sdkVersion: sdkOptions.sdkVersion,\n },\n metaContext: {\n appName: metadata?.appName,\n appVersion: metadata?.appVersion,\n },\n logger,\n baseUrl,\n urlFactory: defaultUrlFactory,\n valueIdGenerator: generateValueId,\n }),\n clientSdkKeyOrOptions,\n sdkOptions,\n clientOptions,\n );\n};\n","import type { ClientEvents, ClientHooks, ConfigDirectorClient } from \"./types\";\n\ntype Registration = { event: keyof ClientEvents; handler: (payload: any) => void };\n\nexport class ClientHandlers {\n private registrations: Registration[] = [];\n\n constructor(private readonly client: ConfigDirectorClient) {}\n\n public on<T extends keyof ClientEvents>(event: T, handler: (payload: ClientEvents[T]) => void) {\n this.client.on(event, handler);\n this.registrations.push({ event, handler });\n }\n\n public registerHooks(hooks: ClientHooks | undefined) {\n for (const [event, handlerOrHandlers] of Object.entries(hooks ?? {})) {\n const handlers = Array.isArray(handlerOrHandlers) ? handlerOrHandlers : [handlerOrHandlers];\n for (const handler of handlers) {\n if (typeof handler === \"function\") {\n this.on(event as keyof ClientEvents, handler as (payload: unknown) => void);\n }\n }\n }\n }\n\n public removeAll() {\n for (const { event, handler } of this.registrations) {\n this.client.off(event, handler);\n }\n this.registrations = [];\n }\n}\n","export const deepEqual = (left: unknown, right: unknown): boolean => {\n if (Object.is(left, right)) {\n return true;\n }\n if (typeof left !== \"object\" || typeof right !== \"object\" || left === null || right === null) {\n return false;\n }\n if (Object.getPrototypeOf(left) !== Object.getPrototypeOf(right)) {\n return false;\n }\n if (left instanceof Date && right instanceof Date) {\n return left.getTime() === right.getTime();\n }\n if (Array.isArray(left) && Array.isArray(right)) {\n return left.length === right.length && left.every((item, index) => deepEqual(item, right[index]));\n }\n if (!isPlainObject(left) || !isPlainObject(right)) {\n return false;\n }\n const leftKeys = Object.keys(left);\n const rightKeys = Object.keys(right);\n return (\n leftKeys.length === rightKeys.length &&\n leftKeys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && deepEqual(left[key], right[key]))\n );\n};\n\nconst isPlainObject = (value: object): value is Record<string, unknown> => {\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n","import type { ConfigDirectorClient, ConfigDirectorContext } from \"./types\";\nimport { deepEqual } from \"@shared/deepEqual\";\n\nexport type MountAction = \"initialize\" | \"updateContext\" | \"none\";\n\nexport const decideMountAction = (\n client: ConfigDirectorClient,\n context: ConfigDirectorContext | undefined,\n): MountAction => {\n if (client.isInitializing) {\n return \"none\";\n }\n if (!client.isReady) {\n return \"initialize\";\n }\n if (context !== undefined && !deepEqual(context, client.context)) {\n return \"updateContext\";\n }\n return \"none\";\n};\n","\"use client\";\n\nimport React from \"react\";\nimport type { ConfigDirectorContextData } from \"./types\";\n\nconst createReactContext = () => React.createContext<ConfigDirectorContextData>({ status: \"loading\" });\nexport const reactContext = createReactContext();\n","import type {\n ConfigDirectorLogMessageDecorator,\n ConfigDirectorLoggingLevel,\n ConfigDirectorLogger,\n} from \"@js-browser-client/index\";\nimport { createDefaultLogger as createJsSdkLogger } from \"@js-browser-client/index\";\n\nclass LogMessageDecorator implements ConfigDirectorLogMessageDecorator {\n decorateMessage(message: string): string {\n return `[ConfigDirector:nextjs-sdk] ${message}`;\n }\n}\n\nexport const createConsoleLogger = (level: ConfigDirectorLoggingLevel): ConfigDirectorLogger => {\n return createJsSdkLogger(level, new LogMessageDecorator());\n};\n","\"use client\";\n\nimport { Component, type PropsWithChildren } from \"react\";\nimport { createBrowserClient, type ConfigDirectorClient, type ConfigDirectorContext } from \"@js-browser-client/index\";\nimport { ClientHandlers } from \"@js-client-core/clientHandlers\";\nimport { readInstalledTestClient } from \"@js-client-core/installedTestClient\";\nimport { decideMountAction } from \"@js-client-core/mountAction\";\nimport { deepEqual } from \"@shared/deepEqual\";\nimport { reactContext } from \"./context\";\nimport { createConsoleLogger } from \"./logger\";\nimport type {\n ClientStatus,\n ConfigDirectorClientProviderProps,\n ConfigDirectorProviderOptions,\n ConfigDirectorProviderState,\n} from \"./types\";\n\nconst hasGivenClient = (props: ConfigDirectorClientProviderProps): props is { client: ConfigDirectorClient } =>\n \"client\" in props && props.client !== undefined;\n\nconst settledStatusOf = (client: ConfigDirectorClient): ClientStatus => (client.isReady ? \"ready\" : \"default\");\n\n/**\n * Initializes the ConfigDirector browser client and provides it to all descendant hooks.\n *\n * Place this in your root layout, wrapping your application. In most cases prefer the\n * `ConfigDirectorProvider` exported from `@configdirector/nextjs-sdk/server` — it is a React\n * Server Component that populates `initialConfigs` automatically, ensuring Client Components\n * render the correct values during SSR without any extra wiring.\n *\n * This component itself is a Client Component, so if you use it directly (rather than through\n * the server provider) any `sdkKey` sourced from `process.env` must use the `NEXT_PUBLIC_`\n * prefix — Next.js only exposes prefixed variables to code that runs in the browser.\n *\n * Given a `client` prop, or while a test client is installed from\n * `@configdirector/nextjs-sdk/client/testing`, the provider provides that client from its first\n * render instead of building one, and never disposes it.\n */\nexport class ConfigDirectorProvider extends Component<\n PropsWithChildren<ConfigDirectorClientProviderProps>,\n ConfigDirectorProviderState\n> {\n private client: ConfigDirectorClient | undefined;\n private readonly ownsClient: boolean;\n private handlers: ClientHandlers | undefined;\n\n constructor(props: PropsWithChildren<ConfigDirectorClientProviderProps>) {\n super(props);\n const givenClient = hasGivenClient(props) ? props.client : readInstalledTestClient();\n this.ownsClient = givenClient === undefined;\n this.client = givenClient;\n this.state = givenClient\n ? { client: givenClient, status: givenClient.isReady ? \"ready\" : \"loading\" }\n : { status: \"loading\" };\n }\n\n private buildClient(): ConfigDirectorClient {\n const options = this.props as ConfigDirectorProviderOptions;\n return createBrowserClient(\n options.sdkKey,\n { sdkName: \"nextjs-sdk\", sdkVersion: \"__VERSION__\" },\n {\n connection: {\n url: options.url,\n timeout: options.timeout,\n mode: options.mode,\n pollingInterval: options.pollingInterval,\n values: options.values,\n },\n metadata: { appName: options.appName, appVersion: options.appVersion },\n logger: createConsoleLogger(options.logLevel ?? \"warn\"),\n hooks: options.hooks,\n },\n );\n }\n\n override async componentDidMount(): Promise<void> {\n let client = this.client;\n if (this.ownsClient) {\n client = this.buildClient();\n this.client = client;\n this.setState({ client });\n }\n if (!client) {\n return;\n }\n\n this.handlers = new ClientHandlers(client);\n this.handlers.on(\"configsUpdated\", () => {\n this.setState({ updatedAt: new Date() });\n });\n this.handlers.on(\"clientReady\", () => {\n this.setState({ status: \"ready\" });\n });\n if (!this.ownsClient) {\n this.handlers.registerHooks(this.props.hooks);\n }\n await this.connect(client, this.props.context);\n }\n\n private async connect(client: ConfigDirectorClient, context: ConfigDirectorContext | undefined): Promise<void> {\n switch (decideMountAction(client, context)) {\n case \"initialize\":\n await client.initialize(context);\n break;\n case \"updateContext\":\n this.setState({ status: \"loading\" });\n await client.updateContext(context as ConfigDirectorContext);\n break;\n case \"none\":\n return;\n }\n if (this.client === client) {\n this.setState({ status: settledStatusOf(client) });\n }\n }\n\n override async componentDidUpdate(\n prevProps: PropsWithChildren<ConfigDirectorClientProviderProps>,\n ): Promise<void> {\n if (hasGivenClient(prevProps) && hasGivenClient(this.props) && prevProps.client !== this.props.client) {\n createConsoleLogger(\"warn\").warn(\n \"The client prop of ConfigDirectorProvider changed after it mounted and is ignored. Remount the provider, for example with a new key, to use another client.\",\n );\n }\n if (!deepEqual(prevProps.context, this.props.context)) {\n const client = this.client;\n if (!client) return;\n this.setState({ status: \"loading\" });\n await client.updateContext(this.props.context ?? {});\n if (this.client === client) {\n this.setState({ status: settledStatusOf(client) });\n }\n }\n }\n\n override componentWillUnmount(): void {\n this.handlers?.removeAll();\n this.handlers = undefined;\n if (this.ownsClient) {\n this.client?.dispose();\n this.client = undefined;\n }\n }\n\n override render() {\n return (\n <reactContext.Provider value={{ ...this.state, initialConfigs: this.props.initialConfigs }}>\n {this.props.children}\n </reactContext.Provider>\n );\n }\n}\n","export class ConfigDirectorNextContextError extends Error {\n public override readonly name: string = \"ConfigDirectorNextContextError\";\n\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, ConfigDirectorNextContextError.prototype);\n }\n}\n","\"use client\";\n\nimport { useContext as useReactContext } from \"react\";\nimport { reactContext } from \"./context\";\nimport type { ConfigDirectorContext, ConfigValueType } from \"@js-browser-client/index\";\nimport { parseConfigValue } from \"@shared/value-parser\";\nimport { ConfigDirectorNextContextError } from \"./errors\";\nimport type { ClientStatus } from \"./types\";\n\nconst noContextError = () =>\n new ConfigDirectorNextContextError(\n \"The ConfigDirector client was not found in the React context. \" +\n \"Make sure the component using this hook is inside a <ConfigDirectorProvider>.\",\n );\n\n/**\n * Returns the evaluated value of a config key.\n *\n * During SSR and before the browser client finishes initializing, returns the value from\n * `initialConfigs` (if provided to the provider) to avoid a flash of wrong content on hydration.\n * Once the browser client is ready, returns live-evaluated values and re-renders whenever configs\n * change.\n *\n * Must be used inside a `<ConfigDirectorProvider>`.\n */\nexport const useConfigValue = <T extends ConfigValueType>(\n key: string,\n defaultValue: T,\n): { value: T; readyStatus: ClientStatus; loading: boolean } => {\n const configDirectorReactContext = useReactContext(reactContext);\n if (!configDirectorReactContext) throw noContextError();\n\n // The client is undefined during SSR and briefly during the first client render before componentDidMount\n // fires. Fall through to initialConfigs in both cases so the rendered output matches the server HTML,\n // avoiding a hydration mismatch.\n const initialConfigState = configDirectorReactContext.initialConfigs?.[key];\n const value = configDirectorReactContext.client?.isReady\n ? configDirectorReactContext.client.getValue(key, defaultValue)\n : initialConfigState\n ? parseConfigValue(initialConfigState, defaultValue).parsedValue\n : defaultValue;\n\n return {\n value,\n readyStatus: configDirectorReactContext.status,\n loading: configDirectorReactContext.status === \"loading\",\n };\n};\n\n/**\n * Returns an `updateContext` function to update the user context on the browser client.\n * Triggers re-evaluation of all watched config values.\n *\n * Must be used inside a `<ConfigDirectorProvider>`.\n */\nexport const useContext = (): { updateContext: (context: ConfigDirectorContext) => Promise<void> } => {\n const configDirectorReactContext = useReactContext(reactContext);\n if (!configDirectorReactContext) throw noContextError();\n\n return {\n // client is undefined during SSR and briefly before componentDidMount; no-op until ready\n updateContext: async (context: ConfigDirectorContext) => {\n await configDirectorReactContext.client?.updateContext(context);\n },\n };\n};\n\n/**\n * Returns the raw browser client for advanced use cases.\n *\n * Must be used inside a `<ConfigDirectorProvider>`.\n */\nexport const useClient = () => {\n const configDirectorReactContext = useReactContext(reactContext);\n if (!configDirectorReactContext?.client) throw noContextError();\n return { client: configDirectorReactContext.client };\n};\n\n/**\n * Returns the current connection status of the browser client.\n *\n * - `\"loading\"` — client is initializing\n * - `\"ready\"` — client received configs from the server, or loaded its offline values\n * - `\"default\"` — initialization timed out; hooks return default or initial values\n *\n * Must be used inside a `<ConfigDirectorProvider>`.\n */\nexport const useConfigDirectorStatus = (): { readyStatus: ClientStatus; loading: boolean } => {\n const configDirectorReactContext = useReactContext(reactContext);\n if (!configDirectorReactContext) throw noContextError();\n return {\n readyStatus: configDirectorReactContext.status,\n loading: configDirectorReactContext.status === \"loading\",\n };\n};\n"],"mappings":"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"}