@fluxcontrolsdk/js-sdk 0.1.2 → 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/README.md CHANGED
@@ -17,10 +17,10 @@ yarn add @fluxcontrolsdk/js-sdk
17
17
  ```typescript
18
18
  import { FluxClient } from '@fluxcontrolsdk/js-sdk';
19
19
 
20
- // Initialize client
20
+ // Initialize client (apiUrl is required)
21
21
  const client = new FluxClient('your-sdk-key', {
22
- edgeUrl: 'https://edge.fluxcontrol.io',
23
- enableAnalytics: true
22
+ apiUrl: 'https://api.fluxcontrol.io/api/v1/sdk', // Required: FluxControl API endpoint
23
+ pollingIntervalMs: 60000 // Optional: polling interval in ms
24
24
  });
25
25
 
26
26
  // Create context
@@ -101,10 +101,13 @@ new FluxClient(sdkKey: string, config?: Config)
101
101
  ```
102
102
 
103
103
  **Config Options:**
104
- - `edgeUrl` - Edge evaluator URL (default: 'https://edge.fluxcontrol.io')
105
- - `pollingInterval` - Cache refresh interval in ms (default: 60000)
106
- - `enableAnalytics` - Enable event tracking (default: true)
107
- - `localStorage` - Use localStorage for caching (default: true)
104
+ - `apiUrl` - **Required**. FluxControl API endpoint URL (e.g., `'https://api.fluxcontrol.io/api/v1/sdk'`)
105
+ - `pollingIntervalMs` - Polling interval in milliseconds (default: 60000)
106
+ - `eventFlushIntervalMs` - Event flush interval in milliseconds (optional)
107
+ - `eventQueueSize` - Maximum event queue size (optional)
108
+ - `offlineMode` - Enable offline mode (default: false)
109
+ - `cacheFilePath` - Path for local cache file (optional)
110
+ - `timeout` - Request timeout in milliseconds (optional)
108
111
 
109
112
  #### Methods
110
113
 
package/dist/client.d.ts CHANGED
@@ -11,7 +11,7 @@ export declare class FluxClient {
11
11
  private evaluator;
12
12
  private ruleset;
13
13
  private pollingInterval;
14
- constructor(sdkKey: string, config?: Config);
14
+ constructor(sdkKey: string, config: Config);
15
15
  /**
16
16
  * Initialize the SDK (fetch ruleset).
17
17
  */
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;AAEtD;;;;GAIG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,eAAe,CAAM;gBAEjB,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW;IAe/C;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BnC;;;;;;OAMG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO;IAKhF,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAKhF,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAKhF,aAAa,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC;IAI7E,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO;IAMjG;;OAEG;IACH,OAAO,CAAC,QAAQ;IAahB;;OAEG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBjH,KAAK;CAGR"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;AAEtD;;;;GAIG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,eAAe,CAAM;gBAEjB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAmB1C;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BnC;;;;;;OAMG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO;IAKhF,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAKhF,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAKhF,aAAa,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC;IAI7E,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO;IAMjG;;OAEG;IACH,OAAO,CAAC,QAAQ;IAahB;;OAEG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBjH,KAAK;CAGR"}
package/dist/index.esm.js CHANGED
@@ -204,12 +204,15 @@ class Evaluator {
204
204
  * Downloads rulesets and evaluates flags locally.
205
205
  */
206
206
  class FluxClient {
207
- constructor(sdkKey, config = {}) {
207
+ constructor(sdkKey, config) {
208
208
  this.ruleset = null;
209
+ if (!config.apiUrl) {
210
+ throw new Error('[FluxClient] apiUrl is required. Please provide the FluxControl API endpoint (e.g., "https://api.fluxcontrol.io/api/v1/sdk")');
211
+ }
209
212
  this.sdkKey = sdkKey;
210
213
  this.config = {
211
- apiUrl: config.apiUrl || 'http://localhost:8000/api/v1/sdk',
212
- pollingIntervalMs: config.pollingIntervalMs || 60000,
214
+ environment: 'production',
215
+ pollingIntervalMs: 60000,
213
216
  ...config
214
217
  };
215
218
  this.evaluator = new Evaluator();
@@ -232,9 +235,8 @@ class FluxClient {
232
235
  */
233
236
  async fetchRuleset() {
234
237
  try {
235
- // Environment context is usually passed or inferred.
236
- // For now, hardcode or assume API defaults.
237
- const url = `${this.config.apiUrl}/ruleset?environment=production`;
238
+ const environment = this.config.environment || 'production';
239
+ const url = `${this.config.apiUrl}/ruleset?environment=${environment}`;
238
240
  const res = await fetch(url, {
239
241
  headers: {
240
242
  'Authorization': `Bearer ${this.sdkKey}`
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/evaluator.ts","../src/client.ts","../src/react.tsx","../src/index.ts"],"sourcesContent":["// import { createHash } from 'crypto';\nimport {\n Context,\n Ruleset,\n FlagConfig,\n TargetingRule,\n Condition,\n EvaluationResult,\n Variation,\n PercentageRollout,\n} from './types';\n\n/**\n * Evaluates feature flags against targeting rules.\n */\nexport class Evaluator {\n /**\n * Evaluate a flag.\n */\n evaluate(\n flagKey: string,\n context: Context,\n ruleset: Ruleset,\n defaultValue: any\n ): EvaluationResult {\n const flag = ruleset.flags[flagKey];\n\n if (!flag) {\n return {\n value: defaultValue,\n variationKey: undefined,\n reason: 'flag_not_found',\n };\n }\n\n // Evaluate targeting rules\n if (flag.rules) {\n // Sort by priority (lower numbers = higher priority, evaluated first)\n const sortedRules = [...flag.rules].sort((a: any, b: any) => {\n const priorityA = a.priority ?? 999;\n const priorityB = b.priority ?? 999;\n return priorityA - priorityB;\n });\n\n for (const rule of sortedRules) {\n if (this.evaluateConditions(rule.conditions, context, ruleset)) {\n // Rule matched\n if (rule.variationId) {\n return this.serveVariation(flag, rule.variationId, 'rule_match');\n } else if (rule.rollout) {\n // Handle boolean flag rollout format: {on: percentage}\n return this.serveBooleanRollout(\n flag,\n rule.rollout,\n context,\n 'percentage_rollout'\n );\n }\n }\n }\n }\n\n // No rules matched, return default variation\n return this.serveVariation(flag, flag.defaultVariationId, 'default');\n }\n\n /**\n * Evaluate all conditions in a rule.\n */\n private evaluateConditions(\n conditions: Condition[],\n context: Context,\n ruleset: Ruleset\n ): boolean {\n if (!conditions || conditions.length === 0) {\n return true;\n }\n\n return conditions.every((condition) =>\n this.evaluateCondition(condition, context, ruleset)\n );\n }\n\n /**\n * Evaluate a single condition.\n */\n private evaluateCondition(\n condition: Condition,\n context: Context,\n ruleset: Ruleset\n ): boolean {\n // Get attribute value from context\n let contextValue: any;\n if (condition.attribute === 'userId' || condition.attribute === 'user_id') {\n contextValue = context.userId;\n } else if (condition.attribute === 'sessionId') {\n contextValue = context.sessionId;\n } else {\n contextValue = context.attributes?.[condition.attribute];\n }\n\n switch (condition.operator) {\n case 'IS':\n return contextValue === condition.value;\n case 'IS_NOT':\n return contextValue !== condition.value;\n case 'CONTAINS':\n return String(contextValue).includes(String(condition.value));\n case 'DOES_NOT_CONTAIN':\n return !String(contextValue).includes(String(condition.value));\n case 'IN':\n // Check if contextValue is in the array of values\n if (Array.isArray(condition.value)) {\n return condition.value.map(String).includes(String(contextValue));\n }\n return String(contextValue) === String(condition.value);\n case 'ONE_OF':\n case 'IS_ONE_OF':\n return condition.values?.includes(contextValue) ?? false;\n case 'NOT_ONE_OF':\n return !condition.values?.includes(contextValue);\n case 'GREATER_THAN':\n return Number(contextValue) > Number(condition.value);\n case 'LESS_THAN':\n return Number(contextValue) < Number(condition.value);\n case 'IN_SEGMENT':\n if (condition.segment_key) {\n const segment = ruleset.segments[condition.segment_key];\n if (segment) {\n return this.evaluateConditions(segment.conditions, context, ruleset);\n }\n }\n return false;\n default:\n console.warn(`Unknown operator: ${condition.operator}`);\n return false;\n }\n }\n\n /**\n * Serve a specific variation.\n */\n private serveVariation(\n flag: FlagConfig,\n variationId: string,\n reason: string\n ): EvaluationResult {\n const variation = flag.variations.find((v) => v.id === variationId);\n\n if (!variation) {\n return {\n value: null,\n variationKey: undefined,\n reason: 'variation_not_found',\n };\n }\n\n return {\n value: variation.value,\n variationKey: variation.key,\n reason,\n };\n }\n\n /**\n * Serve variation based on percentage rollout.\n */\n private servePercentageRollout(\n flag: FlagConfig,\n rollout: PercentageRollout,\n context: Context,\n reason: string\n ): EvaluationResult {\n const userId = context.userId || context.sessionId || 'anonymous';\n const bucket = this.getBucket(userId, flag.key || 'default'); // FIXED: Use flag.key for consistency\n\n let cumulative = 0;\n for (const item of rollout.variations) {\n cumulative += item.weight;\n if (bucket < cumulative) {\n return {\n value: item.variation.value,\n variationKey: item.variation.key,\n reason,\n };\n }\n }\n\n // Fallback to last variation\n const lastItem = rollout.variations[rollout.variations.length - 1];\n return {\n value: lastItem.variation.value,\n variationKey: lastItem.variation.key,\n reason,\n };\n }\n\n /**\n * Serve variation based on boolean rollout (simplified format: {on: percentage}).\n * Used for boolean flags where 'on' represents the percentage for 'true'.\n */\n private serveBooleanRollout(\n flag: FlagConfig,\n rollout: { on: number },\n context: Context,\n reason: string\n ): EvaluationResult {\n const userId = context.userId || context.sessionId || 'anonymous';\n const bucket = this.getBucket(userId, flag.key || 'default'); // FIXED: Use flag.key instead of flag.salt\n const percentage = rollout.on || 0;\n\n // Bucket is 0-9999, so we need to scale percentage (0-100) to 0-9999\n const threshold = (percentage / 100) * 10000;\n\n if (bucket < threshold) {\n // User is in the rollout, serve 'true' variation\n const trueVar = flag.variations.find(v => v.value === true);\n if (trueVar) {\n return {\n value: trueVar.value,\n variationKey: trueVar.key,\n reason,\n };\n }\n }\n\n // User is not in rollout, serve 'false' variation\n const falseVar = flag.variations.find(v => v.value === false);\n if (falseVar) {\n return {\n value: falseVar.value,\n variationKey: falseVar.key,\n reason,\n };\n }\n\n // Fallback\n return {\n value: false,\n variationKey: undefined,\n reason: 'rollout_fallback',\n };\n }\n\n /**\n * Get consistent bucket (0-9999) for user using MD5 hash.\n */\n /**\n * Get consistent bucket (0-9999) for user using simple hash (DJB2).\n * Format: flagKey:userId (matches Python SDK for cross-SDK consistency)\n */\n private getBucket(userId: string, flagKey: string): number {\n const input = `${flagKey}:${userId}`; // FIXED: Match Python SDK format\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = ((hash << 5) + hash) + input.charCodeAt(i); /* hash * 33 + c */\n }\n return Math.abs(hash) % 10000;\n }\n}\n","import { Evaluator } from './evaluator';\nimport { Context, Config, EvaluationResult, Ruleset } from './types';\nexport { Context, Config, EvaluationResult, Ruleset };\n\n/**\n * FluxControl JavaScript SDK (Thick Client)\n * \n * Downloads rulesets and evaluates flags locally.\n */\nexport class FluxClient {\n private sdkKey: string;\n private config: Config;\n private evaluator: Evaluator;\n private ruleset: Ruleset | null = null;\n private pollingInterval: any;\n\n constructor(sdkKey: string, config: Config = {}) {\n this.sdkKey = sdkKey;\n this.config = {\n apiUrl: config.apiUrl || 'http://localhost:8000/api/v1/sdk',\n pollingIntervalMs: config.pollingIntervalMs || 60000,\n ...config\n };\n this.evaluator = new Evaluator();\n\n // Auto-init if in browser\n if (typeof window !== 'undefined') {\n this.init();\n }\n }\n\n /**\n * Initialize the SDK (fetch ruleset).\n */\n async init(): Promise<void> {\n await this.fetchRuleset();\n\n if (this.config.pollingIntervalMs && this.config.pollingIntervalMs > 0) {\n this.pollingInterval = setInterval(() => this.fetchRuleset(), this.config.pollingIntervalMs);\n }\n }\n\n /**\n * Fetch ruleset from API.\n */\n async fetchRuleset(): Promise<void> {\n try {\n // Environment context is usually passed or inferred.\n // For now, hardcode or assume API defaults.\n const url = `${this.config.apiUrl}/ruleset?environment=production`;\n\n const res = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${this.sdkKey}`\n }\n });\n\n if (res.ok) {\n this.ruleset = await res.json();\n // Optional: Save to localStorage for offline boot\n if (typeof window !== 'undefined') {\n localStorage.setItem(`flux_ruleset_${this.sdkKey}`, JSON.stringify(this.ruleset));\n }\n } else {\n console.warn('[FluxClient] Failed to fetch ruleset:', res.status);\n }\n } catch (e) {\n console.error('[FluxClient] Error fetching ruleset:', e);\n // Try load from local storage\n if (typeof window !== 'undefined' && !this.ruleset) {\n const stored = localStorage.getItem(`flux_ruleset_${this.sdkKey}`);\n if (stored) this.ruleset = JSON.parse(stored);\n }\n }\n }\n\n /**\n * Evaluate a boolean flag.\n * Note: Sync evaluation now possible if ruleset is loaded!\n * But we keep async signature if needed or make it sync?\n * Legacy SDK was async. Let's make it sync but helpful.\n * Actually, if init() is async, we can't guarantee ruleset is there immediately.\n */\n boolVariation(flagKey: string, context: Context, defaultValue: boolean): boolean {\n const result = this.evaluate(flagKey, context, defaultValue);\n return !!result;\n }\n\n stringVariation(flagKey: string, context: Context, defaultValue: string): string {\n const result = this.evaluate(flagKey, context, defaultValue);\n return String(result);\n }\n\n numberVariation(flagKey: string, context: Context, defaultValue: number): number {\n const result = this.evaluate(flagKey, context, defaultValue);\n return Number(result);\n }\n\n jsonVariation<T = any>(flagKey: string, context: Context, defaultValue: T): T {\n return this.evaluate(flagKey, context, defaultValue) as T;\n }\n\n isEnabled(flagKey: string, contextOrId: Context | string, defaultValue: boolean = false): boolean {\n // Compatibility helper\n const context = typeof contextOrId === 'string' ? { userId: contextOrId } : contextOrId;\n return this.boolVariation(flagKey, context, defaultValue);\n }\n\n /**\n * Internal evaluation.\n */\n private evaluate(flagKey: string, context: Context, defaultValue: any): any {\n if (!this.ruleset) {\n console.warn(`[FluxClient] Ruleset not loaded. Returning default for ${flagKey}`);\n return defaultValue;\n }\n\n const result = this.evaluator.evaluate(flagKey, context, this.ruleset, defaultValue);\n\n // TODO: Queue exposure event logic here\n\n return result.value;\n }\n\n /**\n * Track a custom event.\n */\n async track(eventName: string, context: Context, properties?: Record<string, any>, value?: number): Promise<void> {\n try {\n await fetch(`${this.config.apiUrl}/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sdkKey}`\n },\n body: JSON.stringify({\n events: [{\n type: 'custom',\n timestamp: new Date().toISOString(),\n eventName,\n context,\n properties,\n value\n }]\n })\n });\n } catch (e) {\n console.error('[FluxClient] Error tracking event:', e);\n }\n }\n\n close() {\n if (this.pollingInterval) clearInterval(this.pollingInterval);\n }\n}\n","/**\n * React hooks for FluxControl.\n * \n * Provides easy integration with React applications.\n */\n\nimport React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';\nimport { FluxClient, Context as FluxContext } from './client';\n\ninterface FluxProviderProps {\n sdkKey: string;\n config?: any;\n context?: FluxContext;\n children: ReactNode;\n}\n\ninterface FluxContextType {\n client: FluxClient | null;\n context: FluxContext;\n}\n\nconst FluxReactContext = createContext<FluxContextType>({\n client: null,\n context: {}\n});\n\n/**\n * Provider component for FluxControl.\n * \n * Wrap your app with this to enable hooks.\n * \n * @example\n * <FluxProvider sdkKey=\"your-key\" context={{ userId: \"user-123\" }}>\n * <App />\n * </FluxProvider>\n */\nexport function FluxProvider({ sdkKey, config, context = {}, children }: FluxProviderProps) {\n const [client] = useState(() => new FluxClient(sdkKey, config));\n\n useEffect(() => {\n return () => {\n client.close();\n };\n }, [client]);\n\n return (\n <FluxReactContext.Provider value={{ client, context }}>\n {children}\n </FluxReactContext.Provider>\n );\n}\n\n/**\n * Hook to evaluate a feature flag.\n * \n * @example\n * const checkoutFlow = useFeature('checkout-flow', 'standard');\n * if (checkoutFlow === 'one-click') {\n * return <OneClickCheckout />;\n * }\n */\nexport function useFeature<T = any>(\n flagKey: string,\n defaultValue: T,\n contextOverride?: FluxContext\n): T {\n const { client, context: providerContext } = useContext(FluxReactContext);\n const [value, setValue] = useState<T>(defaultValue);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n if (!client) {\n setValue(defaultValue);\n setLoading(false);\n return;\n }\n\n const context = { ...providerContext, ...contextOverride };\n\n const evaluate = async () => {\n try {\n let result: any;\n\n // Determine type and call appropriate method\n if (typeof defaultValue === 'boolean') {\n result = await client.boolVariation(flagKey, context, defaultValue);\n } else if (typeof defaultValue === 'number') {\n result = await client.numberVariation(flagKey, context, defaultValue);\n } else if (typeof defaultValue === 'string') {\n result = await client.stringVariation(flagKey, context, defaultValue);\n } else {\n result = await client.jsonVariation(flagKey, context, defaultValue);\n }\n\n setValue(result as T);\n } catch (error) {\n console.error(`FluxControl: Error evaluating ${flagKey}:`, error);\n setValue(defaultValue);\n } finally {\n setLoading(false);\n }\n };\n\n evaluate();\n }, [client, flagKey, defaultValue, providerContext, contextOverride]);\n\n return value;\n}\n\n/**\n * Hook to get the FluxControl client instance.\n * \n * Use this for advanced scenarios like tracking custom events.\n * \n * @example\n * const client = useFluxClient();\n * client.track('button_clicked', context, { button: 'checkout' });\n */\nexport function useFluxClient(): FluxClient | null {\n const { client } = useContext(FluxReactContext);\n return client;\n}\n\n/**\n * Hook to track a custom event.\n * \n * @example\n * const trackPurchase = useTrack();\n * trackPurchase('purchase_completed', { productId: '123' }, 99.99);\n */\nexport function useTrack() {\n const { client, context } = useContext(FluxReactContext);\n\n return (\n eventName: string,\n properties?: Record<string, any>,\n value?: number,\n contextOverride?: FluxContext\n ) => {\n if (!client) {\n return;\n }\n\n const finalContext = { ...context, ...contextOverride };\n client.track(eventName, finalContext, properties, value);\n };\n}\n","/**\n * FluxControl JavaScript SDK\n * \n * @packageDocumentation\n */\n\nexport * from './types';\nexport * from './client';\nexport * from './react';\n\nimport { FluxClient } from './client';\nexport default FluxClient;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/evaluator.ts","../src/client.ts","../src/react.tsx","../src/index.ts"],"sourcesContent":["// import { createHash } from 'crypto';\nimport {\n Context,\n Ruleset,\n FlagConfig,\n TargetingRule,\n Condition,\n EvaluationResult,\n Variation,\n PercentageRollout,\n} from './types';\n\n/**\n * Evaluates feature flags against targeting rules.\n */\nexport class Evaluator {\n /**\n * Evaluate a flag.\n */\n evaluate(\n flagKey: string,\n context: Context,\n ruleset: Ruleset,\n defaultValue: any\n ): EvaluationResult {\n const flag = ruleset.flags[flagKey];\n\n if (!flag) {\n return {\n value: defaultValue,\n variationKey: undefined,\n reason: 'flag_not_found',\n };\n }\n\n // Evaluate targeting rules\n if (flag.rules) {\n // Sort by priority (lower numbers = higher priority, evaluated first)\n const sortedRules = [...flag.rules].sort((a: any, b: any) => {\n const priorityA = a.priority ?? 999;\n const priorityB = b.priority ?? 999;\n return priorityA - priorityB;\n });\n\n for (const rule of sortedRules) {\n if (this.evaluateConditions(rule.conditions, context, ruleset)) {\n // Rule matched\n if (rule.variationId) {\n return this.serveVariation(flag, rule.variationId, 'rule_match');\n } else if (rule.rollout) {\n // Handle boolean flag rollout format: {on: percentage}\n return this.serveBooleanRollout(\n flag,\n rule.rollout,\n context,\n 'percentage_rollout'\n );\n }\n }\n }\n }\n\n // No rules matched, return default variation\n return this.serveVariation(flag, flag.defaultVariationId, 'default');\n }\n\n /**\n * Evaluate all conditions in a rule.\n */\n private evaluateConditions(\n conditions: Condition[],\n context: Context,\n ruleset: Ruleset\n ): boolean {\n if (!conditions || conditions.length === 0) {\n return true;\n }\n\n return conditions.every((condition) =>\n this.evaluateCondition(condition, context, ruleset)\n );\n }\n\n /**\n * Evaluate a single condition.\n */\n private evaluateCondition(\n condition: Condition,\n context: Context,\n ruleset: Ruleset\n ): boolean {\n // Get attribute value from context\n let contextValue: any;\n if (condition.attribute === 'userId' || condition.attribute === 'user_id') {\n contextValue = context.userId;\n } else if (condition.attribute === 'sessionId') {\n contextValue = context.sessionId;\n } else {\n contextValue = context.attributes?.[condition.attribute];\n }\n\n switch (condition.operator) {\n case 'IS':\n return contextValue === condition.value;\n case 'IS_NOT':\n return contextValue !== condition.value;\n case 'CONTAINS':\n return String(contextValue).includes(String(condition.value));\n case 'DOES_NOT_CONTAIN':\n return !String(contextValue).includes(String(condition.value));\n case 'IN':\n // Check if contextValue is in the array of values\n if (Array.isArray(condition.value)) {\n return condition.value.map(String).includes(String(contextValue));\n }\n return String(contextValue) === String(condition.value);\n case 'ONE_OF':\n case 'IS_ONE_OF':\n return condition.values?.includes(contextValue) ?? false;\n case 'NOT_ONE_OF':\n return !condition.values?.includes(contextValue);\n case 'GREATER_THAN':\n return Number(contextValue) > Number(condition.value);\n case 'LESS_THAN':\n return Number(contextValue) < Number(condition.value);\n case 'IN_SEGMENT':\n if (condition.segment_key) {\n const segment = ruleset.segments[condition.segment_key];\n if (segment) {\n return this.evaluateConditions(segment.conditions, context, ruleset);\n }\n }\n return false;\n default:\n console.warn(`Unknown operator: ${condition.operator}`);\n return false;\n }\n }\n\n /**\n * Serve a specific variation.\n */\n private serveVariation(\n flag: FlagConfig,\n variationId: string,\n reason: string\n ): EvaluationResult {\n const variation = flag.variations.find((v) => v.id === variationId);\n\n if (!variation) {\n return {\n value: null,\n variationKey: undefined,\n reason: 'variation_not_found',\n };\n }\n\n return {\n value: variation.value,\n variationKey: variation.key,\n reason,\n };\n }\n\n /**\n * Serve variation based on percentage rollout.\n */\n private servePercentageRollout(\n flag: FlagConfig,\n rollout: PercentageRollout,\n context: Context,\n reason: string\n ): EvaluationResult {\n const userId = context.userId || context.sessionId || 'anonymous';\n const bucket = this.getBucket(userId, flag.key || 'default'); // FIXED: Use flag.key for consistency\n\n let cumulative = 0;\n for (const item of rollout.variations) {\n cumulative += item.weight;\n if (bucket < cumulative) {\n return {\n value: item.variation.value,\n variationKey: item.variation.key,\n reason,\n };\n }\n }\n\n // Fallback to last variation\n const lastItem = rollout.variations[rollout.variations.length - 1];\n return {\n value: lastItem.variation.value,\n variationKey: lastItem.variation.key,\n reason,\n };\n }\n\n /**\n * Serve variation based on boolean rollout (simplified format: {on: percentage}).\n * Used for boolean flags where 'on' represents the percentage for 'true'.\n */\n private serveBooleanRollout(\n flag: FlagConfig,\n rollout: { on: number },\n context: Context,\n reason: string\n ): EvaluationResult {\n const userId = context.userId || context.sessionId || 'anonymous';\n const bucket = this.getBucket(userId, flag.key || 'default'); // FIXED: Use flag.key instead of flag.salt\n const percentage = rollout.on || 0;\n\n // Bucket is 0-9999, so we need to scale percentage (0-100) to 0-9999\n const threshold = (percentage / 100) * 10000;\n\n if (bucket < threshold) {\n // User is in the rollout, serve 'true' variation\n const trueVar = flag.variations.find(v => v.value === true);\n if (trueVar) {\n return {\n value: trueVar.value,\n variationKey: trueVar.key,\n reason,\n };\n }\n }\n\n // User is not in rollout, serve 'false' variation\n const falseVar = flag.variations.find(v => v.value === false);\n if (falseVar) {\n return {\n value: falseVar.value,\n variationKey: falseVar.key,\n reason,\n };\n }\n\n // Fallback\n return {\n value: false,\n variationKey: undefined,\n reason: 'rollout_fallback',\n };\n }\n\n /**\n * Get consistent bucket (0-9999) for user using MD5 hash.\n */\n /**\n * Get consistent bucket (0-9999) for user using simple hash (DJB2).\n * Format: flagKey:userId (matches Python SDK for cross-SDK consistency)\n */\n private getBucket(userId: string, flagKey: string): number {\n const input = `${flagKey}:${userId}`; // FIXED: Match Python SDK format\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = ((hash << 5) + hash) + input.charCodeAt(i); /* hash * 33 + c */\n }\n return Math.abs(hash) % 10000;\n }\n}\n","import { Evaluator } from './evaluator';\nimport { Context, Config, EvaluationResult, Ruleset } from './types';\nexport { Context, Config, EvaluationResult, Ruleset };\n\n/**\n * FluxControl JavaScript SDK (Thick Client)\n * \n * Downloads rulesets and evaluates flags locally.\n */\nexport class FluxClient {\n private sdkKey: string;\n private config: Config;\n private evaluator: Evaluator;\n private ruleset: Ruleset | null = null;\n private pollingInterval: any;\n\n constructor(sdkKey: string, config: Config) {\n if (!config.apiUrl) {\n throw new Error('[FluxClient] apiUrl is required. Please provide the FluxControl API endpoint (e.g., \"https://api.fluxcontrol.io/api/v1/sdk\")');\n }\n\n this.sdkKey = sdkKey;\n this.config = {\n environment: 'production',\n pollingIntervalMs: 60000,\n ...config\n };\n this.evaluator = new Evaluator();\n\n // Auto-init if in browser\n if (typeof window !== 'undefined') {\n this.init();\n }\n }\n\n /**\n * Initialize the SDK (fetch ruleset).\n */\n async init(): Promise<void> {\n await this.fetchRuleset();\n\n if (this.config.pollingIntervalMs && this.config.pollingIntervalMs > 0) {\n this.pollingInterval = setInterval(() => this.fetchRuleset(), this.config.pollingIntervalMs);\n }\n }\n\n /**\n * Fetch ruleset from API.\n */\n async fetchRuleset(): Promise<void> {\n try {\n const environment = this.config.environment || 'production';\n const url = `${this.config.apiUrl}/ruleset?environment=${environment}`;\n\n const res = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${this.sdkKey}`\n }\n });\n\n if (res.ok) {\n this.ruleset = await res.json();\n // Optional: Save to localStorage for offline boot\n if (typeof window !== 'undefined') {\n localStorage.setItem(`flux_ruleset_${this.sdkKey}`, JSON.stringify(this.ruleset));\n }\n } else {\n console.warn('[FluxClient] Failed to fetch ruleset:', res.status);\n }\n } catch (e) {\n console.error('[FluxClient] Error fetching ruleset:', e);\n // Try load from local storage\n if (typeof window !== 'undefined' && !this.ruleset) {\n const stored = localStorage.getItem(`flux_ruleset_${this.sdkKey}`);\n if (stored) this.ruleset = JSON.parse(stored);\n }\n }\n }\n\n /**\n * Evaluate a boolean flag.\n * Note: Sync evaluation now possible if ruleset is loaded!\n * But we keep async signature if needed or make it sync?\n * Legacy SDK was async. Let's make it sync but helpful.\n * Actually, if init() is async, we can't guarantee ruleset is there immediately.\n */\n boolVariation(flagKey: string, context: Context, defaultValue: boolean): boolean {\n const result = this.evaluate(flagKey, context, defaultValue);\n return !!result;\n }\n\n stringVariation(flagKey: string, context: Context, defaultValue: string): string {\n const result = this.evaluate(flagKey, context, defaultValue);\n return String(result);\n }\n\n numberVariation(flagKey: string, context: Context, defaultValue: number): number {\n const result = this.evaluate(flagKey, context, defaultValue);\n return Number(result);\n }\n\n jsonVariation<T = any>(flagKey: string, context: Context, defaultValue: T): T {\n return this.evaluate(flagKey, context, defaultValue) as T;\n }\n\n isEnabled(flagKey: string, contextOrId: Context | string, defaultValue: boolean = false): boolean {\n // Compatibility helper\n const context = typeof contextOrId === 'string' ? { userId: contextOrId } : contextOrId;\n return this.boolVariation(flagKey, context, defaultValue);\n }\n\n /**\n * Internal evaluation.\n */\n private evaluate(flagKey: string, context: Context, defaultValue: any): any {\n if (!this.ruleset) {\n console.warn(`[FluxClient] Ruleset not loaded. Returning default for ${flagKey}`);\n return defaultValue;\n }\n\n const result = this.evaluator.evaluate(flagKey, context, this.ruleset, defaultValue);\n\n // TODO: Queue exposure event logic here\n\n return result.value;\n }\n\n /**\n * Track a custom event.\n */\n async track(eventName: string, context: Context, properties?: Record<string, any>, value?: number): Promise<void> {\n try {\n await fetch(`${this.config.apiUrl}/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sdkKey}`\n },\n body: JSON.stringify({\n events: [{\n type: 'custom',\n timestamp: new Date().toISOString(),\n eventName,\n context,\n properties,\n value\n }]\n })\n });\n } catch (e) {\n console.error('[FluxClient] Error tracking event:', e);\n }\n }\n\n close() {\n if (this.pollingInterval) clearInterval(this.pollingInterval);\n }\n}\n","/**\n * React hooks for FluxControl.\n * \n * Provides easy integration with React applications.\n */\n\nimport React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';\nimport { FluxClient, Context as FluxContext } from './client';\n\ninterface FluxProviderProps {\n sdkKey: string;\n config?: any;\n context?: FluxContext;\n children: ReactNode;\n}\n\ninterface FluxContextType {\n client: FluxClient | null;\n context: FluxContext;\n}\n\nconst FluxReactContext = createContext<FluxContextType>({\n client: null,\n context: {}\n});\n\n/**\n * Provider component for FluxControl.\n * \n * Wrap your app with this to enable hooks.\n * \n * @example\n * <FluxProvider sdkKey=\"your-key\" context={{ userId: \"user-123\" }}>\n * <App />\n * </FluxProvider>\n */\nexport function FluxProvider({ sdkKey, config, context = {}, children }: FluxProviderProps) {\n const [client] = useState(() => new FluxClient(sdkKey, config));\n\n useEffect(() => {\n return () => {\n client.close();\n };\n }, [client]);\n\n return (\n <FluxReactContext.Provider value={{ client, context }}>\n {children}\n </FluxReactContext.Provider>\n );\n}\n\n/**\n * Hook to evaluate a feature flag.\n * \n * @example\n * const checkoutFlow = useFeature('checkout-flow', 'standard');\n * if (checkoutFlow === 'one-click') {\n * return <OneClickCheckout />;\n * }\n */\nexport function useFeature<T = any>(\n flagKey: string,\n defaultValue: T,\n contextOverride?: FluxContext\n): T {\n const { client, context: providerContext } = useContext(FluxReactContext);\n const [value, setValue] = useState<T>(defaultValue);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n if (!client) {\n setValue(defaultValue);\n setLoading(false);\n return;\n }\n\n const context = { ...providerContext, ...contextOverride };\n\n const evaluate = async () => {\n try {\n let result: any;\n\n // Determine type and call appropriate method\n if (typeof defaultValue === 'boolean') {\n result = await client.boolVariation(flagKey, context, defaultValue);\n } else if (typeof defaultValue === 'number') {\n result = await client.numberVariation(flagKey, context, defaultValue);\n } else if (typeof defaultValue === 'string') {\n result = await client.stringVariation(flagKey, context, defaultValue);\n } else {\n result = await client.jsonVariation(flagKey, context, defaultValue);\n }\n\n setValue(result as T);\n } catch (error) {\n console.error(`FluxControl: Error evaluating ${flagKey}:`, error);\n setValue(defaultValue);\n } finally {\n setLoading(false);\n }\n };\n\n evaluate();\n }, [client, flagKey, defaultValue, providerContext, contextOverride]);\n\n return value;\n}\n\n/**\n * Hook to get the FluxControl client instance.\n * \n * Use this for advanced scenarios like tracking custom events.\n * \n * @example\n * const client = useFluxClient();\n * client.track('button_clicked', context, { button: 'checkout' });\n */\nexport function useFluxClient(): FluxClient | null {\n const { client } = useContext(FluxReactContext);\n return client;\n}\n\n/**\n * Hook to track a custom event.\n * \n * @example\n * const trackPurchase = useTrack();\n * trackPurchase('purchase_completed', { productId: '123' }, 99.99);\n */\nexport function useTrack() {\n const { client, context } = useContext(FluxReactContext);\n\n return (\n eventName: string,\n properties?: Record<string, any>,\n value?: number,\n contextOverride?: FluxContext\n ) => {\n if (!client) {\n return;\n }\n\n const finalContext = { ...context, ...contextOverride };\n client.track(eventName, finalContext, properties, value);\n };\n}\n","/**\n * FluxControl JavaScript SDK\n * \n * @packageDocumentation\n */\n\nexport * from './types';\nexport * from './client';\nexport * from './react';\n\nimport { FluxClient } from './client';\nexport default FluxClient;\n"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -208,12 +208,15 @@
208
208
  * Downloads rulesets and evaluates flags locally.
209
209
  */
210
210
  class FluxClient {
211
- constructor(sdkKey, config = {}) {
211
+ constructor(sdkKey, config) {
212
212
  this.ruleset = null;
213
+ if (!config.apiUrl) {
214
+ throw new Error('[FluxClient] apiUrl is required. Please provide the FluxControl API endpoint (e.g., "https://api.fluxcontrol.io/api/v1/sdk")');
215
+ }
213
216
  this.sdkKey = sdkKey;
214
217
  this.config = {
215
- apiUrl: config.apiUrl || 'http://localhost:8000/api/v1/sdk',
216
- pollingIntervalMs: config.pollingIntervalMs || 60000,
218
+ environment: 'production',
219
+ pollingIntervalMs: 60000,
217
220
  ...config
218
221
  };
219
222
  this.evaluator = new Evaluator();
@@ -236,9 +239,8 @@
236
239
  */
237
240
  async fetchRuleset() {
238
241
  try {
239
- // Environment context is usually passed or inferred.
240
- // For now, hardcode or assume API defaults.
241
- const url = `${this.config.apiUrl}/ruleset?environment=production`;
242
+ const environment = this.config.environment || 'production';
243
+ const url = `${this.config.apiUrl}/ruleset?environment=${environment}`;
242
244
  const res = await fetch(url, {
243
245
  headers: {
244
246
  'Authorization': `Bearer ${this.sdkKey}`
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/evaluator.ts","../src/client.ts","../src/react.tsx","../src/index.ts"],"sourcesContent":["// import { createHash } from 'crypto';\nimport {\n Context,\n Ruleset,\n FlagConfig,\n TargetingRule,\n Condition,\n EvaluationResult,\n Variation,\n PercentageRollout,\n} from './types';\n\n/**\n * Evaluates feature flags against targeting rules.\n */\nexport class Evaluator {\n /**\n * Evaluate a flag.\n */\n evaluate(\n flagKey: string,\n context: Context,\n ruleset: Ruleset,\n defaultValue: any\n ): EvaluationResult {\n const flag = ruleset.flags[flagKey];\n\n if (!flag) {\n return {\n value: defaultValue,\n variationKey: undefined,\n reason: 'flag_not_found',\n };\n }\n\n // Evaluate targeting rules\n if (flag.rules) {\n // Sort by priority (lower numbers = higher priority, evaluated first)\n const sortedRules = [...flag.rules].sort((a: any, b: any) => {\n const priorityA = a.priority ?? 999;\n const priorityB = b.priority ?? 999;\n return priorityA - priorityB;\n });\n\n for (const rule of sortedRules) {\n if (this.evaluateConditions(rule.conditions, context, ruleset)) {\n // Rule matched\n if (rule.variationId) {\n return this.serveVariation(flag, rule.variationId, 'rule_match');\n } else if (rule.rollout) {\n // Handle boolean flag rollout format: {on: percentage}\n return this.serveBooleanRollout(\n flag,\n rule.rollout,\n context,\n 'percentage_rollout'\n );\n }\n }\n }\n }\n\n // No rules matched, return default variation\n return this.serveVariation(flag, flag.defaultVariationId, 'default');\n }\n\n /**\n * Evaluate all conditions in a rule.\n */\n private evaluateConditions(\n conditions: Condition[],\n context: Context,\n ruleset: Ruleset\n ): boolean {\n if (!conditions || conditions.length === 0) {\n return true;\n }\n\n return conditions.every((condition) =>\n this.evaluateCondition(condition, context, ruleset)\n );\n }\n\n /**\n * Evaluate a single condition.\n */\n private evaluateCondition(\n condition: Condition,\n context: Context,\n ruleset: Ruleset\n ): boolean {\n // Get attribute value from context\n let contextValue: any;\n if (condition.attribute === 'userId' || condition.attribute === 'user_id') {\n contextValue = context.userId;\n } else if (condition.attribute === 'sessionId') {\n contextValue = context.sessionId;\n } else {\n contextValue = context.attributes?.[condition.attribute];\n }\n\n switch (condition.operator) {\n case 'IS':\n return contextValue === condition.value;\n case 'IS_NOT':\n return contextValue !== condition.value;\n case 'CONTAINS':\n return String(contextValue).includes(String(condition.value));\n case 'DOES_NOT_CONTAIN':\n return !String(contextValue).includes(String(condition.value));\n case 'IN':\n // Check if contextValue is in the array of values\n if (Array.isArray(condition.value)) {\n return condition.value.map(String).includes(String(contextValue));\n }\n return String(contextValue) === String(condition.value);\n case 'ONE_OF':\n case 'IS_ONE_OF':\n return condition.values?.includes(contextValue) ?? false;\n case 'NOT_ONE_OF':\n return !condition.values?.includes(contextValue);\n case 'GREATER_THAN':\n return Number(contextValue) > Number(condition.value);\n case 'LESS_THAN':\n return Number(contextValue) < Number(condition.value);\n case 'IN_SEGMENT':\n if (condition.segment_key) {\n const segment = ruleset.segments[condition.segment_key];\n if (segment) {\n return this.evaluateConditions(segment.conditions, context, ruleset);\n }\n }\n return false;\n default:\n console.warn(`Unknown operator: ${condition.operator}`);\n return false;\n }\n }\n\n /**\n * Serve a specific variation.\n */\n private serveVariation(\n flag: FlagConfig,\n variationId: string,\n reason: string\n ): EvaluationResult {\n const variation = flag.variations.find((v) => v.id === variationId);\n\n if (!variation) {\n return {\n value: null,\n variationKey: undefined,\n reason: 'variation_not_found',\n };\n }\n\n return {\n value: variation.value,\n variationKey: variation.key,\n reason,\n };\n }\n\n /**\n * Serve variation based on percentage rollout.\n */\n private servePercentageRollout(\n flag: FlagConfig,\n rollout: PercentageRollout,\n context: Context,\n reason: string\n ): EvaluationResult {\n const userId = context.userId || context.sessionId || 'anonymous';\n const bucket = this.getBucket(userId, flag.key || 'default'); // FIXED: Use flag.key for consistency\n\n let cumulative = 0;\n for (const item of rollout.variations) {\n cumulative += item.weight;\n if (bucket < cumulative) {\n return {\n value: item.variation.value,\n variationKey: item.variation.key,\n reason,\n };\n }\n }\n\n // Fallback to last variation\n const lastItem = rollout.variations[rollout.variations.length - 1];\n return {\n value: lastItem.variation.value,\n variationKey: lastItem.variation.key,\n reason,\n };\n }\n\n /**\n * Serve variation based on boolean rollout (simplified format: {on: percentage}).\n * Used for boolean flags where 'on' represents the percentage for 'true'.\n */\n private serveBooleanRollout(\n flag: FlagConfig,\n rollout: { on: number },\n context: Context,\n reason: string\n ): EvaluationResult {\n const userId = context.userId || context.sessionId || 'anonymous';\n const bucket = this.getBucket(userId, flag.key || 'default'); // FIXED: Use flag.key instead of flag.salt\n const percentage = rollout.on || 0;\n\n // Bucket is 0-9999, so we need to scale percentage (0-100) to 0-9999\n const threshold = (percentage / 100) * 10000;\n\n if (bucket < threshold) {\n // User is in the rollout, serve 'true' variation\n const trueVar = flag.variations.find(v => v.value === true);\n if (trueVar) {\n return {\n value: trueVar.value,\n variationKey: trueVar.key,\n reason,\n };\n }\n }\n\n // User is not in rollout, serve 'false' variation\n const falseVar = flag.variations.find(v => v.value === false);\n if (falseVar) {\n return {\n value: falseVar.value,\n variationKey: falseVar.key,\n reason,\n };\n }\n\n // Fallback\n return {\n value: false,\n variationKey: undefined,\n reason: 'rollout_fallback',\n };\n }\n\n /**\n * Get consistent bucket (0-9999) for user using MD5 hash.\n */\n /**\n * Get consistent bucket (0-9999) for user using simple hash (DJB2).\n * Format: flagKey:userId (matches Python SDK for cross-SDK consistency)\n */\n private getBucket(userId: string, flagKey: string): number {\n const input = `${flagKey}:${userId}`; // FIXED: Match Python SDK format\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = ((hash << 5) + hash) + input.charCodeAt(i); /* hash * 33 + c */\n }\n return Math.abs(hash) % 10000;\n }\n}\n","import { Evaluator } from './evaluator';\nimport { Context, Config, EvaluationResult, Ruleset } from './types';\nexport { Context, Config, EvaluationResult, Ruleset };\n\n/**\n * FluxControl JavaScript SDK (Thick Client)\n * \n * Downloads rulesets and evaluates flags locally.\n */\nexport class FluxClient {\n private sdkKey: string;\n private config: Config;\n private evaluator: Evaluator;\n private ruleset: Ruleset | null = null;\n private pollingInterval: any;\n\n constructor(sdkKey: string, config: Config = {}) {\n this.sdkKey = sdkKey;\n this.config = {\n apiUrl: config.apiUrl || 'http://localhost:8000/api/v1/sdk',\n pollingIntervalMs: config.pollingIntervalMs || 60000,\n ...config\n };\n this.evaluator = new Evaluator();\n\n // Auto-init if in browser\n if (typeof window !== 'undefined') {\n this.init();\n }\n }\n\n /**\n * Initialize the SDK (fetch ruleset).\n */\n async init(): Promise<void> {\n await this.fetchRuleset();\n\n if (this.config.pollingIntervalMs && this.config.pollingIntervalMs > 0) {\n this.pollingInterval = setInterval(() => this.fetchRuleset(), this.config.pollingIntervalMs);\n }\n }\n\n /**\n * Fetch ruleset from API.\n */\n async fetchRuleset(): Promise<void> {\n try {\n // Environment context is usually passed or inferred.\n // For now, hardcode or assume API defaults.\n const url = `${this.config.apiUrl}/ruleset?environment=production`;\n\n const res = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${this.sdkKey}`\n }\n });\n\n if (res.ok) {\n this.ruleset = await res.json();\n // Optional: Save to localStorage for offline boot\n if (typeof window !== 'undefined') {\n localStorage.setItem(`flux_ruleset_${this.sdkKey}`, JSON.stringify(this.ruleset));\n }\n } else {\n console.warn('[FluxClient] Failed to fetch ruleset:', res.status);\n }\n } catch (e) {\n console.error('[FluxClient] Error fetching ruleset:', e);\n // Try load from local storage\n if (typeof window !== 'undefined' && !this.ruleset) {\n const stored = localStorage.getItem(`flux_ruleset_${this.sdkKey}`);\n if (stored) this.ruleset = JSON.parse(stored);\n }\n }\n }\n\n /**\n * Evaluate a boolean flag.\n * Note: Sync evaluation now possible if ruleset is loaded!\n * But we keep async signature if needed or make it sync?\n * Legacy SDK was async. Let's make it sync but helpful.\n * Actually, if init() is async, we can't guarantee ruleset is there immediately.\n */\n boolVariation(flagKey: string, context: Context, defaultValue: boolean): boolean {\n const result = this.evaluate(flagKey, context, defaultValue);\n return !!result;\n }\n\n stringVariation(flagKey: string, context: Context, defaultValue: string): string {\n const result = this.evaluate(flagKey, context, defaultValue);\n return String(result);\n }\n\n numberVariation(flagKey: string, context: Context, defaultValue: number): number {\n const result = this.evaluate(flagKey, context, defaultValue);\n return Number(result);\n }\n\n jsonVariation<T = any>(flagKey: string, context: Context, defaultValue: T): T {\n return this.evaluate(flagKey, context, defaultValue) as T;\n }\n\n isEnabled(flagKey: string, contextOrId: Context | string, defaultValue: boolean = false): boolean {\n // Compatibility helper\n const context = typeof contextOrId === 'string' ? { userId: contextOrId } : contextOrId;\n return this.boolVariation(flagKey, context, defaultValue);\n }\n\n /**\n * Internal evaluation.\n */\n private evaluate(flagKey: string, context: Context, defaultValue: any): any {\n if (!this.ruleset) {\n console.warn(`[FluxClient] Ruleset not loaded. Returning default for ${flagKey}`);\n return defaultValue;\n }\n\n const result = this.evaluator.evaluate(flagKey, context, this.ruleset, defaultValue);\n\n // TODO: Queue exposure event logic here\n\n return result.value;\n }\n\n /**\n * Track a custom event.\n */\n async track(eventName: string, context: Context, properties?: Record<string, any>, value?: number): Promise<void> {\n try {\n await fetch(`${this.config.apiUrl}/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sdkKey}`\n },\n body: JSON.stringify({\n events: [{\n type: 'custom',\n timestamp: new Date().toISOString(),\n eventName,\n context,\n properties,\n value\n }]\n })\n });\n } catch (e) {\n console.error('[FluxClient] Error tracking event:', e);\n }\n }\n\n close() {\n if (this.pollingInterval) clearInterval(this.pollingInterval);\n }\n}\n","/**\n * React hooks for FluxControl.\n * \n * Provides easy integration with React applications.\n */\n\nimport React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';\nimport { FluxClient, Context as FluxContext } from './client';\n\ninterface FluxProviderProps {\n sdkKey: string;\n config?: any;\n context?: FluxContext;\n children: ReactNode;\n}\n\ninterface FluxContextType {\n client: FluxClient | null;\n context: FluxContext;\n}\n\nconst FluxReactContext = createContext<FluxContextType>({\n client: null,\n context: {}\n});\n\n/**\n * Provider component for FluxControl.\n * \n * Wrap your app with this to enable hooks.\n * \n * @example\n * <FluxProvider sdkKey=\"your-key\" context={{ userId: \"user-123\" }}>\n * <App />\n * </FluxProvider>\n */\nexport function FluxProvider({ sdkKey, config, context = {}, children }: FluxProviderProps) {\n const [client] = useState(() => new FluxClient(sdkKey, config));\n\n useEffect(() => {\n return () => {\n client.close();\n };\n }, [client]);\n\n return (\n <FluxReactContext.Provider value={{ client, context }}>\n {children}\n </FluxReactContext.Provider>\n );\n}\n\n/**\n * Hook to evaluate a feature flag.\n * \n * @example\n * const checkoutFlow = useFeature('checkout-flow', 'standard');\n * if (checkoutFlow === 'one-click') {\n * return <OneClickCheckout />;\n * }\n */\nexport function useFeature<T = any>(\n flagKey: string,\n defaultValue: T,\n contextOverride?: FluxContext\n): T {\n const { client, context: providerContext } = useContext(FluxReactContext);\n const [value, setValue] = useState<T>(defaultValue);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n if (!client) {\n setValue(defaultValue);\n setLoading(false);\n return;\n }\n\n const context = { ...providerContext, ...contextOverride };\n\n const evaluate = async () => {\n try {\n let result: any;\n\n // Determine type and call appropriate method\n if (typeof defaultValue === 'boolean') {\n result = await client.boolVariation(flagKey, context, defaultValue);\n } else if (typeof defaultValue === 'number') {\n result = await client.numberVariation(flagKey, context, defaultValue);\n } else if (typeof defaultValue === 'string') {\n result = await client.stringVariation(flagKey, context, defaultValue);\n } else {\n result = await client.jsonVariation(flagKey, context, defaultValue);\n }\n\n setValue(result as T);\n } catch (error) {\n console.error(`FluxControl: Error evaluating ${flagKey}:`, error);\n setValue(defaultValue);\n } finally {\n setLoading(false);\n }\n };\n\n evaluate();\n }, [client, flagKey, defaultValue, providerContext, contextOverride]);\n\n return value;\n}\n\n/**\n * Hook to get the FluxControl client instance.\n * \n * Use this for advanced scenarios like tracking custom events.\n * \n * @example\n * const client = useFluxClient();\n * client.track('button_clicked', context, { button: 'checkout' });\n */\nexport function useFluxClient(): FluxClient | null {\n const { client } = useContext(FluxReactContext);\n return client;\n}\n\n/**\n * Hook to track a custom event.\n * \n * @example\n * const trackPurchase = useTrack();\n * trackPurchase('purchase_completed', { productId: '123' }, 99.99);\n */\nexport function useTrack() {\n const { client, context } = useContext(FluxReactContext);\n\n return (\n eventName: string,\n properties?: Record<string, any>,\n value?: number,\n contextOverride?: FluxContext\n ) => {\n if (!client) {\n return;\n }\n\n const finalContext = { ...context, ...contextOverride };\n client.track(eventName, finalContext, properties, value);\n };\n}\n","/**\n * FluxControl JavaScript SDK\n * \n * @packageDocumentation\n */\n\nexport * from './types';\nexport * from './client';\nexport * from './react';\n\nimport { FluxClient } from './client';\nexport default FluxClient;\n"],"names":["createContext","useState","useEffect","useContext"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/evaluator.ts","../src/client.ts","../src/react.tsx","../src/index.ts"],"sourcesContent":["// import { createHash } from 'crypto';\nimport {\n Context,\n Ruleset,\n FlagConfig,\n TargetingRule,\n Condition,\n EvaluationResult,\n Variation,\n PercentageRollout,\n} from './types';\n\n/**\n * Evaluates feature flags against targeting rules.\n */\nexport class Evaluator {\n /**\n * Evaluate a flag.\n */\n evaluate(\n flagKey: string,\n context: Context,\n ruleset: Ruleset,\n defaultValue: any\n ): EvaluationResult {\n const flag = ruleset.flags[flagKey];\n\n if (!flag) {\n return {\n value: defaultValue,\n variationKey: undefined,\n reason: 'flag_not_found',\n };\n }\n\n // Evaluate targeting rules\n if (flag.rules) {\n // Sort by priority (lower numbers = higher priority, evaluated first)\n const sortedRules = [...flag.rules].sort((a: any, b: any) => {\n const priorityA = a.priority ?? 999;\n const priorityB = b.priority ?? 999;\n return priorityA - priorityB;\n });\n\n for (const rule of sortedRules) {\n if (this.evaluateConditions(rule.conditions, context, ruleset)) {\n // Rule matched\n if (rule.variationId) {\n return this.serveVariation(flag, rule.variationId, 'rule_match');\n } else if (rule.rollout) {\n // Handle boolean flag rollout format: {on: percentage}\n return this.serveBooleanRollout(\n flag,\n rule.rollout,\n context,\n 'percentage_rollout'\n );\n }\n }\n }\n }\n\n // No rules matched, return default variation\n return this.serveVariation(flag, flag.defaultVariationId, 'default');\n }\n\n /**\n * Evaluate all conditions in a rule.\n */\n private evaluateConditions(\n conditions: Condition[],\n context: Context,\n ruleset: Ruleset\n ): boolean {\n if (!conditions || conditions.length === 0) {\n return true;\n }\n\n return conditions.every((condition) =>\n this.evaluateCondition(condition, context, ruleset)\n );\n }\n\n /**\n * Evaluate a single condition.\n */\n private evaluateCondition(\n condition: Condition,\n context: Context,\n ruleset: Ruleset\n ): boolean {\n // Get attribute value from context\n let contextValue: any;\n if (condition.attribute === 'userId' || condition.attribute === 'user_id') {\n contextValue = context.userId;\n } else if (condition.attribute === 'sessionId') {\n contextValue = context.sessionId;\n } else {\n contextValue = context.attributes?.[condition.attribute];\n }\n\n switch (condition.operator) {\n case 'IS':\n return contextValue === condition.value;\n case 'IS_NOT':\n return contextValue !== condition.value;\n case 'CONTAINS':\n return String(contextValue).includes(String(condition.value));\n case 'DOES_NOT_CONTAIN':\n return !String(contextValue).includes(String(condition.value));\n case 'IN':\n // Check if contextValue is in the array of values\n if (Array.isArray(condition.value)) {\n return condition.value.map(String).includes(String(contextValue));\n }\n return String(contextValue) === String(condition.value);\n case 'ONE_OF':\n case 'IS_ONE_OF':\n return condition.values?.includes(contextValue) ?? false;\n case 'NOT_ONE_OF':\n return !condition.values?.includes(contextValue);\n case 'GREATER_THAN':\n return Number(contextValue) > Number(condition.value);\n case 'LESS_THAN':\n return Number(contextValue) < Number(condition.value);\n case 'IN_SEGMENT':\n if (condition.segment_key) {\n const segment = ruleset.segments[condition.segment_key];\n if (segment) {\n return this.evaluateConditions(segment.conditions, context, ruleset);\n }\n }\n return false;\n default:\n console.warn(`Unknown operator: ${condition.operator}`);\n return false;\n }\n }\n\n /**\n * Serve a specific variation.\n */\n private serveVariation(\n flag: FlagConfig,\n variationId: string,\n reason: string\n ): EvaluationResult {\n const variation = flag.variations.find((v) => v.id === variationId);\n\n if (!variation) {\n return {\n value: null,\n variationKey: undefined,\n reason: 'variation_not_found',\n };\n }\n\n return {\n value: variation.value,\n variationKey: variation.key,\n reason,\n };\n }\n\n /**\n * Serve variation based on percentage rollout.\n */\n private servePercentageRollout(\n flag: FlagConfig,\n rollout: PercentageRollout,\n context: Context,\n reason: string\n ): EvaluationResult {\n const userId = context.userId || context.sessionId || 'anonymous';\n const bucket = this.getBucket(userId, flag.key || 'default'); // FIXED: Use flag.key for consistency\n\n let cumulative = 0;\n for (const item of rollout.variations) {\n cumulative += item.weight;\n if (bucket < cumulative) {\n return {\n value: item.variation.value,\n variationKey: item.variation.key,\n reason,\n };\n }\n }\n\n // Fallback to last variation\n const lastItem = rollout.variations[rollout.variations.length - 1];\n return {\n value: lastItem.variation.value,\n variationKey: lastItem.variation.key,\n reason,\n };\n }\n\n /**\n * Serve variation based on boolean rollout (simplified format: {on: percentage}).\n * Used for boolean flags where 'on' represents the percentage for 'true'.\n */\n private serveBooleanRollout(\n flag: FlagConfig,\n rollout: { on: number },\n context: Context,\n reason: string\n ): EvaluationResult {\n const userId = context.userId || context.sessionId || 'anonymous';\n const bucket = this.getBucket(userId, flag.key || 'default'); // FIXED: Use flag.key instead of flag.salt\n const percentage = rollout.on || 0;\n\n // Bucket is 0-9999, so we need to scale percentage (0-100) to 0-9999\n const threshold = (percentage / 100) * 10000;\n\n if (bucket < threshold) {\n // User is in the rollout, serve 'true' variation\n const trueVar = flag.variations.find(v => v.value === true);\n if (trueVar) {\n return {\n value: trueVar.value,\n variationKey: trueVar.key,\n reason,\n };\n }\n }\n\n // User is not in rollout, serve 'false' variation\n const falseVar = flag.variations.find(v => v.value === false);\n if (falseVar) {\n return {\n value: falseVar.value,\n variationKey: falseVar.key,\n reason,\n };\n }\n\n // Fallback\n return {\n value: false,\n variationKey: undefined,\n reason: 'rollout_fallback',\n };\n }\n\n /**\n * Get consistent bucket (0-9999) for user using MD5 hash.\n */\n /**\n * Get consistent bucket (0-9999) for user using simple hash (DJB2).\n * Format: flagKey:userId (matches Python SDK for cross-SDK consistency)\n */\n private getBucket(userId: string, flagKey: string): number {\n const input = `${flagKey}:${userId}`; // FIXED: Match Python SDK format\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = ((hash << 5) + hash) + input.charCodeAt(i); /* hash * 33 + c */\n }\n return Math.abs(hash) % 10000;\n }\n}\n","import { Evaluator } from './evaluator';\nimport { Context, Config, EvaluationResult, Ruleset } from './types';\nexport { Context, Config, EvaluationResult, Ruleset };\n\n/**\n * FluxControl JavaScript SDK (Thick Client)\n * \n * Downloads rulesets and evaluates flags locally.\n */\nexport class FluxClient {\n private sdkKey: string;\n private config: Config;\n private evaluator: Evaluator;\n private ruleset: Ruleset | null = null;\n private pollingInterval: any;\n\n constructor(sdkKey: string, config: Config) {\n if (!config.apiUrl) {\n throw new Error('[FluxClient] apiUrl is required. Please provide the FluxControl API endpoint (e.g., \"https://api.fluxcontrol.io/api/v1/sdk\")');\n }\n\n this.sdkKey = sdkKey;\n this.config = {\n environment: 'production',\n pollingIntervalMs: 60000,\n ...config\n };\n this.evaluator = new Evaluator();\n\n // Auto-init if in browser\n if (typeof window !== 'undefined') {\n this.init();\n }\n }\n\n /**\n * Initialize the SDK (fetch ruleset).\n */\n async init(): Promise<void> {\n await this.fetchRuleset();\n\n if (this.config.pollingIntervalMs && this.config.pollingIntervalMs > 0) {\n this.pollingInterval = setInterval(() => this.fetchRuleset(), this.config.pollingIntervalMs);\n }\n }\n\n /**\n * Fetch ruleset from API.\n */\n async fetchRuleset(): Promise<void> {\n try {\n const environment = this.config.environment || 'production';\n const url = `${this.config.apiUrl}/ruleset?environment=${environment}`;\n\n const res = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${this.sdkKey}`\n }\n });\n\n if (res.ok) {\n this.ruleset = await res.json();\n // Optional: Save to localStorage for offline boot\n if (typeof window !== 'undefined') {\n localStorage.setItem(`flux_ruleset_${this.sdkKey}`, JSON.stringify(this.ruleset));\n }\n } else {\n console.warn('[FluxClient] Failed to fetch ruleset:', res.status);\n }\n } catch (e) {\n console.error('[FluxClient] Error fetching ruleset:', e);\n // Try load from local storage\n if (typeof window !== 'undefined' && !this.ruleset) {\n const stored = localStorage.getItem(`flux_ruleset_${this.sdkKey}`);\n if (stored) this.ruleset = JSON.parse(stored);\n }\n }\n }\n\n /**\n * Evaluate a boolean flag.\n * Note: Sync evaluation now possible if ruleset is loaded!\n * But we keep async signature if needed or make it sync?\n * Legacy SDK was async. Let's make it sync but helpful.\n * Actually, if init() is async, we can't guarantee ruleset is there immediately.\n */\n boolVariation(flagKey: string, context: Context, defaultValue: boolean): boolean {\n const result = this.evaluate(flagKey, context, defaultValue);\n return !!result;\n }\n\n stringVariation(flagKey: string, context: Context, defaultValue: string): string {\n const result = this.evaluate(flagKey, context, defaultValue);\n return String(result);\n }\n\n numberVariation(flagKey: string, context: Context, defaultValue: number): number {\n const result = this.evaluate(flagKey, context, defaultValue);\n return Number(result);\n }\n\n jsonVariation<T = any>(flagKey: string, context: Context, defaultValue: T): T {\n return this.evaluate(flagKey, context, defaultValue) as T;\n }\n\n isEnabled(flagKey: string, contextOrId: Context | string, defaultValue: boolean = false): boolean {\n // Compatibility helper\n const context = typeof contextOrId === 'string' ? { userId: contextOrId } : contextOrId;\n return this.boolVariation(flagKey, context, defaultValue);\n }\n\n /**\n * Internal evaluation.\n */\n private evaluate(flagKey: string, context: Context, defaultValue: any): any {\n if (!this.ruleset) {\n console.warn(`[FluxClient] Ruleset not loaded. Returning default for ${flagKey}`);\n return defaultValue;\n }\n\n const result = this.evaluator.evaluate(flagKey, context, this.ruleset, defaultValue);\n\n // TODO: Queue exposure event logic here\n\n return result.value;\n }\n\n /**\n * Track a custom event.\n */\n async track(eventName: string, context: Context, properties?: Record<string, any>, value?: number): Promise<void> {\n try {\n await fetch(`${this.config.apiUrl}/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sdkKey}`\n },\n body: JSON.stringify({\n events: [{\n type: 'custom',\n timestamp: new Date().toISOString(),\n eventName,\n context,\n properties,\n value\n }]\n })\n });\n } catch (e) {\n console.error('[FluxClient] Error tracking event:', e);\n }\n }\n\n close() {\n if (this.pollingInterval) clearInterval(this.pollingInterval);\n }\n}\n","/**\n * React hooks for FluxControl.\n * \n * Provides easy integration with React applications.\n */\n\nimport React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';\nimport { FluxClient, Context as FluxContext } from './client';\n\ninterface FluxProviderProps {\n sdkKey: string;\n config?: any;\n context?: FluxContext;\n children: ReactNode;\n}\n\ninterface FluxContextType {\n client: FluxClient | null;\n context: FluxContext;\n}\n\nconst FluxReactContext = createContext<FluxContextType>({\n client: null,\n context: {}\n});\n\n/**\n * Provider component for FluxControl.\n * \n * Wrap your app with this to enable hooks.\n * \n * @example\n * <FluxProvider sdkKey=\"your-key\" context={{ userId: \"user-123\" }}>\n * <App />\n * </FluxProvider>\n */\nexport function FluxProvider({ sdkKey, config, context = {}, children }: FluxProviderProps) {\n const [client] = useState(() => new FluxClient(sdkKey, config));\n\n useEffect(() => {\n return () => {\n client.close();\n };\n }, [client]);\n\n return (\n <FluxReactContext.Provider value={{ client, context }}>\n {children}\n </FluxReactContext.Provider>\n );\n}\n\n/**\n * Hook to evaluate a feature flag.\n * \n * @example\n * const checkoutFlow = useFeature('checkout-flow', 'standard');\n * if (checkoutFlow === 'one-click') {\n * return <OneClickCheckout />;\n * }\n */\nexport function useFeature<T = any>(\n flagKey: string,\n defaultValue: T,\n contextOverride?: FluxContext\n): T {\n const { client, context: providerContext } = useContext(FluxReactContext);\n const [value, setValue] = useState<T>(defaultValue);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n if (!client) {\n setValue(defaultValue);\n setLoading(false);\n return;\n }\n\n const context = { ...providerContext, ...contextOverride };\n\n const evaluate = async () => {\n try {\n let result: any;\n\n // Determine type and call appropriate method\n if (typeof defaultValue === 'boolean') {\n result = await client.boolVariation(flagKey, context, defaultValue);\n } else if (typeof defaultValue === 'number') {\n result = await client.numberVariation(flagKey, context, defaultValue);\n } else if (typeof defaultValue === 'string') {\n result = await client.stringVariation(flagKey, context, defaultValue);\n } else {\n result = await client.jsonVariation(flagKey, context, defaultValue);\n }\n\n setValue(result as T);\n } catch (error) {\n console.error(`FluxControl: Error evaluating ${flagKey}:`, error);\n setValue(defaultValue);\n } finally {\n setLoading(false);\n }\n };\n\n evaluate();\n }, [client, flagKey, defaultValue, providerContext, contextOverride]);\n\n return value;\n}\n\n/**\n * Hook to get the FluxControl client instance.\n * \n * Use this for advanced scenarios like tracking custom events.\n * \n * @example\n * const client = useFluxClient();\n * client.track('button_clicked', context, { button: 'checkout' });\n */\nexport function useFluxClient(): FluxClient | null {\n const { client } = useContext(FluxReactContext);\n return client;\n}\n\n/**\n * Hook to track a custom event.\n * \n * @example\n * const trackPurchase = useTrack();\n * trackPurchase('purchase_completed', { productId: '123' }, 99.99);\n */\nexport function useTrack() {\n const { client, context } = useContext(FluxReactContext);\n\n return (\n eventName: string,\n properties?: Record<string, any>,\n value?: number,\n contextOverride?: FluxContext\n ) => {\n if (!client) {\n return;\n }\n\n const finalContext = { ...context, ...contextOverride };\n client.track(eventName, finalContext, properties, value);\n };\n}\n","/**\n * FluxControl JavaScript SDK\n * \n * @packageDocumentation\n */\n\nexport * from './types';\nexport * from './client';\nexport * from './react';\n\nimport { FluxClient } from './client';\nexport default FluxClient;\n"],"names":["createContext","useState","useEffect","useContext"],"mappings":"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"}
package/dist/react.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Provides easy integration with React applications.
5
5
  */
6
- import { ReactNode } from 'react';
6
+ import React, { ReactNode } from 'react';
7
7
  import { FluxClient, Context as FluxContext } from './client';
8
8
  interface FluxProviderProps {
9
9
  sdkKey: string;
@@ -21,7 +21,7 @@ interface FluxProviderProps {
21
21
  * <App />
22
22
  * </FluxProvider>
23
23
  */
24
- export declare function FluxProvider({ sdkKey, config, context, children }: FluxProviderProps): any;
24
+ export declare function FluxProvider({ sdkKey, config, context, children }: FluxProviderProps): React.JSX.Element;
25
25
  /**
26
26
  * Hook to evaluate a feature flag.
27
27
  *
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAc,EAAkD,SAAS,EAAE,MAAM,OAAO,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,UAAU,CAAC;AAE9D,UAAU,iBAAiB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;CACvB;AAYD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAY,EAAE,QAAQ,EAAE,EAAE,iBAAiB,OAczF;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,GAAG,EAC9B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,EACf,eAAe,CAAC,EAAE,WAAW,GAC9B,CAAC,CA0CH;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAGjD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,KAIhB,WAAW,MAAM,EACjB,aAAa,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAChC,QAAQ,MAAM,EACd,kBAAkB,WAAW,UASpC"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,EAAkD,SAAS,EAAE,MAAM,OAAO,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,UAAU,CAAC;AAE9D,UAAU,iBAAiB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;CACvB;AAYD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAY,EAAE,QAAQ,EAAE,EAAE,iBAAiB,qBAczF;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,GAAG,EAC9B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,EACf,eAAe,CAAC,EAAE,WAAW,GAC9B,CAAC,CA0CH;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAGjD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,KAIhB,WAAW,MAAM,EACjB,aAAa,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAChC,QAAQ,MAAM,EACd,kBAAkB,WAAW,UASpC"}
package/dist/types.d.ts CHANGED
@@ -10,7 +10,10 @@ export interface Context {
10
10
  * SDK configuration options.
11
11
  */
12
12
  export interface Config {
13
- apiUrl?: string;
13
+ /** Required: FluxControl API endpoint URL (e.g., 'https://api.fluxcontrol.io/api/v1/sdk') */
14
+ apiUrl: string;
15
+ /** Optional: Environment name (defaults to 'production') */
16
+ environment?: string;
14
17
  pollingIntervalMs?: number;
15
18
  eventFlushIntervalMs?: number;
16
19
  eventQueueSize?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluxcontrolsdk/js-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "FluxControl JavaScript SDK for feature flags and experimentation",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -48,13 +48,13 @@
48
48
  "@typescript-eslint/parser": "^6.17.0",
49
49
  "eslint": "^8.56.0",
50
50
  "jest": "^29.7.0",
51
+ "jest-environment-jsdom": "^30.2.0",
51
52
  "prettier": "^3.1.1",
52
53
  "rollup": "^4.9.2",
53
54
  "ts-jest": "^29.1.1",
54
55
  "tslib": "^2.6.2",
55
56
  "typescript": "^5.3.3"
56
57
  },
57
- "dependencies": {},
58
58
  "peerDependencies": {
59
59
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
60
60
  },
@@ -63,4 +63,4 @@
63
63
  "optional": true
64
64
  }
65
65
  }
66
- }
66
+ }