@edgeflags/sdk 0.1.0 → 0.2.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.
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var
|
|
2
|
-
exports.EdgeFlags=
|
|
1
|
+
'use strict';var c=class extends Error{statusCode;constructor(e,t){super(e),this.name="EdgeFlagsError",this.statusCode=t;}};var h=class{enabled;constructor(e){this.enabled=e;}debug(e,...t){this.enabled&&console.debug(`[EdgeFlags] ${e}`,...t);}warn(e,...t){this.enabled&&console.warn(`[EdgeFlags] ${e}`,...t);}error(e,...t){this.enabled&&console.error(`[EdgeFlags] ${e}`,...t);}};var d=class{listeners=new Map;on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.listeners.get(e)?.delete(t);}}emit(e,t){let n=this.listeners.get(e);if(n)for(let s of n)s(t);}removeAll(){this.listeners.clear();}};var u=class{flags=new Map;configs=new Map;getFlag(e){return this.flags.get(e)}getConfig(e){return this.configs.get(e)}allFlags(){return Object.fromEntries(this.flags)}allConfigs(){return Object.fromEntries(this.configs)}update(e,t){let n={flags:[],configs:[]};for(let[s,o]of Object.entries(e)){let i=this.flags.get(s);m(i,o)||n.flags.push({key:s,previous:i,current:o}),this.flags.set(s,o);}for(let[s,o]of Object.entries(t)){let i=this.configs.get(s);m(i,o)||n.configs.push({key:s,previous:i,current:o}),this.configs.set(s,o);}return n.flags.length===0&&n.configs.length===0?null:n}seed(e,t){for(let[n,s]of Object.entries(e))this.flags.set(n,s);for(let[n,s]of Object.entries(t))this.configs.set(n,s);}clear(){this.flags.clear(),this.configs.clear();}};function m(r,e){if(r===e)return true;if(r===null||e===null||r===void 0||e===void 0||typeof r!=typeof e||typeof r!="object")return false;let t=Object.keys(r),n=Object.keys(e);if(t.length!==n.length)return false;for(let s of t)if(!m(r[s],e[s]))return false;return true}var f=class{baseUrl;token;constructor(e,t){this.baseUrl=e.replace(/\/$/,""),this.token=t;}async fetchAll(e){let t=await fetch(`${this.baseUrl}/api/v1/evaluate`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({context:e})});if(!t.ok)throw new c(`Evaluation request failed: ${t.status} ${t.statusText}`,t.status);return await t.json()}};var p=class{intervalMs;timer=null;task;onError;constructor(e,t,n){this.intervalMs=e,this.task=t,this.onError=n;}start(){this.timer||(this.timer=setInterval(async()=>{try{await this.task();}catch(e){this.onError(e instanceof Error?e:new Error(String(e)));}},this.intervalMs));}stop(){this.timer&&(clearInterval(this.timer),this.timer=null);}get running(){return this.timer!==null}};var v=class{baseUrl;token;callbacks;ws=null;intentionallyClosed=false;keepaliveTimer=null;pongTimer=null;reconnectTimer=null;reconnectAttempts=0;lastEnv;lastContext;constructor(e,t,n){this.baseUrl=e.replace(/\/$/,""),this.token=t,this.callbacks=n;}connect(){return new Promise((e,t)=>{let n=this.baseUrl.replace(/^http/,"ws")+`/stream/flags?token=${encodeURIComponent(this.token)}`;this.callbacks.logger.debug("WebSocket connecting",n);let s=new WebSocket(n);this.ws=s;let o=()=>{l(),this.reconnectAttempts=0,this.callbacks.onConnectionChange("connected"),this.startKeepalive(),this.callbacks.logger.debug("WebSocket connected"),e();},i=w=>{l();let E=new Error("WebSocket connection failed");this.callbacks.logger.error("WebSocket connection error",E),t(E);},a=()=>{l(),t(new Error("WebSocket closed before open"));},l=()=>{s.removeEventListener("open",o),s.removeEventListener("error",i),s.removeEventListener("close",a),this.attachListeners(s);};s.addEventListener("open",o),s.addEventListener("error",i),s.addEventListener("close",a);})}subscribe(e,t){this.lastEnv=e,this.lastContext=t,this.send({type:"subscribe",env:e,context:t});}updateContext(e){this.lastContext=e,this.send({type:"update-context",context:e});}close(){this.intentionallyClosed=true,this.stopKeepalive(),this.clearReconnectTimer(),this.ws&&(this.ws.close(),this.ws=null),this.callbacks.onConnectionChange("disconnected");}get connected(){return this.ws?.readyState===WebSocket.OPEN}send(e){this.ws?.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e));}attachListeners(e){e.addEventListener("message",t=>{this.handleMessage(t);}),e.addEventListener("close",()=>{this.stopKeepalive(),this.intentionallyClosed||(this.callbacks.logger.warn("WebSocket closed unexpectedly, reconnecting"),this.callbacks.onConnectionChange("reconnecting"),this.scheduleReconnect());}),e.addEventListener("error",()=>{this.intentionallyClosed||this.callbacks.onError(new Error("WebSocket error"));});}handleMessage(e){let t;try{t=JSON.parse(typeof e.data=="string"?e.data:"");}catch{this.callbacks.logger.warn("Failed to parse WebSocket message");return}switch(t.type){case "snapshot":this.callbacks.logger.debug("Received snapshot"),this.callbacks.onSnapshot(t.flags??{},t.configs??{});break;case "diff":this.callbacks.logger.debug("Received diff",t.changes),this.callbacks.onDiff(t.changes??[]);break;case "pong":this.resetPongTimeout();break;case "error":this.callbacks.onError(new Error(t.error??"Server error"));break}}startKeepalive(){this.stopKeepalive(),this.keepaliveTimer=setInterval(()=>{this.send({type:"ping"}),this.pongTimer=setTimeout(()=>{this.callbacks.logger.warn("Pong timeout, reconnecting"),this.ws?.close();},1e4);},3e4);}stopKeepalive(){this.keepaliveTimer&&(clearInterval(this.keepaliveTimer),this.keepaliveTimer=null),this.resetPongTimeout();}resetPongTimeout(){this.pongTimer&&(clearTimeout(this.pongTimer),this.pongTimer=null);}scheduleReconnect(){this.clearReconnectTimer();let e=Math.min(1e3*Math.pow(2,this.reconnectAttempts),3e4);this.reconnectAttempts++,this.callbacks.logger.debug(`Reconnecting in ${e}ms (attempt ${this.reconnectAttempts})`),this.reconnectTimer=setTimeout(async()=>{try{await this.connect(),(this.lastEnv||this.lastContext)&&this.subscribe(this.lastEnv,this.lastContext);}catch{this.scheduleReconnect();}},e);}clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);}};var k={custom:{}},b=6e4,g=class{cache;emitter;logger;fetcher;poller=null;stream=null;context;pollingInterval;transportMode;ready=false;mockData;_connectionStatus="disconnected";baseUrl;token;constructor(e){let t=e._mock??null;this.mockData=t,this.cache=new u,this.emitter=new d,this.logger=new h(e.debug??false),this.context=e.context??{...k},this.pollingInterval=e.pollingInterval??b,this.transportMode=e.transport??"websocket",this.baseUrl=e.baseUrl,this.token=e.token,t?(this.fetcher=null,this.cache.seed(t.flags,t.configs),this.ready=true,this.logger.debug("Mock client created")):(this.fetcher=new f(e.baseUrl,e.token),e.bootstrap&&(this.cache.seed(e.bootstrap.flags??{},e.bootstrap.configs??{}),this.logger.debug("Bootstrap data loaded")));}async init(){if(this.mockData){this.emitter.emit("ready",void 0);return}if(this.transportMode!=="polling")try{await this.initStream();return}catch{this.logger.warn("WebSocket unavailable, falling back to polling");}await this.initPolling();}async initStream(){let e=new Promise((t,n)=>{let s=false,o=setTimeout(()=>{s||(s=true,n(new Error("Snapshot timeout")));},1e4);this.stream=new v(this.baseUrl,this.token,{onSnapshot:(i,a)=>{let l=this.cache.update(i,a);s?l&&(this.logger.debug("Stream snapshot changes",l),this.emitter.emit("change",l)):(s=true,clearTimeout(o),this.cache.seed(i,a),t());},onDiff:i=>{this.applyDiff(i);},onConnectionChange:i=>{this._connectionStatus=i,this.emitter.emit("connection",{status:i});},onError:i=>{this.logger.error("Stream error",i),this.emitter.emit("error",i);},logger:this.logger});});await this.stream.connect(),this.stream.subscribe(this.context.environment,this.context),await e,this.ready=true,this.logger.debug("Initialized via WebSocket"),this.emitter.emit("ready",void 0);}async initPolling(){try{await this.fetchAndSeed(),this.ready=!0,this.logger.debug("Initialized"),this.emitter.emit("ready",void 0),this.poller=new p(this.pollingInterval,()=>this.refresh(),e=>{this.logger.error("Polling error",e),this.emitter.emit("error",e);}),this.poller.start(),this.logger.debug(`Polling started (${this.pollingInterval}ms)`);}catch(e){let t=e instanceof Error?e:new Error(String(e));if(this.logger.error("Init failed",t),this.emitter.emit("error",t),this.cache.allFlags()&&Object.keys(this.cache.allFlags()).length>0)this.ready=true,this.logger.warn("Using bootstrap data after init failure"),this.emitter.emit("ready",void 0);else throw t}}applyDiff(e){let t={},n={};for(let a of e)a.type==="flag"?t[a.key]=a.value:a.type==="config"&&(n[a.key]=a.value);let s={...this.cache.allFlags(),...t},o={...this.cache.allConfigs(),...n},i=this.cache.update(s,o);i&&(this.logger.debug("Diff changes detected",i),this.emitter.emit("change",i));}flag(e,t){let n=this.cache.getFlag(e);return n===void 0?t:n}config(e,t){let n=this.cache.getConfig(e);return n===void 0?t:n}allFlags(){return this.cache.allFlags()}allConfigs(){return this.cache.allConfigs()}async identify(e){this.context=e,this.logger.debug("Context updated",e),this.ready&&this.stream?.connected?this.stream.updateContext(e):this.ready&&this.fetcher&&await this.refresh();}async refresh(){if(!this.fetcher)return;this.logger.debug("Fetching evaluations");let e=await this.fetcher.fetchAll(this.context),t=this.cache.update(e.flags,e.configs);t&&(this.logger.debug("Changes detected",t),this.emitter.emit("change",t));}async fetchAndSeed(){if(!this.fetcher)return;this.logger.debug("Fetching initial evaluations");let e=await this.fetcher.fetchAll(this.context);this.cache.seed(e.flags,e.configs);}on(e,t){return this.emitter.on(e,t)}get isReady(){return this.ready}get connectionStatus(){return this._connectionStatus}destroy(){this.stream?.close(),this.stream=null,this.poller?.stop(),this.poller=null,this.cache.clear(),this.emitter.removeAll(),this.ready=false,this._connectionStatus="disconnected",this.logger.debug("Destroyed");}};function y(r={}){return new g({token:"mock_token",baseUrl:"http://localhost",_mock:{flags:r.flags??{},configs:r.configs??{}}})}
|
|
2
|
+
exports.EdgeFlags=g;exports.EdgeFlagsError=c;exports.createMockClient=y;//# sourceMappingURL=index.cjs.map
|
|
3
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/logger.ts","../src/emitter.ts","../src/cache.ts","../src/fetcher.ts","../src/poller.ts","../src/client.ts","../src/mock.ts"],"names":["EdgeFlagsError","message","statusCode","Logger","enabled","args","Emitter","event","fn","payload","fns","Cache","key","flags","configs","changes","current","previous","deepEqual","value","a","b","keysA","keysB","Fetcher","baseUrl","token","context","res","Poller","intervalMs","task","onError","err","DEFAULT_CONTEXT","DEFAULT_POLL_INTERVAL","EdgeFlags","options","mock","error","defaultValue","data","createMockClient"],"mappings":"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","file":"index.cjs","sourcesContent":["export class EdgeFlagsError extends Error {\n readonly statusCode: number | undefined;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = 'EdgeFlagsError';\n this.statusCode = statusCode;\n }\n}\n","export class Logger {\n private enabled: boolean;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n }\n\n debug(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.debug(`[EdgeFlags] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.warn(`[EdgeFlags] ${message}`, ...args);\n }\n }\n\n error(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.error(`[EdgeFlags] ${message}`, ...args);\n }\n }\n}\n","import type { EdgeFlagsEvent, EventPayloadMap } from './types.js';\n\ntype Listener<E extends EdgeFlagsEvent> = (payload: EventPayloadMap[E]) => void;\n\nexport class Emitter {\n private listeners = new Map<EdgeFlagsEvent, Set<Listener<never>>>();\n\n on<E extends EdgeFlagsEvent>(event: E, fn: Listener<E>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(fn as Listener<never>);\n\n return () => {\n this.listeners.get(event)?.delete(fn as Listener<never>);\n };\n }\n\n emit<E extends EdgeFlagsEvent>(event: E, payload: EventPayloadMap[E]): void {\n const fns = this.listeners.get(event);\n if (!fns) return;\n for (const fn of fns) {\n (fn as Listener<E>)(payload);\n }\n }\n\n removeAll(): void {\n this.listeners.clear();\n }\n}\n","import type { FlagValue, ChangeEvent } from './types.js';\n\nexport class Cache {\n private flags = new Map<string, FlagValue>();\n private configs = new Map<string, unknown>();\n\n getFlag(key: string): FlagValue | undefined {\n return this.flags.get(key);\n }\n\n getConfig(key: string): unknown {\n return this.configs.get(key);\n }\n\n allFlags(): Record<string, FlagValue> {\n return Object.fromEntries(this.flags);\n }\n\n allConfigs(): Record<string, unknown> {\n return Object.fromEntries(this.configs);\n }\n\n update(\n flags: Record<string, FlagValue>,\n configs: Record<string, unknown>,\n ): ChangeEvent | null {\n const changes: ChangeEvent = { flags: [], configs: [] };\n\n for (const [key, current] of Object.entries(flags)) {\n const previous = this.flags.get(key);\n if (!deepEqual(previous, current)) {\n changes.flags.push({ key, previous, current });\n }\n this.flags.set(key, current);\n }\n\n for (const [key, current] of Object.entries(configs)) {\n const previous = this.configs.get(key);\n if (!deepEqual(previous, current)) {\n changes.configs.push({ key, previous, current });\n }\n this.configs.set(key, current);\n }\n\n if (changes.flags.length === 0 && changes.configs.length === 0) {\n return null;\n }\n return changes;\n }\n\n seed(flags: Record<string, FlagValue>, configs: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(flags)) {\n this.flags.set(key, value);\n }\n for (const [key, value] of Object.entries(configs)) {\n this.configs.set(key, value);\n }\n }\n\n clear(): void {\n this.flags.clear();\n this.configs.clear();\n }\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null || a === undefined || b === undefined) return false;\n if (typeof a !== typeof b) return false;\n if (typeof a !== 'object') return false;\n const keysA = Object.keys(a as Record<string, unknown>);\n const keysB = Object.keys(b as Record<string, unknown>);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) {\n return false;\n }\n }\n return true;\n}\n","import type { EvaluationContext, EvaluationResponse } from './types.js';\nimport { EdgeFlagsError } from './errors.js';\n\nexport class Fetcher {\n private baseUrl: string;\n private token: string;\n\n constructor(baseUrl: string, token: string) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.token = token;\n }\n\n async fetchAll(context: EvaluationContext): Promise<EvaluationResponse> {\n const res = await fetch(`${this.baseUrl}/api/v1/evaluate`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ context }),\n });\n\n if (!res.ok) {\n throw new EdgeFlagsError(\n `Evaluation request failed: ${res.status} ${res.statusText}`,\n res.status,\n );\n }\n\n return (await res.json()) as EvaluationResponse;\n }\n}\n","export class Poller {\n private intervalMs: number;\n private timer: ReturnType<typeof setInterval> | null = null;\n private task: () => Promise<void>;\n private onError: (err: Error) => void;\n\n constructor(\n intervalMs: number,\n task: () => Promise<void>,\n onError: (err: Error) => void,\n ) {\n this.intervalMs = intervalMs;\n this.task = task;\n this.onError = onError;\n }\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(async () => {\n try {\n await this.task();\n } catch (err) {\n this.onError(err instanceof Error ? err : new Error(String(err)));\n }\n }, this.intervalMs);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n get running(): boolean {\n return this.timer !== null;\n }\n}\n","import type {\n FlagValue,\n EvaluationContext,\n EdgeFlagsOptions,\n EdgeFlagsEvent,\n EventPayloadMap,\n ChangeEvent,\n} from './types.js';\nimport { EdgeFlagsError } from './errors.js';\nimport { Logger } from './logger.js';\nimport { Emitter } from './emitter.js';\nimport { Cache } from './cache.js';\nimport { Fetcher } from './fetcher.js';\nimport { Poller } from './poller.js';\n\ninterface MockData {\n flags: Record<string, FlagValue>;\n configs: Record<string, unknown>;\n}\n\nconst DEFAULT_CONTEXT: EvaluationContext = { custom: {} };\nconst DEFAULT_POLL_INTERVAL = 60_000;\n\nexport class EdgeFlags {\n private cache: Cache;\n private emitter: Emitter;\n private logger: Logger;\n private fetcher: Fetcher | null;\n private poller: Poller | null = null;\n private context: EvaluationContext;\n private pollingInterval: number;\n private ready = false;\n private mockData: MockData | null;\n\n constructor(options: EdgeFlagsOptions) {\n const mock = (options as EdgeFlagsOptions & { _mock?: MockData })._mock ?? null;\n this.mockData = mock;\n this.cache = new Cache();\n this.emitter = new Emitter();\n this.logger = new Logger(options.debug ?? false);\n this.context = options.context ?? { ...DEFAULT_CONTEXT };\n this.pollingInterval = options.pollingInterval ?? DEFAULT_POLL_INTERVAL;\n\n if (mock) {\n this.fetcher = null;\n this.cache.seed(mock.flags, mock.configs);\n this.ready = true;\n this.logger.debug('Mock client created');\n } else {\n this.fetcher = new Fetcher(options.baseUrl, options.token);\n if (options.bootstrap) {\n this.cache.seed(\n options.bootstrap.flags ?? {},\n options.bootstrap.configs ?? {},\n );\n this.logger.debug('Bootstrap data loaded');\n }\n }\n }\n\n async init(): Promise<void> {\n if (this.mockData) {\n this.emitter.emit('ready', undefined);\n return;\n }\n\n try {\n await this.fetchAndSeed();\n this.ready = true;\n this.logger.debug('Initialized');\n this.emitter.emit('ready', undefined);\n\n this.poller = new Poller(\n this.pollingInterval,\n () => this.refresh(),\n (err) => {\n this.logger.error('Polling error', err);\n this.emitter.emit('error', err);\n },\n );\n this.poller.start();\n this.logger.debug(`Polling started (${this.pollingInterval}ms)`);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.logger.error('Init failed', error);\n this.emitter.emit('error', error);\n\n if (this.cache.allFlags() && Object.keys(this.cache.allFlags()).length > 0) {\n this.ready = true;\n this.logger.warn('Using bootstrap data after init failure');\n this.emitter.emit('ready', undefined);\n } else {\n throw error;\n }\n }\n }\n\n flag(key: string): FlagValue | undefined;\n flag<T extends FlagValue>(key: string, defaultValue: T): T;\n flag(key: string, defaultValue?: FlagValue): FlagValue | undefined {\n const value = this.cache.getFlag(key);\n if (value === undefined) return defaultValue;\n return value;\n }\n\n config(key: string): unknown;\n config<T>(key: string, defaultValue: T): T;\n config(key: string, defaultValue?: unknown): unknown {\n const value = this.cache.getConfig(key);\n if (value === undefined) return defaultValue;\n return value;\n }\n\n allFlags(): Record<string, FlagValue> {\n return this.cache.allFlags();\n }\n\n allConfigs(): Record<string, unknown> {\n return this.cache.allConfigs();\n }\n\n async identify(context: EvaluationContext): Promise<void> {\n this.context = context;\n this.logger.debug('Context updated', context);\n if (this.ready && this.fetcher) {\n await this.refresh();\n }\n }\n\n async refresh(): Promise<void> {\n if (!this.fetcher) return;\n\n this.logger.debug('Fetching evaluations');\n const data = await this.fetcher.fetchAll(this.context);\n const changes = this.cache.update(data.flags, data.configs);\n\n if (changes) {\n this.logger.debug('Changes detected', changes);\n this.emitter.emit('change', changes);\n }\n }\n\n private async fetchAndSeed(): Promise<void> {\n if (!this.fetcher) return;\n\n this.logger.debug('Fetching initial evaluations');\n const data = await this.fetcher.fetchAll(this.context);\n this.cache.seed(data.flags, data.configs);\n }\n\n on<E extends EdgeFlagsEvent>(\n event: E,\n fn: (payload: EventPayloadMap[E]) => void,\n ): () => void {\n return this.emitter.on(event, fn);\n }\n\n get isReady(): boolean {\n return this.ready;\n }\n\n destroy(): void {\n this.poller?.stop();\n this.poller = null;\n this.cache.clear();\n this.emitter.removeAll();\n this.ready = false;\n this.logger.debug('Destroyed');\n }\n}\n","import type { FlagValue, EdgeFlagsOptions } from './types.js';\nimport { EdgeFlags } from './client.js';\n\nexport interface MockOptions {\n flags?: Record<string, FlagValue>;\n configs?: Record<string, unknown>;\n}\n\nexport function createMockClient(options: MockOptions = {}): EdgeFlags {\n const client = new EdgeFlags({\n token: 'mock_token',\n baseUrl: 'http://localhost',\n _mock: {\n flags: options.flags ?? {},\n configs: options.configs ?? {},\n },\n } as EdgeFlagsOptions & { _mock: { flags: Record<string, FlagValue>; configs: Record<string, unknown> } });\n\n return client;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/logger.ts","../src/emitter.ts","../src/cache.ts","../src/fetcher.ts","../src/poller.ts","../src/stream.ts","../src/client.ts","../src/mock.ts"],"names":["EdgeFlagsError","message","statusCode","Logger","enabled","args","Emitter","event","fn","payload","fns","Cache","key","flags","configs","changes","current","previous","deepEqual","value","a","b","keysA","keysB","Fetcher","baseUrl","token","context","res","Poller","intervalMs","task","onError","err","StreamTransport","callbacks","resolve","reject","wsUrl","ws","onOpen","cleanup","onClose","env","data","msg","delay","DEFAULT_CONTEXT","DEFAULT_POLL_INTERVAL","EdgeFlags","options","mock","snapshotReceived","resolved","timeout","diffChanges","status","error","change","existing","existingConfigs","cacheChanges","defaultValue","createMockClient"],"mappings":"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","file":"index.cjs","sourcesContent":["export class EdgeFlagsError extends Error {\n readonly statusCode: number | undefined;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = 'EdgeFlagsError';\n this.statusCode = statusCode;\n }\n}\n","export class Logger {\n private enabled: boolean;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n }\n\n debug(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.debug(`[EdgeFlags] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.warn(`[EdgeFlags] ${message}`, ...args);\n }\n }\n\n error(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.error(`[EdgeFlags] ${message}`, ...args);\n }\n }\n}\n","import type { EdgeFlagsEvent, EventPayloadMap } from './types.js';\n\ntype Listener<E extends EdgeFlagsEvent> = (payload: EventPayloadMap[E]) => void;\n\nexport class Emitter {\n private listeners = new Map<EdgeFlagsEvent, Set<Listener<never>>>();\n\n on<E extends EdgeFlagsEvent>(event: E, fn: Listener<E>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(fn as Listener<never>);\n\n return () => {\n this.listeners.get(event)?.delete(fn as Listener<never>);\n };\n }\n\n emit<E extends EdgeFlagsEvent>(event: E, payload: EventPayloadMap[E]): void {\n const fns = this.listeners.get(event);\n if (!fns) return;\n for (const fn of fns) {\n (fn as Listener<E>)(payload);\n }\n }\n\n removeAll(): void {\n this.listeners.clear();\n }\n}\n","import type { FlagValue, ChangeEvent } from './types.js';\n\nexport class Cache {\n private flags = new Map<string, FlagValue>();\n private configs = new Map<string, unknown>();\n\n getFlag(key: string): FlagValue | undefined {\n return this.flags.get(key);\n }\n\n getConfig(key: string): unknown {\n return this.configs.get(key);\n }\n\n allFlags(): Record<string, FlagValue> {\n return Object.fromEntries(this.flags);\n }\n\n allConfigs(): Record<string, unknown> {\n return Object.fromEntries(this.configs);\n }\n\n update(\n flags: Record<string, FlagValue>,\n configs: Record<string, unknown>,\n ): ChangeEvent | null {\n const changes: ChangeEvent = { flags: [], configs: [] };\n\n for (const [key, current] of Object.entries(flags)) {\n const previous = this.flags.get(key);\n if (!deepEqual(previous, current)) {\n changes.flags.push({ key, previous, current });\n }\n this.flags.set(key, current);\n }\n\n for (const [key, current] of Object.entries(configs)) {\n const previous = this.configs.get(key);\n if (!deepEqual(previous, current)) {\n changes.configs.push({ key, previous, current });\n }\n this.configs.set(key, current);\n }\n\n if (changes.flags.length === 0 && changes.configs.length === 0) {\n return null;\n }\n return changes;\n }\n\n seed(flags: Record<string, FlagValue>, configs: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(flags)) {\n this.flags.set(key, value);\n }\n for (const [key, value] of Object.entries(configs)) {\n this.configs.set(key, value);\n }\n }\n\n clear(): void {\n this.flags.clear();\n this.configs.clear();\n }\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null || a === undefined || b === undefined) return false;\n if (typeof a !== typeof b) return false;\n if (typeof a !== 'object') return false;\n const keysA = Object.keys(a as Record<string, unknown>);\n const keysB = Object.keys(b as Record<string, unknown>);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) {\n return false;\n }\n }\n return true;\n}\n","import type { EvaluationContext, EvaluationResponse } from './types.js';\nimport { EdgeFlagsError } from './errors.js';\n\nexport class Fetcher {\n private baseUrl: string;\n private token: string;\n\n constructor(baseUrl: string, token: string) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.token = token;\n }\n\n async fetchAll(context: EvaluationContext): Promise<EvaluationResponse> {\n const res = await fetch(`${this.baseUrl}/api/v1/evaluate`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ context }),\n });\n\n if (!res.ok) {\n throw new EdgeFlagsError(\n `Evaluation request failed: ${res.status} ${res.statusText}`,\n res.status,\n );\n }\n\n return (await res.json()) as EvaluationResponse;\n }\n}\n","export class Poller {\n private intervalMs: number;\n private timer: ReturnType<typeof setInterval> | null = null;\n private task: () => Promise<void>;\n private onError: (err: Error) => void;\n\n constructor(\n intervalMs: number,\n task: () => Promise<void>,\n onError: (err: Error) => void,\n ) {\n this.intervalMs = intervalMs;\n this.task = task;\n this.onError = onError;\n }\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(async () => {\n try {\n await this.task();\n } catch (err) {\n this.onError(err instanceof Error ? err : new Error(String(err)));\n }\n }, this.intervalMs);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n get running(): boolean {\n return this.timer !== null;\n }\n}\n","import type { FlagValue, EvaluationContext, ConnectionStatus } from './types.js';\nimport type { Logger } from './logger.js';\n\ninterface StreamCallbacks {\n onSnapshot: (flags: Record<string, FlagValue>, configs: Record<string, unknown>) => void;\n onDiff: (changes: DiffChange[]) => void;\n onConnectionChange: (status: ConnectionStatus) => void;\n onError: (err: Error) => void;\n logger: Logger;\n}\n\nexport interface DiffChange {\n type: 'flag' | 'config';\n key: string;\n value: FlagValue | unknown;\n deleted?: boolean;\n}\n\nconst KEEPALIVE_INTERVAL = 30_000;\nconst PONG_TIMEOUT = 10_000;\nconst BACKOFF_BASE = 1000;\nconst BACKOFF_MAX = 30_000;\n\nexport class StreamTransport {\n private baseUrl: string;\n private token: string;\n private callbacks: StreamCallbacks;\n private ws: WebSocket | null = null;\n private intentionallyClosed = false;\n private keepaliveTimer: ReturnType<typeof setInterval> | null = null;\n private pongTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectAttempts = 0;\n private lastEnv?: string;\n private lastContext?: EvaluationContext;\n\n constructor(baseUrl: string, token: string, callbacks: StreamCallbacks) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.token = token;\n this.callbacks = callbacks;\n }\n\n connect(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const wsUrl = this.baseUrl.replace(/^http/, 'ws') + `/stream/flags?token=${encodeURIComponent(this.token)}`;\n this.callbacks.logger.debug('WebSocket connecting', wsUrl);\n\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n\n const onOpen = () => {\n cleanup();\n this.reconnectAttempts = 0;\n this.callbacks.onConnectionChange('connected');\n this.startKeepalive();\n this.callbacks.logger.debug('WebSocket connected');\n resolve();\n };\n\n const onError = (event: Event) => {\n cleanup();\n const err = new Error('WebSocket connection failed');\n this.callbacks.logger.error('WebSocket connection error', err);\n reject(err);\n };\n\n const onClose = () => {\n cleanup();\n reject(new Error('WebSocket closed before open'));\n };\n\n const cleanup = () => {\n ws.removeEventListener('open', onOpen);\n ws.removeEventListener('error', onError);\n ws.removeEventListener('close', onClose);\n this.attachListeners(ws);\n };\n\n ws.addEventListener('open', onOpen);\n ws.addEventListener('error', onError);\n ws.addEventListener('close', onClose);\n });\n }\n\n subscribe(env?: string, context?: EvaluationContext): void {\n this.lastEnv = env;\n this.lastContext = context;\n this.send({ type: 'subscribe', env, context });\n }\n\n updateContext(context: EvaluationContext): void {\n this.lastContext = context;\n this.send({ type: 'update-context', context });\n }\n\n close(): void {\n this.intentionallyClosed = true;\n this.stopKeepalive();\n this.clearReconnectTimer();\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.callbacks.onConnectionChange('disconnected');\n }\n\n get connected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n private send(data: Record<string, unknown>): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(data));\n }\n }\n\n private attachListeners(ws: WebSocket): void {\n ws.addEventListener('message', (event) => {\n this.handleMessage(event);\n });\n\n ws.addEventListener('close', () => {\n this.stopKeepalive();\n if (!this.intentionallyClosed) {\n this.callbacks.logger.warn('WebSocket closed unexpectedly, reconnecting');\n this.callbacks.onConnectionChange('reconnecting');\n this.scheduleReconnect();\n }\n });\n\n ws.addEventListener('error', () => {\n if (!this.intentionallyClosed) {\n this.callbacks.onError(new Error('WebSocket error'));\n }\n });\n }\n\n private handleMessage(event: MessageEvent): void {\n let msg: { type: string; flags?: Record<string, FlagValue>; configs?: Record<string, unknown>; changes?: DiffChange[]; error?: string };\n try {\n msg = JSON.parse(typeof event.data === 'string' ? event.data : '');\n } catch {\n this.callbacks.logger.warn('Failed to parse WebSocket message');\n return;\n }\n\n switch (msg.type) {\n case 'snapshot':\n this.callbacks.logger.debug('Received snapshot');\n this.callbacks.onSnapshot(msg.flags ?? {}, msg.configs ?? {});\n break;\n case 'diff':\n this.callbacks.logger.debug('Received diff', msg.changes);\n this.callbacks.onDiff(msg.changes ?? []);\n break;\n case 'pong':\n this.resetPongTimeout();\n break;\n case 'error':\n this.callbacks.onError(new Error(msg.error ?? 'Server error'));\n break;\n }\n }\n\n private startKeepalive(): void {\n this.stopKeepalive();\n this.keepaliveTimer = setInterval(() => {\n this.send({ type: 'ping' });\n this.pongTimer = setTimeout(() => {\n this.callbacks.logger.warn('Pong timeout, reconnecting');\n this.ws?.close();\n }, PONG_TIMEOUT);\n }, KEEPALIVE_INTERVAL);\n }\n\n private stopKeepalive(): void {\n if (this.keepaliveTimer) {\n clearInterval(this.keepaliveTimer);\n this.keepaliveTimer = null;\n }\n this.resetPongTimeout();\n }\n\n private resetPongTimeout(): void {\n if (this.pongTimer) {\n clearTimeout(this.pongTimer);\n this.pongTimer = null;\n }\n }\n\n private scheduleReconnect(): void {\n this.clearReconnectTimer();\n const delay = Math.min(BACKOFF_BASE * Math.pow(2, this.reconnectAttempts), BACKOFF_MAX);\n this.reconnectAttempts++;\n this.callbacks.logger.debug(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);\n\n this.reconnectTimer = setTimeout(async () => {\n try {\n await this.connect();\n if (this.lastEnv || this.lastContext) {\n this.subscribe(this.lastEnv, this.lastContext);\n }\n } catch {\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n","import type {\n FlagValue,\n EvaluationContext,\n EdgeFlagsOptions,\n EdgeFlagsEvent,\n EventPayloadMap,\n ConnectionStatus,\n} from './types.js';\nimport { EdgeFlagsError } from './errors.js';\nimport { Logger } from './logger.js';\nimport { Emitter } from './emitter.js';\nimport { Cache } from './cache.js';\nimport { Fetcher } from './fetcher.js';\nimport { Poller } from './poller.js';\nimport { StreamTransport, type DiffChange } from './stream.js';\n\ninterface MockData {\n flags: Record<string, FlagValue>;\n configs: Record<string, unknown>;\n}\n\nconst DEFAULT_CONTEXT: EvaluationContext = { custom: {} };\nconst DEFAULT_POLL_INTERVAL = 60_000;\n\nexport class EdgeFlags {\n private cache: Cache;\n private emitter: Emitter;\n private logger: Logger;\n private fetcher: Fetcher | null;\n private poller: Poller | null = null;\n private stream: StreamTransport | null = null;\n private context: EvaluationContext;\n private pollingInterval: number;\n private transportMode: 'websocket' | 'polling';\n private ready = false;\n private mockData: MockData | null;\n private _connectionStatus: ConnectionStatus = 'disconnected';\n private baseUrl: string;\n private token: string;\n\n constructor(options: EdgeFlagsOptions) {\n const mock = (options as EdgeFlagsOptions & { _mock?: MockData })._mock ?? null;\n this.mockData = mock;\n this.cache = new Cache();\n this.emitter = new Emitter();\n this.logger = new Logger(options.debug ?? false);\n this.context = options.context ?? { ...DEFAULT_CONTEXT };\n this.pollingInterval = options.pollingInterval ?? DEFAULT_POLL_INTERVAL;\n this.transportMode = options.transport ?? 'websocket';\n this.baseUrl = options.baseUrl;\n this.token = options.token;\n\n if (mock) {\n this.fetcher = null;\n this.cache.seed(mock.flags, mock.configs);\n this.ready = true;\n this.logger.debug('Mock client created');\n } else {\n this.fetcher = new Fetcher(options.baseUrl, options.token);\n if (options.bootstrap) {\n this.cache.seed(\n options.bootstrap.flags ?? {},\n options.bootstrap.configs ?? {},\n );\n this.logger.debug('Bootstrap data loaded');\n }\n }\n }\n\n async init(): Promise<void> {\n if (this.mockData) {\n this.emitter.emit('ready', undefined);\n return;\n }\n\n if (this.transportMode !== 'polling') {\n try {\n await this.initStream();\n return;\n } catch {\n this.logger.warn('WebSocket unavailable, falling back to polling');\n }\n }\n\n await this.initPolling();\n }\n\n private async initStream(): Promise<void> {\n const snapshotReceived = new Promise<void>((resolve, reject) => {\n let resolved = false;\n const timeout = setTimeout(() => {\n if (!resolved) {\n resolved = true;\n reject(new Error('Snapshot timeout'));\n }\n }, 10_000);\n\n this.stream = new StreamTransport(this.baseUrl, this.token, {\n onSnapshot: (flags, configs) => {\n const changes = this.cache.update(flags, configs);\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n this.cache.seed(flags, configs);\n resolve();\n } else if (changes) {\n this.logger.debug('Stream snapshot changes', changes);\n this.emitter.emit('change', changes);\n }\n },\n onDiff: (diffChanges) => {\n this.applyDiff(diffChanges);\n },\n onConnectionChange: (status) => {\n this._connectionStatus = status;\n this.emitter.emit('connection', { status });\n },\n onError: (err) => {\n this.logger.error('Stream error', err);\n this.emitter.emit('error', err);\n },\n logger: this.logger,\n });\n });\n\n await this.stream!.connect();\n this.stream!.subscribe(this.context.environment, this.context);\n await snapshotReceived;\n\n this.ready = true;\n this.logger.debug('Initialized via WebSocket');\n this.emitter.emit('ready', undefined);\n }\n\n private async initPolling(): Promise<void> {\n try {\n await this.fetchAndSeed();\n this.ready = true;\n this.logger.debug('Initialized');\n this.emitter.emit('ready', undefined);\n\n this.poller = new Poller(\n this.pollingInterval,\n () => this.refresh(),\n (err) => {\n this.logger.error('Polling error', err);\n this.emitter.emit('error', err);\n },\n );\n this.poller.start();\n this.logger.debug(`Polling started (${this.pollingInterval}ms)`);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.logger.error('Init failed', error);\n this.emitter.emit('error', error);\n\n if (this.cache.allFlags() && Object.keys(this.cache.allFlags()).length > 0) {\n this.ready = true;\n this.logger.warn('Using bootstrap data after init failure');\n this.emitter.emit('ready', undefined);\n } else {\n throw error;\n }\n }\n }\n\n private applyDiff(changes: DiffChange[]): void {\n const flags: Record<string, FlagValue> = {};\n const configs: Record<string, unknown> = {};\n\n for (const change of changes) {\n if (change.type === 'flag') {\n flags[change.key] = change.value as FlagValue;\n } else if (change.type === 'config') {\n configs[change.key] = change.value;\n }\n }\n\n const existing = { ...this.cache.allFlags(), ...flags };\n const existingConfigs = { ...this.cache.allConfigs(), ...configs };\n const cacheChanges = this.cache.update(existing, existingConfigs);\n\n if (cacheChanges) {\n this.logger.debug('Diff changes detected', cacheChanges);\n this.emitter.emit('change', cacheChanges);\n }\n }\n\n flag(key: string): FlagValue | undefined;\n flag<T extends FlagValue>(key: string, defaultValue: T): T;\n flag(key: string, defaultValue?: FlagValue): FlagValue | undefined {\n const value = this.cache.getFlag(key);\n if (value === undefined) return defaultValue;\n return value;\n }\n\n config(key: string): unknown;\n config<T>(key: string, defaultValue: T): T;\n config(key: string, defaultValue?: unknown): unknown {\n const value = this.cache.getConfig(key);\n if (value === undefined) return defaultValue;\n return value;\n }\n\n allFlags(): Record<string, FlagValue> {\n return this.cache.allFlags();\n }\n\n allConfigs(): Record<string, unknown> {\n return this.cache.allConfigs();\n }\n\n async identify(context: EvaluationContext): Promise<void> {\n this.context = context;\n this.logger.debug('Context updated', context);\n if (this.ready && this.stream?.connected) {\n this.stream.updateContext(context);\n } else if (this.ready && this.fetcher) {\n await this.refresh();\n }\n }\n\n async refresh(): Promise<void> {\n if (!this.fetcher) return;\n\n this.logger.debug('Fetching evaluations');\n const data = await this.fetcher.fetchAll(this.context);\n const changes = this.cache.update(data.flags, data.configs);\n\n if (changes) {\n this.logger.debug('Changes detected', changes);\n this.emitter.emit('change', changes);\n }\n }\n\n private async fetchAndSeed(): Promise<void> {\n if (!this.fetcher) return;\n\n this.logger.debug('Fetching initial evaluations');\n const data = await this.fetcher.fetchAll(this.context);\n this.cache.seed(data.flags, data.configs);\n }\n\n on<E extends EdgeFlagsEvent>(\n event: E,\n fn: (payload: EventPayloadMap[E]) => void,\n ): () => void {\n return this.emitter.on(event, fn);\n }\n\n get isReady(): boolean {\n return this.ready;\n }\n\n get connectionStatus(): ConnectionStatus {\n return this._connectionStatus;\n }\n\n destroy(): void {\n this.stream?.close();\n this.stream = null;\n this.poller?.stop();\n this.poller = null;\n this.cache.clear();\n this.emitter.removeAll();\n this.ready = false;\n this._connectionStatus = 'disconnected';\n this.logger.debug('Destroyed');\n }\n}\n","import type { FlagValue, EdgeFlagsOptions } from './types.js';\nimport { EdgeFlags } from './client.js';\n\nexport interface MockOptions {\n flags?: Record<string, FlagValue>;\n configs?: Record<string, unknown>;\n}\n\nexport function createMockClient(options: MockOptions = {}): EdgeFlags {\n const client = new EdgeFlags({\n token: 'mock_token',\n baseUrl: 'http://localhost',\n _mock: {\n flags: options.flags ?? {},\n configs: options.configs ?? {},\n },\n } as EdgeFlagsOptions & { _mock: { flags: Record<string, FlagValue>; configs: Record<string, unknown> } });\n\n return client;\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -29,17 +29,23 @@ interface EdgeFlagsOptions {
|
|
|
29
29
|
baseUrl: string;
|
|
30
30
|
context?: EvaluationContext;
|
|
31
31
|
pollingInterval?: number;
|
|
32
|
+
transport?: 'websocket' | 'polling';
|
|
32
33
|
bootstrap?: {
|
|
33
34
|
flags?: Record<string, FlagValue>;
|
|
34
35
|
configs?: Record<string, unknown>;
|
|
35
36
|
};
|
|
36
37
|
debug?: boolean;
|
|
37
38
|
}
|
|
38
|
-
type
|
|
39
|
+
type ConnectionStatus = 'connected' | 'reconnecting' | 'disconnected';
|
|
40
|
+
interface ConnectionEvent {
|
|
41
|
+
status: ConnectionStatus;
|
|
42
|
+
}
|
|
43
|
+
type EdgeFlagsEvent = 'ready' | 'change' | 'error' | 'connection';
|
|
39
44
|
type EventPayloadMap = {
|
|
40
45
|
ready: undefined;
|
|
41
46
|
change: ChangeEvent;
|
|
42
47
|
error: Error;
|
|
48
|
+
connection: ConnectionEvent;
|
|
43
49
|
};
|
|
44
50
|
|
|
45
51
|
declare class EdgeFlags {
|
|
@@ -48,12 +54,20 @@ declare class EdgeFlags {
|
|
|
48
54
|
private logger;
|
|
49
55
|
private fetcher;
|
|
50
56
|
private poller;
|
|
57
|
+
private stream;
|
|
51
58
|
private context;
|
|
52
59
|
private pollingInterval;
|
|
60
|
+
private transportMode;
|
|
53
61
|
private ready;
|
|
54
62
|
private mockData;
|
|
63
|
+
private _connectionStatus;
|
|
64
|
+
private baseUrl;
|
|
65
|
+
private token;
|
|
55
66
|
constructor(options: EdgeFlagsOptions);
|
|
56
67
|
init(): Promise<void>;
|
|
68
|
+
private initStream;
|
|
69
|
+
private initPolling;
|
|
70
|
+
private applyDiff;
|
|
57
71
|
flag(key: string): FlagValue | undefined;
|
|
58
72
|
flag<T extends FlagValue>(key: string, defaultValue: T): T;
|
|
59
73
|
config(key: string): unknown;
|
|
@@ -65,6 +79,7 @@ declare class EdgeFlags {
|
|
|
65
79
|
private fetchAndSeed;
|
|
66
80
|
on<E extends EdgeFlagsEvent>(event: E, fn: (payload: EventPayloadMap[E]) => void): () => void;
|
|
67
81
|
get isReady(): boolean;
|
|
82
|
+
get connectionStatus(): ConnectionStatus;
|
|
68
83
|
destroy(): void;
|
|
69
84
|
}
|
|
70
85
|
|
|
@@ -79,4 +94,4 @@ interface MockOptions {
|
|
|
79
94
|
}
|
|
80
95
|
declare function createMockClient(options?: MockOptions): EdgeFlags;
|
|
81
96
|
|
|
82
|
-
export { type ChangeEvent, EdgeFlags, EdgeFlagsError, type EdgeFlagsEvent, type EdgeFlagsOptions, type EvaluationContext, type EvaluationResponse, type EventPayloadMap, type FlagValue, createMockClient };
|
|
97
|
+
export { type ChangeEvent, type ConnectionEvent, type ConnectionStatus, EdgeFlags, EdgeFlagsError, type EdgeFlagsEvent, type EdgeFlagsOptions, type EvaluationContext, type EvaluationResponse, type EventPayloadMap, type FlagValue, createMockClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -29,17 +29,23 @@ interface EdgeFlagsOptions {
|
|
|
29
29
|
baseUrl: string;
|
|
30
30
|
context?: EvaluationContext;
|
|
31
31
|
pollingInterval?: number;
|
|
32
|
+
transport?: 'websocket' | 'polling';
|
|
32
33
|
bootstrap?: {
|
|
33
34
|
flags?: Record<string, FlagValue>;
|
|
34
35
|
configs?: Record<string, unknown>;
|
|
35
36
|
};
|
|
36
37
|
debug?: boolean;
|
|
37
38
|
}
|
|
38
|
-
type
|
|
39
|
+
type ConnectionStatus = 'connected' | 'reconnecting' | 'disconnected';
|
|
40
|
+
interface ConnectionEvent {
|
|
41
|
+
status: ConnectionStatus;
|
|
42
|
+
}
|
|
43
|
+
type EdgeFlagsEvent = 'ready' | 'change' | 'error' | 'connection';
|
|
39
44
|
type EventPayloadMap = {
|
|
40
45
|
ready: undefined;
|
|
41
46
|
change: ChangeEvent;
|
|
42
47
|
error: Error;
|
|
48
|
+
connection: ConnectionEvent;
|
|
43
49
|
};
|
|
44
50
|
|
|
45
51
|
declare class EdgeFlags {
|
|
@@ -48,12 +54,20 @@ declare class EdgeFlags {
|
|
|
48
54
|
private logger;
|
|
49
55
|
private fetcher;
|
|
50
56
|
private poller;
|
|
57
|
+
private stream;
|
|
51
58
|
private context;
|
|
52
59
|
private pollingInterval;
|
|
60
|
+
private transportMode;
|
|
53
61
|
private ready;
|
|
54
62
|
private mockData;
|
|
63
|
+
private _connectionStatus;
|
|
64
|
+
private baseUrl;
|
|
65
|
+
private token;
|
|
55
66
|
constructor(options: EdgeFlagsOptions);
|
|
56
67
|
init(): Promise<void>;
|
|
68
|
+
private initStream;
|
|
69
|
+
private initPolling;
|
|
70
|
+
private applyDiff;
|
|
57
71
|
flag(key: string): FlagValue | undefined;
|
|
58
72
|
flag<T extends FlagValue>(key: string, defaultValue: T): T;
|
|
59
73
|
config(key: string): unknown;
|
|
@@ -65,6 +79,7 @@ declare class EdgeFlags {
|
|
|
65
79
|
private fetchAndSeed;
|
|
66
80
|
on<E extends EdgeFlagsEvent>(event: E, fn: (payload: EventPayloadMap[E]) => void): () => void;
|
|
67
81
|
get isReady(): boolean;
|
|
82
|
+
get connectionStatus(): ConnectionStatus;
|
|
68
83
|
destroy(): void;
|
|
69
84
|
}
|
|
70
85
|
|
|
@@ -79,4 +94,4 @@ interface MockOptions {
|
|
|
79
94
|
}
|
|
80
95
|
declare function createMockClient(options?: MockOptions): EdgeFlags;
|
|
81
96
|
|
|
82
|
-
export { type ChangeEvent, EdgeFlags, EdgeFlagsError, type EdgeFlagsEvent, type EdgeFlagsOptions, type EvaluationContext, type EvaluationResponse, type EventPayloadMap, type FlagValue, createMockClient };
|
|
97
|
+
export { type ChangeEvent, type ConnectionEvent, type ConnectionStatus, EdgeFlags, EdgeFlagsError, type EdgeFlagsEvent, type EdgeFlagsOptions, type EvaluationContext, type EvaluationResponse, type EventPayloadMap, type FlagValue, createMockClient };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
export{
|
|
1
|
+
var c=class extends Error{statusCode;constructor(e,t){super(e),this.name="EdgeFlagsError",this.statusCode=t;}};var h=class{enabled;constructor(e){this.enabled=e;}debug(e,...t){this.enabled&&console.debug(`[EdgeFlags] ${e}`,...t);}warn(e,...t){this.enabled&&console.warn(`[EdgeFlags] ${e}`,...t);}error(e,...t){this.enabled&&console.error(`[EdgeFlags] ${e}`,...t);}};var d=class{listeners=new Map;on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.listeners.get(e)?.delete(t);}}emit(e,t){let n=this.listeners.get(e);if(n)for(let s of n)s(t);}removeAll(){this.listeners.clear();}};var u=class{flags=new Map;configs=new Map;getFlag(e){return this.flags.get(e)}getConfig(e){return this.configs.get(e)}allFlags(){return Object.fromEntries(this.flags)}allConfigs(){return Object.fromEntries(this.configs)}update(e,t){let n={flags:[],configs:[]};for(let[s,o]of Object.entries(e)){let i=this.flags.get(s);m(i,o)||n.flags.push({key:s,previous:i,current:o}),this.flags.set(s,o);}for(let[s,o]of Object.entries(t)){let i=this.configs.get(s);m(i,o)||n.configs.push({key:s,previous:i,current:o}),this.configs.set(s,o);}return n.flags.length===0&&n.configs.length===0?null:n}seed(e,t){for(let[n,s]of Object.entries(e))this.flags.set(n,s);for(let[n,s]of Object.entries(t))this.configs.set(n,s);}clear(){this.flags.clear(),this.configs.clear();}};function m(r,e){if(r===e)return true;if(r===null||e===null||r===void 0||e===void 0||typeof r!=typeof e||typeof r!="object")return false;let t=Object.keys(r),n=Object.keys(e);if(t.length!==n.length)return false;for(let s of t)if(!m(r[s],e[s]))return false;return true}var f=class{baseUrl;token;constructor(e,t){this.baseUrl=e.replace(/\/$/,""),this.token=t;}async fetchAll(e){let t=await fetch(`${this.baseUrl}/api/v1/evaluate`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({context:e})});if(!t.ok)throw new c(`Evaluation request failed: ${t.status} ${t.statusText}`,t.status);return await t.json()}};var p=class{intervalMs;timer=null;task;onError;constructor(e,t,n){this.intervalMs=e,this.task=t,this.onError=n;}start(){this.timer||(this.timer=setInterval(async()=>{try{await this.task();}catch(e){this.onError(e instanceof Error?e:new Error(String(e)));}},this.intervalMs));}stop(){this.timer&&(clearInterval(this.timer),this.timer=null);}get running(){return this.timer!==null}};var v=class{baseUrl;token;callbacks;ws=null;intentionallyClosed=false;keepaliveTimer=null;pongTimer=null;reconnectTimer=null;reconnectAttempts=0;lastEnv;lastContext;constructor(e,t,n){this.baseUrl=e.replace(/\/$/,""),this.token=t,this.callbacks=n;}connect(){return new Promise((e,t)=>{let n=this.baseUrl.replace(/^http/,"ws")+`/stream/flags?token=${encodeURIComponent(this.token)}`;this.callbacks.logger.debug("WebSocket connecting",n);let s=new WebSocket(n);this.ws=s;let o=()=>{l(),this.reconnectAttempts=0,this.callbacks.onConnectionChange("connected"),this.startKeepalive(),this.callbacks.logger.debug("WebSocket connected"),e();},i=w=>{l();let E=new Error("WebSocket connection failed");this.callbacks.logger.error("WebSocket connection error",E),t(E);},a=()=>{l(),t(new Error("WebSocket closed before open"));},l=()=>{s.removeEventListener("open",o),s.removeEventListener("error",i),s.removeEventListener("close",a),this.attachListeners(s);};s.addEventListener("open",o),s.addEventListener("error",i),s.addEventListener("close",a);})}subscribe(e,t){this.lastEnv=e,this.lastContext=t,this.send({type:"subscribe",env:e,context:t});}updateContext(e){this.lastContext=e,this.send({type:"update-context",context:e});}close(){this.intentionallyClosed=true,this.stopKeepalive(),this.clearReconnectTimer(),this.ws&&(this.ws.close(),this.ws=null),this.callbacks.onConnectionChange("disconnected");}get connected(){return this.ws?.readyState===WebSocket.OPEN}send(e){this.ws?.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e));}attachListeners(e){e.addEventListener("message",t=>{this.handleMessage(t);}),e.addEventListener("close",()=>{this.stopKeepalive(),this.intentionallyClosed||(this.callbacks.logger.warn("WebSocket closed unexpectedly, reconnecting"),this.callbacks.onConnectionChange("reconnecting"),this.scheduleReconnect());}),e.addEventListener("error",()=>{this.intentionallyClosed||this.callbacks.onError(new Error("WebSocket error"));});}handleMessage(e){let t;try{t=JSON.parse(typeof e.data=="string"?e.data:"");}catch{this.callbacks.logger.warn("Failed to parse WebSocket message");return}switch(t.type){case "snapshot":this.callbacks.logger.debug("Received snapshot"),this.callbacks.onSnapshot(t.flags??{},t.configs??{});break;case "diff":this.callbacks.logger.debug("Received diff",t.changes),this.callbacks.onDiff(t.changes??[]);break;case "pong":this.resetPongTimeout();break;case "error":this.callbacks.onError(new Error(t.error??"Server error"));break}}startKeepalive(){this.stopKeepalive(),this.keepaliveTimer=setInterval(()=>{this.send({type:"ping"}),this.pongTimer=setTimeout(()=>{this.callbacks.logger.warn("Pong timeout, reconnecting"),this.ws?.close();},1e4);},3e4);}stopKeepalive(){this.keepaliveTimer&&(clearInterval(this.keepaliveTimer),this.keepaliveTimer=null),this.resetPongTimeout();}resetPongTimeout(){this.pongTimer&&(clearTimeout(this.pongTimer),this.pongTimer=null);}scheduleReconnect(){this.clearReconnectTimer();let e=Math.min(1e3*Math.pow(2,this.reconnectAttempts),3e4);this.reconnectAttempts++,this.callbacks.logger.debug(`Reconnecting in ${e}ms (attempt ${this.reconnectAttempts})`),this.reconnectTimer=setTimeout(async()=>{try{await this.connect(),(this.lastEnv||this.lastContext)&&this.subscribe(this.lastEnv,this.lastContext);}catch{this.scheduleReconnect();}},e);}clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);}};var k={custom:{}},b=6e4,g=class{cache;emitter;logger;fetcher;poller=null;stream=null;context;pollingInterval;transportMode;ready=false;mockData;_connectionStatus="disconnected";baseUrl;token;constructor(e){let t=e._mock??null;this.mockData=t,this.cache=new u,this.emitter=new d,this.logger=new h(e.debug??false),this.context=e.context??{...k},this.pollingInterval=e.pollingInterval??b,this.transportMode=e.transport??"websocket",this.baseUrl=e.baseUrl,this.token=e.token,t?(this.fetcher=null,this.cache.seed(t.flags,t.configs),this.ready=true,this.logger.debug("Mock client created")):(this.fetcher=new f(e.baseUrl,e.token),e.bootstrap&&(this.cache.seed(e.bootstrap.flags??{},e.bootstrap.configs??{}),this.logger.debug("Bootstrap data loaded")));}async init(){if(this.mockData){this.emitter.emit("ready",void 0);return}if(this.transportMode!=="polling")try{await this.initStream();return}catch{this.logger.warn("WebSocket unavailable, falling back to polling");}await this.initPolling();}async initStream(){let e=new Promise((t,n)=>{let s=false,o=setTimeout(()=>{s||(s=true,n(new Error("Snapshot timeout")));},1e4);this.stream=new v(this.baseUrl,this.token,{onSnapshot:(i,a)=>{let l=this.cache.update(i,a);s?l&&(this.logger.debug("Stream snapshot changes",l),this.emitter.emit("change",l)):(s=true,clearTimeout(o),this.cache.seed(i,a),t());},onDiff:i=>{this.applyDiff(i);},onConnectionChange:i=>{this._connectionStatus=i,this.emitter.emit("connection",{status:i});},onError:i=>{this.logger.error("Stream error",i),this.emitter.emit("error",i);},logger:this.logger});});await this.stream.connect(),this.stream.subscribe(this.context.environment,this.context),await e,this.ready=true,this.logger.debug("Initialized via WebSocket"),this.emitter.emit("ready",void 0);}async initPolling(){try{await this.fetchAndSeed(),this.ready=!0,this.logger.debug("Initialized"),this.emitter.emit("ready",void 0),this.poller=new p(this.pollingInterval,()=>this.refresh(),e=>{this.logger.error("Polling error",e),this.emitter.emit("error",e);}),this.poller.start(),this.logger.debug(`Polling started (${this.pollingInterval}ms)`);}catch(e){let t=e instanceof Error?e:new Error(String(e));if(this.logger.error("Init failed",t),this.emitter.emit("error",t),this.cache.allFlags()&&Object.keys(this.cache.allFlags()).length>0)this.ready=true,this.logger.warn("Using bootstrap data after init failure"),this.emitter.emit("ready",void 0);else throw t}}applyDiff(e){let t={},n={};for(let a of e)a.type==="flag"?t[a.key]=a.value:a.type==="config"&&(n[a.key]=a.value);let s={...this.cache.allFlags(),...t},o={...this.cache.allConfigs(),...n},i=this.cache.update(s,o);i&&(this.logger.debug("Diff changes detected",i),this.emitter.emit("change",i));}flag(e,t){let n=this.cache.getFlag(e);return n===void 0?t:n}config(e,t){let n=this.cache.getConfig(e);return n===void 0?t:n}allFlags(){return this.cache.allFlags()}allConfigs(){return this.cache.allConfigs()}async identify(e){this.context=e,this.logger.debug("Context updated",e),this.ready&&this.stream?.connected?this.stream.updateContext(e):this.ready&&this.fetcher&&await this.refresh();}async refresh(){if(!this.fetcher)return;this.logger.debug("Fetching evaluations");let e=await this.fetcher.fetchAll(this.context),t=this.cache.update(e.flags,e.configs);t&&(this.logger.debug("Changes detected",t),this.emitter.emit("change",t));}async fetchAndSeed(){if(!this.fetcher)return;this.logger.debug("Fetching initial evaluations");let e=await this.fetcher.fetchAll(this.context);this.cache.seed(e.flags,e.configs);}on(e,t){return this.emitter.on(e,t)}get isReady(){return this.ready}get connectionStatus(){return this._connectionStatus}destroy(){this.stream?.close(),this.stream=null,this.poller?.stop(),this.poller=null,this.cache.clear(),this.emitter.removeAll(),this.ready=false,this._connectionStatus="disconnected",this.logger.debug("Destroyed");}};function y(r={}){return new g({token:"mock_token",baseUrl:"http://localhost",_mock:{flags:r.flags??{},configs:r.configs??{}}})}
|
|
2
|
+
export{g as EdgeFlags,c as EdgeFlagsError,y as createMockClient};//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/logger.ts","../src/emitter.ts","../src/cache.ts","../src/fetcher.ts","../src/poller.ts","../src/client.ts","../src/mock.ts"],"names":["EdgeFlagsError","message","statusCode","Logger","enabled","args","Emitter","event","fn","payload","fns","Cache","key","flags","configs","changes","current","previous","deepEqual","value","a","b","keysA","keysB","Fetcher","baseUrl","token","context","res","Poller","intervalMs","task","onError","err","DEFAULT_CONTEXT","DEFAULT_POLL_INTERVAL","EdgeFlags","options","mock","error","defaultValue","data","createMockClient"],"mappings":"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","file":"index.js","sourcesContent":["export class EdgeFlagsError extends Error {\n readonly statusCode: number | undefined;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = 'EdgeFlagsError';\n this.statusCode = statusCode;\n }\n}\n","export class Logger {\n private enabled: boolean;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n }\n\n debug(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.debug(`[EdgeFlags] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.warn(`[EdgeFlags] ${message}`, ...args);\n }\n }\n\n error(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.error(`[EdgeFlags] ${message}`, ...args);\n }\n }\n}\n","import type { EdgeFlagsEvent, EventPayloadMap } from './types.js';\n\ntype Listener<E extends EdgeFlagsEvent> = (payload: EventPayloadMap[E]) => void;\n\nexport class Emitter {\n private listeners = new Map<EdgeFlagsEvent, Set<Listener<never>>>();\n\n on<E extends EdgeFlagsEvent>(event: E, fn: Listener<E>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(fn as Listener<never>);\n\n return () => {\n this.listeners.get(event)?.delete(fn as Listener<never>);\n };\n }\n\n emit<E extends EdgeFlagsEvent>(event: E, payload: EventPayloadMap[E]): void {\n const fns = this.listeners.get(event);\n if (!fns) return;\n for (const fn of fns) {\n (fn as Listener<E>)(payload);\n }\n }\n\n removeAll(): void {\n this.listeners.clear();\n }\n}\n","import type { FlagValue, ChangeEvent } from './types.js';\n\nexport class Cache {\n private flags = new Map<string, FlagValue>();\n private configs = new Map<string, unknown>();\n\n getFlag(key: string): FlagValue | undefined {\n return this.flags.get(key);\n }\n\n getConfig(key: string): unknown {\n return this.configs.get(key);\n }\n\n allFlags(): Record<string, FlagValue> {\n return Object.fromEntries(this.flags);\n }\n\n allConfigs(): Record<string, unknown> {\n return Object.fromEntries(this.configs);\n }\n\n update(\n flags: Record<string, FlagValue>,\n configs: Record<string, unknown>,\n ): ChangeEvent | null {\n const changes: ChangeEvent = { flags: [], configs: [] };\n\n for (const [key, current] of Object.entries(flags)) {\n const previous = this.flags.get(key);\n if (!deepEqual(previous, current)) {\n changes.flags.push({ key, previous, current });\n }\n this.flags.set(key, current);\n }\n\n for (const [key, current] of Object.entries(configs)) {\n const previous = this.configs.get(key);\n if (!deepEqual(previous, current)) {\n changes.configs.push({ key, previous, current });\n }\n this.configs.set(key, current);\n }\n\n if (changes.flags.length === 0 && changes.configs.length === 0) {\n return null;\n }\n return changes;\n }\n\n seed(flags: Record<string, FlagValue>, configs: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(flags)) {\n this.flags.set(key, value);\n }\n for (const [key, value] of Object.entries(configs)) {\n this.configs.set(key, value);\n }\n }\n\n clear(): void {\n this.flags.clear();\n this.configs.clear();\n }\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null || a === undefined || b === undefined) return false;\n if (typeof a !== typeof b) return false;\n if (typeof a !== 'object') return false;\n const keysA = Object.keys(a as Record<string, unknown>);\n const keysB = Object.keys(b as Record<string, unknown>);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) {\n return false;\n }\n }\n return true;\n}\n","import type { EvaluationContext, EvaluationResponse } from './types.js';\nimport { EdgeFlagsError } from './errors.js';\n\nexport class Fetcher {\n private baseUrl: string;\n private token: string;\n\n constructor(baseUrl: string, token: string) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.token = token;\n }\n\n async fetchAll(context: EvaluationContext): Promise<EvaluationResponse> {\n const res = await fetch(`${this.baseUrl}/api/v1/evaluate`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ context }),\n });\n\n if (!res.ok) {\n throw new EdgeFlagsError(\n `Evaluation request failed: ${res.status} ${res.statusText}`,\n res.status,\n );\n }\n\n return (await res.json()) as EvaluationResponse;\n }\n}\n","export class Poller {\n private intervalMs: number;\n private timer: ReturnType<typeof setInterval> | null = null;\n private task: () => Promise<void>;\n private onError: (err: Error) => void;\n\n constructor(\n intervalMs: number,\n task: () => Promise<void>,\n onError: (err: Error) => void,\n ) {\n this.intervalMs = intervalMs;\n this.task = task;\n this.onError = onError;\n }\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(async () => {\n try {\n await this.task();\n } catch (err) {\n this.onError(err instanceof Error ? err : new Error(String(err)));\n }\n }, this.intervalMs);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n get running(): boolean {\n return this.timer !== null;\n }\n}\n","import type {\n FlagValue,\n EvaluationContext,\n EdgeFlagsOptions,\n EdgeFlagsEvent,\n EventPayloadMap,\n ChangeEvent,\n} from './types.js';\nimport { EdgeFlagsError } from './errors.js';\nimport { Logger } from './logger.js';\nimport { Emitter } from './emitter.js';\nimport { Cache } from './cache.js';\nimport { Fetcher } from './fetcher.js';\nimport { Poller } from './poller.js';\n\ninterface MockData {\n flags: Record<string, FlagValue>;\n configs: Record<string, unknown>;\n}\n\nconst DEFAULT_CONTEXT: EvaluationContext = { custom: {} };\nconst DEFAULT_POLL_INTERVAL = 60_000;\n\nexport class EdgeFlags {\n private cache: Cache;\n private emitter: Emitter;\n private logger: Logger;\n private fetcher: Fetcher | null;\n private poller: Poller | null = null;\n private context: EvaluationContext;\n private pollingInterval: number;\n private ready = false;\n private mockData: MockData | null;\n\n constructor(options: EdgeFlagsOptions) {\n const mock = (options as EdgeFlagsOptions & { _mock?: MockData })._mock ?? null;\n this.mockData = mock;\n this.cache = new Cache();\n this.emitter = new Emitter();\n this.logger = new Logger(options.debug ?? false);\n this.context = options.context ?? { ...DEFAULT_CONTEXT };\n this.pollingInterval = options.pollingInterval ?? DEFAULT_POLL_INTERVAL;\n\n if (mock) {\n this.fetcher = null;\n this.cache.seed(mock.flags, mock.configs);\n this.ready = true;\n this.logger.debug('Mock client created');\n } else {\n this.fetcher = new Fetcher(options.baseUrl, options.token);\n if (options.bootstrap) {\n this.cache.seed(\n options.bootstrap.flags ?? {},\n options.bootstrap.configs ?? {},\n );\n this.logger.debug('Bootstrap data loaded');\n }\n }\n }\n\n async init(): Promise<void> {\n if (this.mockData) {\n this.emitter.emit('ready', undefined);\n return;\n }\n\n try {\n await this.fetchAndSeed();\n this.ready = true;\n this.logger.debug('Initialized');\n this.emitter.emit('ready', undefined);\n\n this.poller = new Poller(\n this.pollingInterval,\n () => this.refresh(),\n (err) => {\n this.logger.error('Polling error', err);\n this.emitter.emit('error', err);\n },\n );\n this.poller.start();\n this.logger.debug(`Polling started (${this.pollingInterval}ms)`);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.logger.error('Init failed', error);\n this.emitter.emit('error', error);\n\n if (this.cache.allFlags() && Object.keys(this.cache.allFlags()).length > 0) {\n this.ready = true;\n this.logger.warn('Using bootstrap data after init failure');\n this.emitter.emit('ready', undefined);\n } else {\n throw error;\n }\n }\n }\n\n flag(key: string): FlagValue | undefined;\n flag<T extends FlagValue>(key: string, defaultValue: T): T;\n flag(key: string, defaultValue?: FlagValue): FlagValue | undefined {\n const value = this.cache.getFlag(key);\n if (value === undefined) return defaultValue;\n return value;\n }\n\n config(key: string): unknown;\n config<T>(key: string, defaultValue: T): T;\n config(key: string, defaultValue?: unknown): unknown {\n const value = this.cache.getConfig(key);\n if (value === undefined) return defaultValue;\n return value;\n }\n\n allFlags(): Record<string, FlagValue> {\n return this.cache.allFlags();\n }\n\n allConfigs(): Record<string, unknown> {\n return this.cache.allConfigs();\n }\n\n async identify(context: EvaluationContext): Promise<void> {\n this.context = context;\n this.logger.debug('Context updated', context);\n if (this.ready && this.fetcher) {\n await this.refresh();\n }\n }\n\n async refresh(): Promise<void> {\n if (!this.fetcher) return;\n\n this.logger.debug('Fetching evaluations');\n const data = await this.fetcher.fetchAll(this.context);\n const changes = this.cache.update(data.flags, data.configs);\n\n if (changes) {\n this.logger.debug('Changes detected', changes);\n this.emitter.emit('change', changes);\n }\n }\n\n private async fetchAndSeed(): Promise<void> {\n if (!this.fetcher) return;\n\n this.logger.debug('Fetching initial evaluations');\n const data = await this.fetcher.fetchAll(this.context);\n this.cache.seed(data.flags, data.configs);\n }\n\n on<E extends EdgeFlagsEvent>(\n event: E,\n fn: (payload: EventPayloadMap[E]) => void,\n ): () => void {\n return this.emitter.on(event, fn);\n }\n\n get isReady(): boolean {\n return this.ready;\n }\n\n destroy(): void {\n this.poller?.stop();\n this.poller = null;\n this.cache.clear();\n this.emitter.removeAll();\n this.ready = false;\n this.logger.debug('Destroyed');\n }\n}\n","import type { FlagValue, EdgeFlagsOptions } from './types.js';\nimport { EdgeFlags } from './client.js';\n\nexport interface MockOptions {\n flags?: Record<string, FlagValue>;\n configs?: Record<string, unknown>;\n}\n\nexport function createMockClient(options: MockOptions = {}): EdgeFlags {\n const client = new EdgeFlags({\n token: 'mock_token',\n baseUrl: 'http://localhost',\n _mock: {\n flags: options.flags ?? {},\n configs: options.configs ?? {},\n },\n } as EdgeFlagsOptions & { _mock: { flags: Record<string, FlagValue>; configs: Record<string, unknown> } });\n\n return client;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/logger.ts","../src/emitter.ts","../src/cache.ts","../src/fetcher.ts","../src/poller.ts","../src/stream.ts","../src/client.ts","../src/mock.ts"],"names":["EdgeFlagsError","message","statusCode","Logger","enabled","args","Emitter","event","fn","payload","fns","Cache","key","flags","configs","changes","current","previous","deepEqual","value","a","b","keysA","keysB","Fetcher","baseUrl","token","context","res","Poller","intervalMs","task","onError","err","StreamTransport","callbacks","resolve","reject","wsUrl","ws","onOpen","cleanup","onClose","env","data","msg","delay","DEFAULT_CONTEXT","DEFAULT_POLL_INTERVAL","EdgeFlags","options","mock","snapshotReceived","resolved","timeout","diffChanges","status","error","change","existing","existingConfigs","cacheChanges","defaultValue","createMockClient"],"mappings":"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","file":"index.js","sourcesContent":["export class EdgeFlagsError extends Error {\n readonly statusCode: number | undefined;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = 'EdgeFlagsError';\n this.statusCode = statusCode;\n }\n}\n","export class Logger {\n private enabled: boolean;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n }\n\n debug(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.debug(`[EdgeFlags] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.warn(`[EdgeFlags] ${message}`, ...args);\n }\n }\n\n error(message: string, ...args: unknown[]): void {\n if (this.enabled) {\n console.error(`[EdgeFlags] ${message}`, ...args);\n }\n }\n}\n","import type { EdgeFlagsEvent, EventPayloadMap } from './types.js';\n\ntype Listener<E extends EdgeFlagsEvent> = (payload: EventPayloadMap[E]) => void;\n\nexport class Emitter {\n private listeners = new Map<EdgeFlagsEvent, Set<Listener<never>>>();\n\n on<E extends EdgeFlagsEvent>(event: E, fn: Listener<E>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(fn as Listener<never>);\n\n return () => {\n this.listeners.get(event)?.delete(fn as Listener<never>);\n };\n }\n\n emit<E extends EdgeFlagsEvent>(event: E, payload: EventPayloadMap[E]): void {\n const fns = this.listeners.get(event);\n if (!fns) return;\n for (const fn of fns) {\n (fn as Listener<E>)(payload);\n }\n }\n\n removeAll(): void {\n this.listeners.clear();\n }\n}\n","import type { FlagValue, ChangeEvent } from './types.js';\n\nexport class Cache {\n private flags = new Map<string, FlagValue>();\n private configs = new Map<string, unknown>();\n\n getFlag(key: string): FlagValue | undefined {\n return this.flags.get(key);\n }\n\n getConfig(key: string): unknown {\n return this.configs.get(key);\n }\n\n allFlags(): Record<string, FlagValue> {\n return Object.fromEntries(this.flags);\n }\n\n allConfigs(): Record<string, unknown> {\n return Object.fromEntries(this.configs);\n }\n\n update(\n flags: Record<string, FlagValue>,\n configs: Record<string, unknown>,\n ): ChangeEvent | null {\n const changes: ChangeEvent = { flags: [], configs: [] };\n\n for (const [key, current] of Object.entries(flags)) {\n const previous = this.flags.get(key);\n if (!deepEqual(previous, current)) {\n changes.flags.push({ key, previous, current });\n }\n this.flags.set(key, current);\n }\n\n for (const [key, current] of Object.entries(configs)) {\n const previous = this.configs.get(key);\n if (!deepEqual(previous, current)) {\n changes.configs.push({ key, previous, current });\n }\n this.configs.set(key, current);\n }\n\n if (changes.flags.length === 0 && changes.configs.length === 0) {\n return null;\n }\n return changes;\n }\n\n seed(flags: Record<string, FlagValue>, configs: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(flags)) {\n this.flags.set(key, value);\n }\n for (const [key, value] of Object.entries(configs)) {\n this.configs.set(key, value);\n }\n }\n\n clear(): void {\n this.flags.clear();\n this.configs.clear();\n }\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null || a === undefined || b === undefined) return false;\n if (typeof a !== typeof b) return false;\n if (typeof a !== 'object') return false;\n const keysA = Object.keys(a as Record<string, unknown>);\n const keysB = Object.keys(b as Record<string, unknown>);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) {\n return false;\n }\n }\n return true;\n}\n","import type { EvaluationContext, EvaluationResponse } from './types.js';\nimport { EdgeFlagsError } from './errors.js';\n\nexport class Fetcher {\n private baseUrl: string;\n private token: string;\n\n constructor(baseUrl: string, token: string) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.token = token;\n }\n\n async fetchAll(context: EvaluationContext): Promise<EvaluationResponse> {\n const res = await fetch(`${this.baseUrl}/api/v1/evaluate`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ context }),\n });\n\n if (!res.ok) {\n throw new EdgeFlagsError(\n `Evaluation request failed: ${res.status} ${res.statusText}`,\n res.status,\n );\n }\n\n return (await res.json()) as EvaluationResponse;\n }\n}\n","export class Poller {\n private intervalMs: number;\n private timer: ReturnType<typeof setInterval> | null = null;\n private task: () => Promise<void>;\n private onError: (err: Error) => void;\n\n constructor(\n intervalMs: number,\n task: () => Promise<void>,\n onError: (err: Error) => void,\n ) {\n this.intervalMs = intervalMs;\n this.task = task;\n this.onError = onError;\n }\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(async () => {\n try {\n await this.task();\n } catch (err) {\n this.onError(err instanceof Error ? err : new Error(String(err)));\n }\n }, this.intervalMs);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n get running(): boolean {\n return this.timer !== null;\n }\n}\n","import type { FlagValue, EvaluationContext, ConnectionStatus } from './types.js';\nimport type { Logger } from './logger.js';\n\ninterface StreamCallbacks {\n onSnapshot: (flags: Record<string, FlagValue>, configs: Record<string, unknown>) => void;\n onDiff: (changes: DiffChange[]) => void;\n onConnectionChange: (status: ConnectionStatus) => void;\n onError: (err: Error) => void;\n logger: Logger;\n}\n\nexport interface DiffChange {\n type: 'flag' | 'config';\n key: string;\n value: FlagValue | unknown;\n deleted?: boolean;\n}\n\nconst KEEPALIVE_INTERVAL = 30_000;\nconst PONG_TIMEOUT = 10_000;\nconst BACKOFF_BASE = 1000;\nconst BACKOFF_MAX = 30_000;\n\nexport class StreamTransport {\n private baseUrl: string;\n private token: string;\n private callbacks: StreamCallbacks;\n private ws: WebSocket | null = null;\n private intentionallyClosed = false;\n private keepaliveTimer: ReturnType<typeof setInterval> | null = null;\n private pongTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectAttempts = 0;\n private lastEnv?: string;\n private lastContext?: EvaluationContext;\n\n constructor(baseUrl: string, token: string, callbacks: StreamCallbacks) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.token = token;\n this.callbacks = callbacks;\n }\n\n connect(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const wsUrl = this.baseUrl.replace(/^http/, 'ws') + `/stream/flags?token=${encodeURIComponent(this.token)}`;\n this.callbacks.logger.debug('WebSocket connecting', wsUrl);\n\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n\n const onOpen = () => {\n cleanup();\n this.reconnectAttempts = 0;\n this.callbacks.onConnectionChange('connected');\n this.startKeepalive();\n this.callbacks.logger.debug('WebSocket connected');\n resolve();\n };\n\n const onError = (event: Event) => {\n cleanup();\n const err = new Error('WebSocket connection failed');\n this.callbacks.logger.error('WebSocket connection error', err);\n reject(err);\n };\n\n const onClose = () => {\n cleanup();\n reject(new Error('WebSocket closed before open'));\n };\n\n const cleanup = () => {\n ws.removeEventListener('open', onOpen);\n ws.removeEventListener('error', onError);\n ws.removeEventListener('close', onClose);\n this.attachListeners(ws);\n };\n\n ws.addEventListener('open', onOpen);\n ws.addEventListener('error', onError);\n ws.addEventListener('close', onClose);\n });\n }\n\n subscribe(env?: string, context?: EvaluationContext): void {\n this.lastEnv = env;\n this.lastContext = context;\n this.send({ type: 'subscribe', env, context });\n }\n\n updateContext(context: EvaluationContext): void {\n this.lastContext = context;\n this.send({ type: 'update-context', context });\n }\n\n close(): void {\n this.intentionallyClosed = true;\n this.stopKeepalive();\n this.clearReconnectTimer();\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.callbacks.onConnectionChange('disconnected');\n }\n\n get connected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n private send(data: Record<string, unknown>): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(data));\n }\n }\n\n private attachListeners(ws: WebSocket): void {\n ws.addEventListener('message', (event) => {\n this.handleMessage(event);\n });\n\n ws.addEventListener('close', () => {\n this.stopKeepalive();\n if (!this.intentionallyClosed) {\n this.callbacks.logger.warn('WebSocket closed unexpectedly, reconnecting');\n this.callbacks.onConnectionChange('reconnecting');\n this.scheduleReconnect();\n }\n });\n\n ws.addEventListener('error', () => {\n if (!this.intentionallyClosed) {\n this.callbacks.onError(new Error('WebSocket error'));\n }\n });\n }\n\n private handleMessage(event: MessageEvent): void {\n let msg: { type: string; flags?: Record<string, FlagValue>; configs?: Record<string, unknown>; changes?: DiffChange[]; error?: string };\n try {\n msg = JSON.parse(typeof event.data === 'string' ? event.data : '');\n } catch {\n this.callbacks.logger.warn('Failed to parse WebSocket message');\n return;\n }\n\n switch (msg.type) {\n case 'snapshot':\n this.callbacks.logger.debug('Received snapshot');\n this.callbacks.onSnapshot(msg.flags ?? {}, msg.configs ?? {});\n break;\n case 'diff':\n this.callbacks.logger.debug('Received diff', msg.changes);\n this.callbacks.onDiff(msg.changes ?? []);\n break;\n case 'pong':\n this.resetPongTimeout();\n break;\n case 'error':\n this.callbacks.onError(new Error(msg.error ?? 'Server error'));\n break;\n }\n }\n\n private startKeepalive(): void {\n this.stopKeepalive();\n this.keepaliveTimer = setInterval(() => {\n this.send({ type: 'ping' });\n this.pongTimer = setTimeout(() => {\n this.callbacks.logger.warn('Pong timeout, reconnecting');\n this.ws?.close();\n }, PONG_TIMEOUT);\n }, KEEPALIVE_INTERVAL);\n }\n\n private stopKeepalive(): void {\n if (this.keepaliveTimer) {\n clearInterval(this.keepaliveTimer);\n this.keepaliveTimer = null;\n }\n this.resetPongTimeout();\n }\n\n private resetPongTimeout(): void {\n if (this.pongTimer) {\n clearTimeout(this.pongTimer);\n this.pongTimer = null;\n }\n }\n\n private scheduleReconnect(): void {\n this.clearReconnectTimer();\n const delay = Math.min(BACKOFF_BASE * Math.pow(2, this.reconnectAttempts), BACKOFF_MAX);\n this.reconnectAttempts++;\n this.callbacks.logger.debug(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);\n\n this.reconnectTimer = setTimeout(async () => {\n try {\n await this.connect();\n if (this.lastEnv || this.lastContext) {\n this.subscribe(this.lastEnv, this.lastContext);\n }\n } catch {\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n","import type {\n FlagValue,\n EvaluationContext,\n EdgeFlagsOptions,\n EdgeFlagsEvent,\n EventPayloadMap,\n ConnectionStatus,\n} from './types.js';\nimport { EdgeFlagsError } from './errors.js';\nimport { Logger } from './logger.js';\nimport { Emitter } from './emitter.js';\nimport { Cache } from './cache.js';\nimport { Fetcher } from './fetcher.js';\nimport { Poller } from './poller.js';\nimport { StreamTransport, type DiffChange } from './stream.js';\n\ninterface MockData {\n flags: Record<string, FlagValue>;\n configs: Record<string, unknown>;\n}\n\nconst DEFAULT_CONTEXT: EvaluationContext = { custom: {} };\nconst DEFAULT_POLL_INTERVAL = 60_000;\n\nexport class EdgeFlags {\n private cache: Cache;\n private emitter: Emitter;\n private logger: Logger;\n private fetcher: Fetcher | null;\n private poller: Poller | null = null;\n private stream: StreamTransport | null = null;\n private context: EvaluationContext;\n private pollingInterval: number;\n private transportMode: 'websocket' | 'polling';\n private ready = false;\n private mockData: MockData | null;\n private _connectionStatus: ConnectionStatus = 'disconnected';\n private baseUrl: string;\n private token: string;\n\n constructor(options: EdgeFlagsOptions) {\n const mock = (options as EdgeFlagsOptions & { _mock?: MockData })._mock ?? null;\n this.mockData = mock;\n this.cache = new Cache();\n this.emitter = new Emitter();\n this.logger = new Logger(options.debug ?? false);\n this.context = options.context ?? { ...DEFAULT_CONTEXT };\n this.pollingInterval = options.pollingInterval ?? DEFAULT_POLL_INTERVAL;\n this.transportMode = options.transport ?? 'websocket';\n this.baseUrl = options.baseUrl;\n this.token = options.token;\n\n if (mock) {\n this.fetcher = null;\n this.cache.seed(mock.flags, mock.configs);\n this.ready = true;\n this.logger.debug('Mock client created');\n } else {\n this.fetcher = new Fetcher(options.baseUrl, options.token);\n if (options.bootstrap) {\n this.cache.seed(\n options.bootstrap.flags ?? {},\n options.bootstrap.configs ?? {},\n );\n this.logger.debug('Bootstrap data loaded');\n }\n }\n }\n\n async init(): Promise<void> {\n if (this.mockData) {\n this.emitter.emit('ready', undefined);\n return;\n }\n\n if (this.transportMode !== 'polling') {\n try {\n await this.initStream();\n return;\n } catch {\n this.logger.warn('WebSocket unavailable, falling back to polling');\n }\n }\n\n await this.initPolling();\n }\n\n private async initStream(): Promise<void> {\n const snapshotReceived = new Promise<void>((resolve, reject) => {\n let resolved = false;\n const timeout = setTimeout(() => {\n if (!resolved) {\n resolved = true;\n reject(new Error('Snapshot timeout'));\n }\n }, 10_000);\n\n this.stream = new StreamTransport(this.baseUrl, this.token, {\n onSnapshot: (flags, configs) => {\n const changes = this.cache.update(flags, configs);\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n this.cache.seed(flags, configs);\n resolve();\n } else if (changes) {\n this.logger.debug('Stream snapshot changes', changes);\n this.emitter.emit('change', changes);\n }\n },\n onDiff: (diffChanges) => {\n this.applyDiff(diffChanges);\n },\n onConnectionChange: (status) => {\n this._connectionStatus = status;\n this.emitter.emit('connection', { status });\n },\n onError: (err) => {\n this.logger.error('Stream error', err);\n this.emitter.emit('error', err);\n },\n logger: this.logger,\n });\n });\n\n await this.stream!.connect();\n this.stream!.subscribe(this.context.environment, this.context);\n await snapshotReceived;\n\n this.ready = true;\n this.logger.debug('Initialized via WebSocket');\n this.emitter.emit('ready', undefined);\n }\n\n private async initPolling(): Promise<void> {\n try {\n await this.fetchAndSeed();\n this.ready = true;\n this.logger.debug('Initialized');\n this.emitter.emit('ready', undefined);\n\n this.poller = new Poller(\n this.pollingInterval,\n () => this.refresh(),\n (err) => {\n this.logger.error('Polling error', err);\n this.emitter.emit('error', err);\n },\n );\n this.poller.start();\n this.logger.debug(`Polling started (${this.pollingInterval}ms)`);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.logger.error('Init failed', error);\n this.emitter.emit('error', error);\n\n if (this.cache.allFlags() && Object.keys(this.cache.allFlags()).length > 0) {\n this.ready = true;\n this.logger.warn('Using bootstrap data after init failure');\n this.emitter.emit('ready', undefined);\n } else {\n throw error;\n }\n }\n }\n\n private applyDiff(changes: DiffChange[]): void {\n const flags: Record<string, FlagValue> = {};\n const configs: Record<string, unknown> = {};\n\n for (const change of changes) {\n if (change.type === 'flag') {\n flags[change.key] = change.value as FlagValue;\n } else if (change.type === 'config') {\n configs[change.key] = change.value;\n }\n }\n\n const existing = { ...this.cache.allFlags(), ...flags };\n const existingConfigs = { ...this.cache.allConfigs(), ...configs };\n const cacheChanges = this.cache.update(existing, existingConfigs);\n\n if (cacheChanges) {\n this.logger.debug('Diff changes detected', cacheChanges);\n this.emitter.emit('change', cacheChanges);\n }\n }\n\n flag(key: string): FlagValue | undefined;\n flag<T extends FlagValue>(key: string, defaultValue: T): T;\n flag(key: string, defaultValue?: FlagValue): FlagValue | undefined {\n const value = this.cache.getFlag(key);\n if (value === undefined) return defaultValue;\n return value;\n }\n\n config(key: string): unknown;\n config<T>(key: string, defaultValue: T): T;\n config(key: string, defaultValue?: unknown): unknown {\n const value = this.cache.getConfig(key);\n if (value === undefined) return defaultValue;\n return value;\n }\n\n allFlags(): Record<string, FlagValue> {\n return this.cache.allFlags();\n }\n\n allConfigs(): Record<string, unknown> {\n return this.cache.allConfigs();\n }\n\n async identify(context: EvaluationContext): Promise<void> {\n this.context = context;\n this.logger.debug('Context updated', context);\n if (this.ready && this.stream?.connected) {\n this.stream.updateContext(context);\n } else if (this.ready && this.fetcher) {\n await this.refresh();\n }\n }\n\n async refresh(): Promise<void> {\n if (!this.fetcher) return;\n\n this.logger.debug('Fetching evaluations');\n const data = await this.fetcher.fetchAll(this.context);\n const changes = this.cache.update(data.flags, data.configs);\n\n if (changes) {\n this.logger.debug('Changes detected', changes);\n this.emitter.emit('change', changes);\n }\n }\n\n private async fetchAndSeed(): Promise<void> {\n if (!this.fetcher) return;\n\n this.logger.debug('Fetching initial evaluations');\n const data = await this.fetcher.fetchAll(this.context);\n this.cache.seed(data.flags, data.configs);\n }\n\n on<E extends EdgeFlagsEvent>(\n event: E,\n fn: (payload: EventPayloadMap[E]) => void,\n ): () => void {\n return this.emitter.on(event, fn);\n }\n\n get isReady(): boolean {\n return this.ready;\n }\n\n get connectionStatus(): ConnectionStatus {\n return this._connectionStatus;\n }\n\n destroy(): void {\n this.stream?.close();\n this.stream = null;\n this.poller?.stop();\n this.poller = null;\n this.cache.clear();\n this.emitter.removeAll();\n this.ready = false;\n this._connectionStatus = 'disconnected';\n this.logger.debug('Destroyed');\n }\n}\n","import type { FlagValue, EdgeFlagsOptions } from './types.js';\nimport { EdgeFlags } from './client.js';\n\nexport interface MockOptions {\n flags?: Record<string, FlagValue>;\n configs?: Record<string, unknown>;\n}\n\nexport function createMockClient(options: MockOptions = {}): EdgeFlags {\n const client = new EdgeFlags({\n token: 'mock_token',\n baseUrl: 'http://localhost',\n _mock: {\n flags: options.flags ?? {},\n configs: options.configs ?? {},\n },\n } as EdgeFlagsOptions & { _mock: { flags: Record<string, FlagValue>; configs: Record<string, unknown> } });\n\n return client;\n}\n"]}
|