flipflag-sdk 1.1.0 → 1.1.2

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
@@ -35,7 +35,7 @@ const config: FlipFlagConfig = {
35
35
  projectId: "your-project-uuid",
36
36
  environment: "production", // optional: 'dev', 'staging', 'prod'
37
37
  userId: "user123", // optional: user identification for A/B testing
38
- baseUrl: "https://app.flipflag.ru", // optional, defaults to production
38
+ baseUrl: "https://app.flipflag.ru", // optional, defaults to https://app.flipflag.ru
39
39
  pullInterval: 60000, // optional: auto-refresh interval in ms (60 seconds)
40
40
  cacheTimeout: 30000, // optional, cache TTL in ms
41
41
  retryAttempts: 3, // optional, number of retry attempts
@@ -593,32 +593,6 @@ npm test
593
593
  npm run dev
594
594
  ```
595
595
 
596
- ## 🎮 Demo Projects
597
-
598
- Протестируйте SDK в действии! В папке `demo/` находятся полнофункциональные примеры:
599
-
600
- ### Быстрый запуск всех демо
601
-
602
- ```bash
603
- cd demo
604
- ./start-all.sh start
605
- ```
606
-
607
- ### Индивидуальный запуск
608
-
609
- ```bash
610
- # React demo
611
- cd demo/react-demo && npm install && npm link flipflag && npm start
612
-
613
- # Next.js demo
614
- cd demo/next-demo && npm install && npm link flipflag && npm run dev
615
-
616
- # Vue demo
617
- cd demo/vue-demo && npm install && npm link flipflag && npm run dev
618
- ```
619
-
620
- ### Что демонстрируют демо-проекты
621
-
622
596
  - ✅ **Feature Flags** - Управление видимостью функций
623
597
  - ✅ **A/B Testing** - Тестирование различных вариантов
624
598
  - ✅ **Caching** - Интеллектуальное кэширование
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  class FlipFlagSDK {
4
4
  constructor(config) {
5
5
  this.cache = new Map();
6
- this.defaultBaseUrl = "https://app.flipflag.ru/api";
6
+ this.defaultBaseUrl = "https://app.flipflag.ru";
7
7
  this.stateListeners = new Set();
8
8
  this.config = {
9
9
  baseUrl: this.defaultBaseUrl,
@@ -165,7 +165,7 @@ class FlipFlagSDK {
165
165
  */
166
166
  async fetchAllFlags() {
167
167
  try {
168
- return await this.makeRequest(`/sdk/flags/${this.config.projectId}`);
168
+ return await this.makeRequest(`/api/sdk/flags/${this.config.projectId}`);
169
169
  }
170
170
  catch (error) {
171
171
  console.error("Failed to fetch flags:", error);
@@ -177,7 +177,7 @@ class FlipFlagSDK {
177
177
  */
178
178
  async fetchAllABTests() {
179
179
  try {
180
- return await this.makeRequest(`/sdk/ab-tests/${this.config.projectId}`);
180
+ return await this.makeRequest(`/api/sdk/ab-tests/${this.config.projectId}`);
181
181
  }
182
182
  catch (error) {
183
183
  console.error("Failed to fetch A/B tests:", error);
@@ -200,7 +200,7 @@ class FlipFlagSDK {
200
200
  if (cached) {
201
201
  return cached;
202
202
  }
203
- const url = new URL(`/sdk/flags/${projectId}`, this.config.baseUrl);
203
+ const url = new URL(`/api/sdk/flags/${projectId}`, this.config.baseUrl);
204
204
  if (environment || this.config.environment) {
205
205
  url.searchParams.set("environment", environment || this.config.environment);
206
206
  }
@@ -228,7 +228,7 @@ class FlipFlagSDK {
228
228
  if (cached) {
229
229
  return cached;
230
230
  }
231
- const url = new URL(`/sdk/flags/${projectId}/${flagName}`, this.config.baseUrl);
231
+ const url = new URL(`/api/sdk/flags/${projectId}/${flagName}`, this.config.baseUrl);
232
232
  if (environment || this.config.environment) {
233
233
  url.searchParams.set("environment", environment || this.config.environment);
234
234
  }
@@ -250,7 +250,7 @@ class FlipFlagSDK {
250
250
  if (cached) {
251
251
  return cached;
252
252
  }
253
- const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}`;
253
+ const url = new URL(`/api/sdk/ab-test/${projectId}/${testName}`, this.config.baseUrl);
254
254
  const response = await this.makeRequest(url, {
255
255
  headers: {
256
256
  "X-User-ID": userId,
@@ -264,7 +264,7 @@ class FlipFlagSDK {
264
264
  * Record an A/B test event
265
265
  */
266
266
  async recordAbTestEvent(testName, userId, event, variantId, eventData, projectId = this.config.projectId) {
267
- const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}/event`;
267
+ const url = new URL(`/api/sdk/ab-test/${projectId}/${testName}/event`, this.config.baseUrl);
268
268
  return this.makeRequest(url, {
269
269
  method: "POST",
270
270
  headers: {
@@ -287,7 +287,7 @@ class FlipFlagSDK {
287
287
  if (cached) {
288
288
  return cached;
289
289
  }
290
- const url = `${this.config.baseUrl}/sdk/ab-tests/${projectId}`;
290
+ const url = new URL(`/api/sdk/ab-tests/${projectId}`, this.config.baseUrl);
291
291
  const response = await this.makeRequest(url);
292
292
  this.setCache(cacheKey, response, this.config.cacheTimeout);
293
293
  return response;
@@ -310,6 +310,13 @@ class FlipFlagSDK {
310
310
  this.config = { ...this.config, ...newConfig };
311
311
  }
312
312
  async makeRequest(url, options = {}) {
313
+ var _a;
314
+ // Convert URL object to string if needed
315
+ const urlString = url instanceof URL ? url.toString() : url;
316
+ // If URL starts with '/', prepend baseUrl and handle trailing slashes
317
+ const fullUrl = urlString.startsWith("/")
318
+ ? `${((_a = this.config.baseUrl) === null || _a === void 0 ? void 0 : _a.replace(/\/$/, "")) || this.defaultBaseUrl}${urlString}`
319
+ : urlString;
313
320
  const headers = {
314
321
  "X-API-Key": this.config.apiKey,
315
322
  "Content-Type": "application/json",
@@ -319,7 +326,7 @@ class FlipFlagSDK {
319
326
  ...options,
320
327
  headers,
321
328
  };
322
- return this.makeRequestWithRetry(url, requestOptions);
329
+ return this.makeRequestWithRetry(fullUrl, requestOptions);
323
330
  }
324
331
  async makeRequestWithRetry(url, options, retryOptions = {
325
332
  attempts: this.config.retryAttempts,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/core/FlipFlagSDK.ts"],"sourcesContent":["import {\n FlipFlagConfig,\n FeatureFlagResponse,\n FeatureFlagsResponse,\n ABTestResponse,\n ABTestEventResponse,\n ABTestsResponse,\n FlipFlagError,\n CacheEntry,\n RetryOptions,\n SDKState,\n IdentifyUserOptions,\n} from \"../types\";\n\nexport class FlipFlagSDK {\n private config: FlipFlagConfig;\n private cache = new Map<string, CacheEntry<any>>();\n private defaultBaseUrl = \"https://app.flipflag.ru/api\";\n private pullIntervalId?: NodeJS.Timeout;\n private state: SDKState;\n private stateListeners: Set<(state: SDKState) => void> = new Set();\n\n constructor(config: FlipFlagConfig) {\n this.config = {\n baseUrl: this.defaultBaseUrl,\n cacheTimeout: 30000, // 30 seconds\n retryAttempts: 3,\n retryDelay: 1000, // 1 second\n pullInterval: 60000, // 1 minute\n ...config,\n };\n\n this.state = {\n flags: {},\n abTests: {},\n lastFetch: null,\n isLoading: false,\n error: null,\n };\n\n // Start automatic pulling if pullInterval is set\n if (this.config.pullInterval && this.config.pullInterval > 0) {\n this.startPulling();\n }\n }\n\n /**\n * Identify user for A/B testing and user-specific flags\n */\n identifyUser(options: IdentifyUserOptions): void {\n this.config.userId = options.userId;\n\n // Clear A/B test cache since user changed\n this.clearABTestCache();\n\n // If we have a user, we might want to refresh immediately\n if (this.config.pullInterval && this.config.pullInterval > 0) {\n this.pullData();\n }\n }\n\n /**\n * Get current SDK state\n */\n getState(): SDKState {\n return { ...this.state };\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(callback: (state: SDKState) => void): () => void {\n this.stateListeners.add(callback);\n\n // Return unsubscribe function\n return () => {\n this.stateListeners.delete(callback);\n };\n }\n\n /**\n * Get a feature flag value from current state\n */\n getFlagValue(flagName: string): boolean {\n return this.state.flags[flagName] ?? false;\n }\n\n /**\n * Get A/B test variant from current state\n */\n getABTestVariant(testName: string): ABTestResponse | null {\n return this.state.abTests[testName] || null;\n }\n\n /**\n * Start automatic data pulling\n */\n private startPulling(): void {\n if (this.pullIntervalId) {\n clearInterval(this.pullIntervalId);\n }\n\n this.pullIntervalId = setInterval(() => {\n this.pullData();\n }, this.config.pullInterval!);\n\n // Initial pull\n this.pullData();\n }\n\n /**\n * Stop automatic data pulling\n */\n stopPulling(): void {\n if (this.pullIntervalId) {\n clearInterval(this.pullIntervalId);\n this.pullIntervalId = undefined;\n }\n }\n\n /**\n * Pull fresh data from API\n */\n private async pullData(): Promise<void> {\n try {\n this.updateState({ isLoading: true, error: null });\n\n // Pull flags\n const flagsResponse = await this.fetchAllFlags();\n\n // Pull A/B tests if user is identified\n let abTestsResponse: ABTestsResponse | null = null;\n if (this.config.userId) {\n try {\n abTestsResponse = await this.fetchAllABTests();\n } catch (error) {\n console.warn(\"Failed to fetch A/B tests:\", error);\n }\n }\n\n const newState: Partial<SDKState> = {\n flags: flagsResponse?.flags || {},\n lastFetch: new Date(),\n isLoading: false,\n error: null,\n };\n\n if (abTestsResponse) {\n const abTestsMap: Record<string, ABTestResponse> = {};\n abTestsResponse.abTests.forEach((test) => {\n // For each test, get the variant for current user\n if (this.config.userId) {\n // This would normally fetch the variant, but for demo we'll simulate\n abTestsMap[test.name] = {\n testName: test.name,\n testId: test.id,\n variantId: \"variant_a\", // Default variant\n variant: test.variants[0] || {\n id: \"default\",\n name: \"Default\",\n value: null,\n weight: 100,\n },\n timestamp: new Date().toISOString(),\n };\n }\n });\n newState.abTests = abTestsMap;\n }\n\n this.updateState(newState);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n this.updateState({\n isLoading: false,\n error: errorMessage,\n });\n console.error(\"Failed to pull data:\", error);\n }\n }\n\n /**\n * Update state and notify listeners\n */\n private updateState(newState: Partial<SDKState>): void {\n this.state = { ...this.state, ...newState };\n\n // Notify all listeners\n this.stateListeners.forEach((callback) => {\n try {\n callback(this.state);\n } catch (error) {\n console.error(\"State listener error:\", error);\n }\n });\n }\n\n /**\n * Fetch all flags from API\n */\n private async fetchAllFlags(): Promise<FeatureFlagsResponse | null> {\n try {\n return await this.makeRequest<FeatureFlagsResponse>(\n `/sdk/flags/${this.config.projectId}`\n );\n } catch (error) {\n console.error(\"Failed to fetch flags:\", error);\n return null;\n }\n }\n\n /**\n * Fetch all A/B tests from API\n */\n private async fetchAllABTests(): Promise<ABTestsResponse | null> {\n try {\n return await this.makeRequest<ABTestsResponse>(\n `/sdk/ab-tests/${this.config.projectId}`\n );\n } catch (error) {\n console.error(\"Failed to fetch A/B tests:\", error);\n return null;\n }\n }\n\n /**\n * Clear A/B test cache\n */\n private clearABTestCache(): void {\n const abTestKeys = Array.from(this.cache.keys()).filter((key) =>\n key.startsWith(\"abtest:\")\n );\n abTestKeys.forEach((key) => this.cache.delete(key));\n }\n\n /**\n * Get all feature flags for a project\n */\n async getFlags(\n projectId: string = this.config.projectId,\n environment?: string\n ): Promise<FeatureFlagsResponse> {\n const cacheKey = `flags:${projectId}:${environment || \"all\"}`;\n const cached = this.getFromCache<FeatureFlagsResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(`/sdk/flags/${projectId}`, this.config.baseUrl);\n if (environment || this.config.environment) {\n url.searchParams.set(\n \"environment\",\n environment || this.config.environment!\n );\n }\n\n const response = await this.makeRequest<FeatureFlagsResponse>(\n url.toString()\n );\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Get a specific feature flag value\n */\n async getFlag(\n flagName: string,\n projectId: string = this.config.projectId,\n environment?: string\n ): Promise<FeatureFlagResponse> {\n // If we have the flag in state, return it immediately\n if (this.state.flags[flagName] !== undefined) {\n return {\n projectId: this.config.projectId,\n flagName,\n environment: this.config.environment || \"all\",\n value: this.state.flags[flagName],\n timestamp:\n this.state.lastFetch?.toISOString() || new Date().toISOString(),\n };\n }\n\n const cacheKey = `flag:${projectId}:${flagName}:${environment || \"all\"}`;\n const cached = this.getFromCache<FeatureFlagResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(\n `/sdk/flags/${projectId}/${flagName}`,\n this.config.baseUrl\n );\n if (environment || this.config.environment) {\n url.searchParams.set(\n \"environment\",\n environment || this.config.environment!\n );\n }\n\n const response = await this.makeRequest<FeatureFlagResponse>(\n url.toString()\n );\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Get A/B test variant for a user\n */\n async getAbTestVariant(\n testName: string,\n userId: string,\n projectId: string = this.config.projectId\n ): Promise<ABTestResponse> {\n // If we have the A/B test in state, return it immediately\n const stateVariant = this.state.abTests[testName];\n if (stateVariant && stateVariant.testName === testName) {\n return stateVariant;\n }\n\n const cacheKey = `abtest:${projectId}:${testName}:${userId}`;\n const cached = this.getFromCache<ABTestResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}`;\n\n const response = await this.makeRequest<ABTestResponse>(url, {\n headers: {\n \"X-User-ID\": userId,\n },\n });\n\n // Cache A/B test variants for longer since they shouldn't change frequently for a user\n this.setCache(cacheKey, response, this.config.cacheTimeout! * 10);\n\n return response;\n }\n\n /**\n * Record an A/B test event\n */\n async recordAbTestEvent(\n testName: string,\n userId: string,\n event: string,\n variantId: string,\n eventData?: Record<string, any>,\n projectId: string = this.config.projectId\n ): Promise<ABTestEventResponse> {\n const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}/event`;\n\n return this.makeRequest<ABTestEventResponse>(url, {\n method: \"POST\",\n headers: {\n \"X-User-ID\": userId,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n event,\n variantId,\n eventData,\n }),\n });\n }\n\n /**\n * Get all A/B tests for a project\n */\n async getAbTests(\n projectId: string = this.config.projectId\n ): Promise<ABTestsResponse> {\n const cacheKey = `abtests:${projectId}`;\n const cached = this.getFromCache<ABTestsResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = `${this.config.baseUrl}/sdk/ab-tests/${projectId}`;\n\n const response = await this.makeRequest<ABTestsResponse>(url);\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Clear cache for specific key or all cache\n */\n clearCache(key?: string): void {\n if (key) {\n this.cache.delete(key);\n } else {\n this.cache.clear();\n }\n }\n\n /**\n * Update configuration\n */\n updateConfig(newConfig: Partial<FlipFlagConfig>): void {\n this.config = { ...this.config, ...newConfig };\n }\n\n private async makeRequest<T>(\n url: string,\n options: RequestInit = {}\n ): Promise<T> {\n const headers = {\n \"X-API-Key\": this.config.apiKey,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n };\n\n const requestOptions: RequestInit = {\n ...options,\n headers,\n };\n\n return this.makeRequestWithRetry<T>(url, requestOptions);\n }\n\n private async makeRequestWithRetry<T>(\n url: string,\n options: RequestInit,\n retryOptions: RetryOptions = {\n attempts: this.config.retryAttempts!,\n delay: this.config.retryDelay!,\n backoff: 2,\n }\n ): Promise<T> {\n let lastError: Error;\n\n for (let attempt = 1; attempt <= retryOptions.attempts; attempt++) {\n try {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(\n `HTTP ${response.status}: ${errorData.error || response.statusText}`\n );\n }\n\n return await response.json();\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on client errors (4xx) except 429 (rate limit)\n if (error instanceof Error && error.message.includes(\"HTTP 4\")) {\n if (!error.message.includes(\"HTTP 429\")) {\n throw error;\n }\n }\n\n if (attempt < retryOptions.attempts) {\n const delay =\n retryOptions.delay * Math.pow(retryOptions.backoff, attempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n throw lastError!;\n }\n\n private getFromCache<T>(key: string): T | null {\n const entry = this.cache.get(key);\n\n if (!entry) {\n return null;\n }\n\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.data;\n }\n\n private setCache<T>(key: string, data: T, ttl: number): void {\n this.cache.set(key, {\n data,\n timestamp: Date.now(),\n ttl,\n });\n }\n\n /**\n * Cleanup method - should be called when SDK is no longer needed\n */\n public destroy(): void {\n this.stopPulling();\n this.stateListeners.clear();\n this.cache.clear();\n }\n}\n"],"names":[],"mappings":";;MAca,WAAW,CAAA;AAQtB,IAAA,WAAA,CAAY,MAAsB,EAAA;AAN1B,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,GAAG,EAA2B;QAC1C,IAAA,CAAA,cAAc,GAAG,6BAA6B;AAG9C,QAAA,IAAA,CAAA,cAAc,GAAmC,IAAI,GAAG,EAAE;QAGhE,IAAI,CAAC,MAAM,GAAG;YACZ,OAAO,EAAE,IAAI,CAAC,cAAc;YAC5B,YAAY,EAAE,KAAK;AACnB,YAAA,aAAa,EAAE,CAAC;YAChB,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,KAAK;AACnB,YAAA,GAAG,MAAM;SACV;QAED,IAAI,CAAC,KAAK,GAAG;AACX,YAAA,KAAK,EAAE,EAAE;AACT,YAAA,OAAO,EAAE,EAAE;AACX,YAAA,SAAS,EAAE,IAAI;AACf,YAAA,SAAS,EAAE,KAAK;AAChB,YAAA,KAAK,EAAE,IAAI;SACZ;;AAGD,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE;YAC5D,IAAI,CAAC,YAAY,EAAE;QACrB;IACF;AAEA;;AAEG;AACH,IAAA,YAAY,CAAC,OAA4B,EAAA;QACvC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM;;QAGnC,IAAI,CAAC,gBAAgB,EAAE;;AAGvB,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE;YAC5D,IAAI,CAAC,QAAQ,EAAE;QACjB;IACF;AAEA;;AAEG;IACH,QAAQ,GAAA;AACN,QAAA,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE;IAC1B;AAEA;;AAEG;AACH,IAAA,SAAS,CAAC,QAAmC,EAAA;AAC3C,QAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC;;AAGjC,QAAA,OAAO,MAAK;AACV,YAAA,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC;AACtC,QAAA,CAAC;IACH;AAEA;;AAEG;AACH,IAAA,YAAY,CAAC,QAAgB,EAAA;;QAC3B,OAAO,CAAA,EAAA,GAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,KAAK;IAC5C;AAEA;;AAEG;AACH,IAAA,gBAAgB,CAAC,QAAgB,EAAA;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI;IAC7C;AAEA;;AAEG;IACK,YAAY,GAAA;AAClB,QAAA,IAAI,IAAI,CAAC,cAAc,EAAE;AACvB,YAAA,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC;QACpC;AAEA,QAAA,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,MAAK;YACrC,IAAI,CAAC,QAAQ,EAAE;AACjB,QAAA,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,YAAa,CAAC;;QAG7B,IAAI,CAAC,QAAQ,EAAE;IACjB;AAEA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,IAAI,IAAI,CAAC,cAAc,EAAE;AACvB,YAAA,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC;AAClC,YAAA,IAAI,CAAC,cAAc,GAAG,SAAS;QACjC;IACF;AAEA;;AAEG;AACK,IAAA,MAAM,QAAQ,GAAA;AACpB,QAAA,IAAI;AACF,YAAA,IAAI,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;;AAGlD,YAAA,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE;;YAGhD,IAAI,eAAe,GAA2B,IAAI;AAClD,YAAA,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;AACtB,gBAAA,IAAI;AACF,oBAAA,eAAe,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE;gBAChD;gBAAE,OAAO,KAAK,EAAE;AACd,oBAAA,OAAO,CAAC,IAAI,CAAC,4BAA4B,EAAE,KAAK,CAAC;gBACnD;YACF;AAEA,YAAA,MAAM,QAAQ,GAAsB;gBAClC,KAAK,EAAE,CAAA,aAAa,KAAA,IAAA,IAAb,aAAa,uBAAb,aAAa,CAAE,KAAK,KAAI,EAAE;gBACjC,SAAS,EAAE,IAAI,IAAI,EAAE;AACrB,gBAAA,SAAS,EAAE,KAAK;AAChB,gBAAA,KAAK,EAAE,IAAI;aACZ;YAED,IAAI,eAAe,EAAE;gBACnB,MAAM,UAAU,GAAmC,EAAE;gBACrD,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;;AAEvC,oBAAA,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;;AAEtB,wBAAA,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;4BACtB,QAAQ,EAAE,IAAI,CAAC,IAAI;4BACnB,MAAM,EAAE,IAAI,CAAC,EAAE;4BACf,SAAS,EAAE,WAAW;AACtB,4BAAA,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI;AAC3B,gCAAA,EAAE,EAAE,SAAS;AACb,gCAAA,IAAI,EAAE,SAAS;AACf,gCAAA,KAAK,EAAE,IAAI;AACX,gCAAA,MAAM,EAAE,GAAG;AACZ,6BAAA;AACD,4BAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;yBACpC;oBACH;AACF,gBAAA,CAAC,CAAC;AACF,gBAAA,QAAQ,CAAC,OAAO,GAAG,UAAU;YAC/B;AAEA,YAAA,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;QAC5B;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,eAAe;YAC1D,IAAI,CAAC,WAAW,CAAC;AACf,gBAAA,SAAS,EAAE,KAAK;AAChB,gBAAA,KAAK,EAAE,YAAY;AACpB,aAAA,CAAC;AACF,YAAA,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC;QAC9C;IACF;AAEA;;AAEG;AACK,IAAA,WAAW,CAAC,QAA2B,EAAA;AAC7C,QAAA,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,QAAQ,EAAE;;QAG3C,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAI;AACvC,YAAA,IAAI;AACF,gBAAA,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;YACtB;YAAE,OAAO,KAAK,EAAE;AACd,gBAAA,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC;YAC/C;AACF,QAAA,CAAC,CAAC;IACJ;AAEA;;AAEG;AACK,IAAA,MAAM,aAAa,GAAA;AACzB,QAAA,IAAI;AACF,YAAA,OAAO,MAAM,IAAI,CAAC,WAAW,CAC3B,CAAA,WAAA,EAAc,IAAI,CAAC,MAAM,CAAC,SAAS,CAAA,CAAE,CACtC;QACH;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC;AAC9C,YAAA,OAAO,IAAI;QACb;IACF;AAEA;;AAEG;AACK,IAAA,MAAM,eAAe,GAAA;AAC3B,QAAA,IAAI;AACF,YAAA,OAAO,MAAM,IAAI,CAAC,WAAW,CAC3B,CAAA,cAAA,EAAiB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAA,CAAE,CACzC;QACH;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC;AAClD,YAAA,OAAO,IAAI;QACb;IACF;AAEA;;AAEG;IACK,gBAAgB,GAAA;AACtB,QAAA,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,KAC1D,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAC1B;AACD,QAAA,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACrD;AAEA;;AAEG;IACH,MAAM,QAAQ,CACZ,SAAA,GAAoB,IAAI,CAAC,MAAM,CAAC,SAAS,EACzC,WAAoB,EAAA;QAEpB,MAAM,QAAQ,GAAG,CAAA,MAAA,EAAS,SAAS,IAAI,WAAW,IAAI,KAAK,CAAA,CAAE;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAuB,QAAQ,CAAC;QAEhE,IAAI,MAAM,EAAE;AACV,YAAA,OAAO,MAAM;QACf;AAEA,QAAA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAA,WAAA,EAAc,SAAS,CAAA,CAAE,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;QACnE,IAAI,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;AAC1C,YAAA,GAAG,CAAC,YAAY,CAAC,GAAG,CAClB,aAAa,EACb,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,WAAY,CACxC;QACH;AAEA,QAAA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CACrC,GAAG,CAAC,QAAQ,EAAE,CACf;AACD,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,YAAa,CAAC;AAE5D,QAAA,OAAO,QAAQ;IACjB;AAEA;;AAEG;AACH,IAAA,MAAM,OAAO,CACX,QAAgB,EAChB,SAAA,GAAoB,IAAI,CAAC,MAAM,CAAC,SAAS,EACzC,WAAoB,EAAA;;;QAGpB,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,SAAS,EAAE;YAC5C,OAAO;AACL,gBAAA,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;gBAChC,QAAQ;AACR,gBAAA,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,KAAK;gBAC7C,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,gBAAA,SAAS,EACP,CAAA,CAAA,EAAA,GAAA,IAAI,CAAC,KAAK,CAAC,SAAS,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAE,WAAW,EAAE,KAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aAClE;QACH;QAEA,MAAM,QAAQ,GAAG,CAAA,KAAA,EAAQ,SAAS,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,EAAI,WAAW,IAAI,KAAK,CAAA,CAAE;QACxE,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAsB,QAAQ,CAAC;QAE/D,IAAI,MAAM,EAAE;AACV,YAAA,OAAO,MAAM;QACf;AAEA,QAAA,MAAM,GAAG,GAAG,IAAI,GAAG,CACjB,cAAc,SAAS,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAE,EACrC,IAAI,CAAC,MAAM,CAAC,OAAO,CACpB;QACD,IAAI,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;AAC1C,YAAA,GAAG,CAAC,YAAY,CAAC,GAAG,CAClB,aAAa,EACb,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,WAAY,CACxC;QACH;AAEA,QAAA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CACrC,GAAG,CAAC,QAAQ,EAAE,CACf;AACD,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,YAAa,CAAC;AAE5D,QAAA,OAAO,QAAQ;IACjB;AAEA;;AAEG;AACH,IAAA,MAAM,gBAAgB,CACpB,QAAgB,EAChB,MAAc,EACd,SAAA,GAAoB,IAAI,CAAC,MAAM,CAAC,SAAS,EAAA;;QAGzC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QACjD,IAAI,YAAY,IAAI,YAAY,CAAC,QAAQ,KAAK,QAAQ,EAAE;AACtD,YAAA,OAAO,YAAY;QACrB;QAEA,MAAM,QAAQ,GAAG,CAAA,OAAA,EAAU,SAAS,IAAI,QAAQ,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAiB,QAAQ,CAAC;QAE1D,IAAI,MAAM,EAAE;AACV,YAAA,OAAO,MAAM;QACf;AAEA,QAAA,MAAM,GAAG,GAAG,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA,aAAA,EAAgB,SAAS,CAAA,CAAA,EAAI,QAAQ,EAAE;QAEzE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAiB,GAAG,EAAE;AAC3D,YAAA,OAAO,EAAE;AACP,gBAAA,WAAW,EAAE,MAAM;AACpB,aAAA;AACF,SAAA,CAAC;;AAGF,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,YAAa,GAAG,EAAE,CAAC;AAEjE,QAAA,OAAO,QAAQ;IACjB;AAEA;;AAEG;AACH,IAAA,MAAM,iBAAiB,CACrB,QAAgB,EAChB,MAAc,EACd,KAAa,EACb,SAAiB,EACjB,SAA+B,EAC/B,SAAA,GAAoB,IAAI,CAAC,MAAM,CAAC,SAAS,EAAA;AAEzC,QAAA,MAAM,GAAG,GAAG,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA,aAAA,EAAgB,SAAS,CAAA,CAAA,EAAI,QAAQ,QAAQ;AAE/E,QAAA,OAAO,IAAI,CAAC,WAAW,CAAsB,GAAG,EAAE;AAChD,YAAA,MAAM,EAAE,MAAM;AACd,YAAA,OAAO,EAAE;AACP,gBAAA,WAAW,EAAE,MAAM;AACnB,gBAAA,cAAc,EAAE,kBAAkB;AACnC,aAAA;AACD,YAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,SAAS;gBACT,SAAS;aACV,CAAC;AACH,SAAA,CAAC;IACJ;AAEA;;AAEG;IACH,MAAM,UAAU,CACd,SAAA,GAAoB,IAAI,CAAC,MAAM,CAAC,SAAS,EAAA;AAEzC,QAAA,MAAM,QAAQ,GAAG,CAAA,QAAA,EAAW,SAAS,EAAE;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAkB,QAAQ,CAAC;QAE3D,IAAI,MAAM,EAAE;AACV,YAAA,OAAO,MAAM;QACf;QAEA,MAAM,GAAG,GAAG,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA,cAAA,EAAiB,SAAS,CAAA,CAAE;QAE9D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAkB,GAAG,CAAC;AAC7D,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,YAAa,CAAC;AAE5D,QAAA,OAAO,QAAQ;IACjB;AAEA;;AAEG;AACH,IAAA,UAAU,CAAC,GAAY,EAAA;QACrB,IAAI,GAAG,EAAE;AACP,YAAA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;QACxB;aAAO;AACL,YAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;QACpB;IACF;AAEA;;AAEG;AACH,IAAA,YAAY,CAAC,SAAkC,EAAA;AAC7C,QAAA,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,EAAE;IAChD;AAEQ,IAAA,MAAM,WAAW,CACvB,GAAW,EACX,UAAuB,EAAE,EAAA;AAEzB,QAAA,MAAM,OAAO,GAAG;AACd,YAAA,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;AAC/B,YAAA,cAAc,EAAE,kBAAkB;YAClC,GAAG,OAAO,CAAC,OAAO;SACnB;AAED,QAAA,MAAM,cAAc,GAAgB;AAClC,YAAA,GAAG,OAAO;YACV,OAAO;SACR;QAED,OAAO,IAAI,CAAC,oBAAoB,CAAI,GAAG,EAAE,cAAc,CAAC;IAC1D;AAEQ,IAAA,MAAM,oBAAoB,CAChC,GAAW,EACX,OAAoB,EACpB,YAAA,GAA6B;AAC3B,QAAA,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,aAAc;AACpC,QAAA,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,UAAW;AAC9B,QAAA,OAAO,EAAE,CAAC;AACX,KAAA,EAAA;AAED,QAAA,IAAI,SAAgB;AAEpB,QAAA,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE;AACjE,YAAA,IAAI;gBACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC;AAE1C,gBAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,oBAAA,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;AACzD,oBAAA,MAAM,IAAI,KAAK,CACb,CAAA,KAAA,EAAQ,QAAQ,CAAC,MAAM,CAAA,EAAA,EAAK,SAAS,CAAC,KAAK,IAAI,QAAQ,CAAC,UAAU,CAAA,CAAE,CACrE;gBACH;AAEA,gBAAA,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE;YAC9B;YAAE,OAAO,KAAK,EAAE;gBACd,SAAS,GAAG,KAAc;;AAG1B,gBAAA,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;oBAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;AACvC,wBAAA,MAAM,KAAK;oBACb;gBACF;AAEA,gBAAA,IAAI,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE;AACnC,oBAAA,MAAM,KAAK,GACT,YAAY,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,CAAC;AAClE,oBAAA,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBAC5D;YACF;QACF;AAEA,QAAA,MAAM,SAAU;IAClB;AAEQ,IAAA,YAAY,CAAI,GAAW,EAAA;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;QAEjC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE;AAC5C,YAAA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;AACtB,YAAA,OAAO,IAAI;QACb;QAEA,OAAO,KAAK,CAAC,IAAI;IACnB;AAEQ,IAAA,QAAQ,CAAI,GAAW,EAAE,IAAO,EAAE,GAAW,EAAA;AACnD,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,IAAI;AACJ,YAAA,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,GAAG;AACJ,SAAA,CAAC;IACJ;AAEA;;AAEG;IACI,OAAO,GAAA;QACZ,IAAI,CAAC,WAAW,EAAE;AAClB,QAAA,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE;AAC3B,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;IACpB;AACD;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../src/core/FlipFlagSDK.ts"],"sourcesContent":["import {\n FlipFlagConfig,\n FeatureFlagResponse,\n FeatureFlagsResponse,\n ABTestResponse,\n ABTestEventResponse,\n ABTestsResponse,\n FlipFlagError,\n CacheEntry,\n RetryOptions,\n SDKState,\n IdentifyUserOptions,\n} from \"../types\";\n\nexport class FlipFlagSDK {\n private config: FlipFlagConfig;\n private cache = new Map<string, CacheEntry<any>>();\n private defaultBaseUrl = \"https://app.flipflag.ru\";\n private pullIntervalId?: NodeJS.Timeout;\n private state: SDKState;\n private stateListeners: Set<(state: SDKState) => void> = new Set();\n\n constructor(config: FlipFlagConfig) {\n this.config = {\n baseUrl: this.defaultBaseUrl,\n cacheTimeout: 30000, // 30 seconds\n retryAttempts: 3,\n retryDelay: 1000, // 1 second\n pullInterval: 60000, // 1 minute\n ...config,\n };\n\n this.state = {\n flags: {},\n abTests: {},\n lastFetch: null,\n isLoading: false,\n error: null,\n };\n\n // Start automatic pulling if pullInterval is set\n if (this.config.pullInterval && this.config.pullInterval > 0) {\n this.startPulling();\n }\n }\n\n /**\n * Identify user for A/B testing and user-specific flags\n */\n identifyUser(options: IdentifyUserOptions): void {\n this.config.userId = options.userId;\n\n // Clear A/B test cache since user changed\n this.clearABTestCache();\n\n // If we have a user, we might want to refresh immediately\n if (this.config.pullInterval && this.config.pullInterval > 0) {\n this.pullData();\n }\n }\n\n /**\n * Get current SDK state\n */\n getState(): SDKState {\n return { ...this.state };\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(callback: (state: SDKState) => void): () => void {\n this.stateListeners.add(callback);\n\n // Return unsubscribe function\n return () => {\n this.stateListeners.delete(callback);\n };\n }\n\n /**\n * Get a feature flag value from current state\n */\n getFlagValue(flagName: string): boolean {\n return this.state.flags[flagName] ?? false;\n }\n\n /**\n * Get A/B test variant from current state\n */\n getABTestVariant(testName: string): ABTestResponse | null {\n return this.state.abTests[testName] || null;\n }\n\n /**\n * Start automatic data pulling\n */\n private startPulling(): void {\n if (this.pullIntervalId) {\n clearInterval(this.pullIntervalId);\n }\n\n this.pullIntervalId = setInterval(() => {\n this.pullData();\n }, this.config.pullInterval!);\n\n // Initial pull\n this.pullData();\n }\n\n /**\n * Stop automatic data pulling\n */\n stopPulling(): void {\n if (this.pullIntervalId) {\n clearInterval(this.pullIntervalId);\n this.pullIntervalId = undefined;\n }\n }\n\n /**\n * Pull fresh data from API\n */\n private async pullData(): Promise<void> {\n try {\n this.updateState({ isLoading: true, error: null });\n\n // Pull flags\n const flagsResponse = await this.fetchAllFlags();\n\n // Pull A/B tests if user is identified\n let abTestsResponse: ABTestsResponse | null = null;\n if (this.config.userId) {\n try {\n abTestsResponse = await this.fetchAllABTests();\n } catch (error) {\n console.warn(\"Failed to fetch A/B tests:\", error);\n }\n }\n\n const newState: Partial<SDKState> = {\n flags: flagsResponse?.flags || {},\n lastFetch: new Date(),\n isLoading: false,\n error: null,\n };\n\n if (abTestsResponse) {\n const abTestsMap: Record<string, ABTestResponse> = {};\n abTestsResponse.abTests.forEach((test) => {\n // For each test, get the variant for current user\n if (this.config.userId) {\n // This would normally fetch the variant, but for demo we'll simulate\n abTestsMap[test.name] = {\n testName: test.name,\n testId: test.id,\n variantId: \"variant_a\", // Default variant\n variant: test.variants[0] || {\n id: \"default\",\n name: \"Default\",\n value: null,\n weight: 100,\n },\n timestamp: new Date().toISOString(),\n };\n }\n });\n newState.abTests = abTestsMap;\n }\n\n this.updateState(newState);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n this.updateState({\n isLoading: false,\n error: errorMessage,\n });\n console.error(\"Failed to pull data:\", error);\n }\n }\n\n /**\n * Update state and notify listeners\n */\n private updateState(newState: Partial<SDKState>): void {\n this.state = { ...this.state, ...newState };\n\n // Notify all listeners\n this.stateListeners.forEach((callback) => {\n try {\n callback(this.state);\n } catch (error) {\n console.error(\"State listener error:\", error);\n }\n });\n }\n\n /**\n * Fetch all flags from API\n */\n private async fetchAllFlags(): Promise<FeatureFlagsResponse | null> {\n try {\n return await this.makeRequest<FeatureFlagsResponse>(\n `/api/sdk/flags/${this.config.projectId}`\n );\n } catch (error) {\n console.error(\"Failed to fetch flags:\", error);\n return null;\n }\n }\n\n /**\n * Fetch all A/B tests from API\n */\n private async fetchAllABTests(): Promise<ABTestsResponse | null> {\n try {\n return await this.makeRequest<ABTestsResponse>(\n `/api/sdk/ab-tests/${this.config.projectId}`\n );\n } catch (error) {\n console.error(\"Failed to fetch A/B tests:\", error);\n return null;\n }\n }\n\n /**\n * Clear A/B test cache\n */\n private clearABTestCache(): void {\n const abTestKeys = Array.from(this.cache.keys()).filter((key) =>\n key.startsWith(\"abtest:\")\n );\n abTestKeys.forEach((key) => this.cache.delete(key));\n }\n\n /**\n * Get all feature flags for a project\n */\n async getFlags(\n projectId: string = this.config.projectId,\n environment?: string\n ): Promise<FeatureFlagsResponse> {\n const cacheKey = `flags:${projectId}:${environment || \"all\"}`;\n const cached = this.getFromCache<FeatureFlagsResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(`/api/sdk/flags/${projectId}`, this.config.baseUrl);\n if (environment || this.config.environment) {\n url.searchParams.set(\n \"environment\",\n environment || this.config.environment!\n );\n }\n\n const response = await this.makeRequest<FeatureFlagsResponse>(\n url.toString()\n );\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Get a specific feature flag value\n */\n async getFlag(\n flagName: string,\n projectId: string = this.config.projectId,\n environment?: string\n ): Promise<FeatureFlagResponse> {\n // If we have the flag in state, return it immediately\n if (this.state.flags[flagName] !== undefined) {\n return {\n projectId: this.config.projectId,\n flagName,\n environment: this.config.environment || \"all\",\n value: this.state.flags[flagName],\n timestamp:\n this.state.lastFetch?.toISOString() || new Date().toISOString(),\n };\n }\n\n const cacheKey = `flag:${projectId}:${flagName}:${environment || \"all\"}`;\n const cached = this.getFromCache<FeatureFlagResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(\n `/api/sdk/flags/${projectId}/${flagName}`,\n this.config.baseUrl\n );\n if (environment || this.config.environment) {\n url.searchParams.set(\n \"environment\",\n environment || this.config.environment!\n );\n }\n\n const response = await this.makeRequest<FeatureFlagResponse>(\n url.toString()\n );\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Get A/B test variant for a user\n */\n async getAbTestVariant(\n testName: string,\n userId: string,\n projectId: string = this.config.projectId\n ): Promise<ABTestResponse> {\n // If we have the A/B test in state, return it immediately\n const stateVariant = this.state.abTests[testName];\n if (stateVariant && stateVariant.testName === testName) {\n return stateVariant;\n }\n\n const cacheKey = `abtest:${projectId}:${testName}:${userId}`;\n const cached = this.getFromCache<ABTestResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(\n `/api/sdk/ab-test/${projectId}/${testName}`,\n this.config.baseUrl\n );\n\n const response = await this.makeRequest<ABTestResponse>(url, {\n headers: {\n \"X-User-ID\": userId,\n },\n });\n\n // Cache A/B test variants for longer since they shouldn't change frequently for a user\n this.setCache(cacheKey, response, this.config.cacheTimeout! * 10);\n\n return response;\n }\n\n /**\n * Record an A/B test event\n */\n async recordAbTestEvent(\n testName: string,\n userId: string,\n event: string,\n variantId: string,\n eventData?: Record<string, any>,\n projectId: string = this.config.projectId\n ): Promise<ABTestEventResponse> {\n const url = new URL(\n `/api/sdk/ab-test/${projectId}/${testName}/event`,\n this.config.baseUrl\n );\n\n return this.makeRequest<ABTestEventResponse>(url, {\n method: \"POST\",\n headers: {\n \"X-User-ID\": userId,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n event,\n variantId,\n eventData,\n }),\n });\n }\n\n /**\n * Get all A/B tests for a project\n */\n async getAbTests(\n projectId: string = this.config.projectId\n ): Promise<ABTestsResponse> {\n const cacheKey = `abtests:${projectId}`;\n const cached = this.getFromCache<ABTestsResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(`/api/sdk/ab-tests/${projectId}`, this.config.baseUrl);\n\n const response = await this.makeRequest<ABTestsResponse>(url);\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Clear cache for specific key or all cache\n */\n clearCache(key?: string): void {\n if (key) {\n this.cache.delete(key);\n } else {\n this.cache.clear();\n }\n }\n\n /**\n * Update configuration\n */\n updateConfig(newConfig: Partial<FlipFlagConfig>): void {\n this.config = { ...this.config, ...newConfig };\n }\n\n private async makeRequest<T>(\n url: string | URL,\n options: RequestInit = {}\n ): Promise<T> {\n // Convert URL object to string if needed\n const urlString = url instanceof URL ? url.toString() : url;\n\n // If URL starts with '/', prepend baseUrl and handle trailing slashes\n const fullUrl = urlString.startsWith(\"/\")\n ? `${this.config.baseUrl?.replace(/\\/$/, \"\") || this.defaultBaseUrl}${urlString}`\n : urlString;\n\n const headers = {\n \"X-API-Key\": this.config.apiKey,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n };\n\n const requestOptions: RequestInit = {\n ...options,\n headers,\n };\n\n return this.makeRequestWithRetry<T>(fullUrl, requestOptions);\n }\n\n private async makeRequestWithRetry<T>(\n url: string,\n options: RequestInit,\n retryOptions: RetryOptions = {\n attempts: this.config.retryAttempts!,\n delay: this.config.retryDelay!,\n backoff: 2,\n }\n ): Promise<T> {\n let lastError: Error;\n\n for (let attempt = 1; attempt <= retryOptions.attempts; attempt++) {\n try {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(\n `HTTP ${response.status}: ${errorData.error || response.statusText}`\n );\n }\n\n return await response.json();\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on client errors (4xx) except 429 (rate limit)\n if (error instanceof Error && error.message.includes(\"HTTP 4\")) {\n if (!error.message.includes(\"HTTP 429\")) {\n throw error;\n }\n }\n\n if (attempt < retryOptions.attempts) {\n const delay =\n retryOptions.delay * Math.pow(retryOptions.backoff, attempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n throw lastError!;\n }\n\n private getFromCache<T>(key: string): T | null {\n const entry = this.cache.get(key);\n\n if (!entry) {\n return null;\n }\n\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.data;\n }\n\n private setCache<T>(key: string, data: T, ttl: number): void {\n this.cache.set(key, {\n data,\n timestamp: Date.now(),\n ttl,\n });\n }\n\n /**\n * Cleanup method - should be called when SDK is no longer needed\n */\n public destroy(): void {\n this.stopPulling();\n this.stateListeners.clear();\n this.cache.clear();\n }\n}\n"],"names":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  class FlipFlagSDK {
2
2
  constructor(config) {
3
3
  this.cache = new Map();
4
- this.defaultBaseUrl = "https://app.flipflag.ru/api";
4
+ this.defaultBaseUrl = "https://app.flipflag.ru";
5
5
  this.stateListeners = new Set();
6
6
  this.config = {
7
7
  baseUrl: this.defaultBaseUrl,
@@ -163,7 +163,7 @@ class FlipFlagSDK {
163
163
  */
164
164
  async fetchAllFlags() {
165
165
  try {
166
- return await this.makeRequest(`/sdk/flags/${this.config.projectId}`);
166
+ return await this.makeRequest(`/api/sdk/flags/${this.config.projectId}`);
167
167
  }
168
168
  catch (error) {
169
169
  console.error("Failed to fetch flags:", error);
@@ -175,7 +175,7 @@ class FlipFlagSDK {
175
175
  */
176
176
  async fetchAllABTests() {
177
177
  try {
178
- return await this.makeRequest(`/sdk/ab-tests/${this.config.projectId}`);
178
+ return await this.makeRequest(`/api/sdk/ab-tests/${this.config.projectId}`);
179
179
  }
180
180
  catch (error) {
181
181
  console.error("Failed to fetch A/B tests:", error);
@@ -198,7 +198,7 @@ class FlipFlagSDK {
198
198
  if (cached) {
199
199
  return cached;
200
200
  }
201
- const url = new URL(`/sdk/flags/${projectId}`, this.config.baseUrl);
201
+ const url = new URL(`/api/sdk/flags/${projectId}`, this.config.baseUrl);
202
202
  if (environment || this.config.environment) {
203
203
  url.searchParams.set("environment", environment || this.config.environment);
204
204
  }
@@ -226,7 +226,7 @@ class FlipFlagSDK {
226
226
  if (cached) {
227
227
  return cached;
228
228
  }
229
- const url = new URL(`/sdk/flags/${projectId}/${flagName}`, this.config.baseUrl);
229
+ const url = new URL(`/api/sdk/flags/${projectId}/${flagName}`, this.config.baseUrl);
230
230
  if (environment || this.config.environment) {
231
231
  url.searchParams.set("environment", environment || this.config.environment);
232
232
  }
@@ -248,7 +248,7 @@ class FlipFlagSDK {
248
248
  if (cached) {
249
249
  return cached;
250
250
  }
251
- const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}`;
251
+ const url = new URL(`/api/sdk/ab-test/${projectId}/${testName}`, this.config.baseUrl);
252
252
  const response = await this.makeRequest(url, {
253
253
  headers: {
254
254
  "X-User-ID": userId,
@@ -262,7 +262,7 @@ class FlipFlagSDK {
262
262
  * Record an A/B test event
263
263
  */
264
264
  async recordAbTestEvent(testName, userId, event, variantId, eventData, projectId = this.config.projectId) {
265
- const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}/event`;
265
+ const url = new URL(`/api/sdk/ab-test/${projectId}/${testName}/event`, this.config.baseUrl);
266
266
  return this.makeRequest(url, {
267
267
  method: "POST",
268
268
  headers: {
@@ -285,7 +285,7 @@ class FlipFlagSDK {
285
285
  if (cached) {
286
286
  return cached;
287
287
  }
288
- const url = `${this.config.baseUrl}/sdk/ab-tests/${projectId}`;
288
+ const url = new URL(`/api/sdk/ab-tests/${projectId}`, this.config.baseUrl);
289
289
  const response = await this.makeRequest(url);
290
290
  this.setCache(cacheKey, response, this.config.cacheTimeout);
291
291
  return response;
@@ -308,6 +308,13 @@ class FlipFlagSDK {
308
308
  this.config = { ...this.config, ...newConfig };
309
309
  }
310
310
  async makeRequest(url, options = {}) {
311
+ var _a;
312
+ // Convert URL object to string if needed
313
+ const urlString = url instanceof URL ? url.toString() : url;
314
+ // If URL starts with '/', prepend baseUrl and handle trailing slashes
315
+ const fullUrl = urlString.startsWith("/")
316
+ ? `${((_a = this.config.baseUrl) === null || _a === void 0 ? void 0 : _a.replace(/\/$/, "")) || this.defaultBaseUrl}${urlString}`
317
+ : urlString;
311
318
  const headers = {
312
319
  "X-API-Key": this.config.apiKey,
313
320
  "Content-Type": "application/json",
@@ -317,7 +324,7 @@ class FlipFlagSDK {
317
324
  ...options,
318
325
  headers,
319
326
  };
320
- return this.makeRequestWithRetry(url, requestOptions);
327
+ return this.makeRequestWithRetry(fullUrl, requestOptions);
321
328
  }
322
329
  async makeRequestWithRetry(url, options, retryOptions = {
323
330
  attempts: this.config.retryAttempts,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/core/FlipFlagSDK.ts"],"sourcesContent":["import {\n FlipFlagConfig,\n FeatureFlagResponse,\n FeatureFlagsResponse,\n ABTestResponse,\n ABTestEventResponse,\n ABTestsResponse,\n FlipFlagError,\n CacheEntry,\n RetryOptions,\n SDKState,\n IdentifyUserOptions,\n} from \"../types\";\n\nexport class FlipFlagSDK {\n private config: FlipFlagConfig;\n private cache = new Map<string, CacheEntry<any>>();\n private defaultBaseUrl = \"https://app.flipflag.ru/api\";\n private pullIntervalId?: NodeJS.Timeout;\n private state: SDKState;\n private stateListeners: Set<(state: SDKState) => void> = new Set();\n\n constructor(config: FlipFlagConfig) {\n this.config = {\n baseUrl: this.defaultBaseUrl,\n cacheTimeout: 30000, // 30 seconds\n retryAttempts: 3,\n retryDelay: 1000, // 1 second\n pullInterval: 60000, // 1 minute\n ...config,\n };\n\n this.state = {\n flags: {},\n abTests: {},\n lastFetch: null,\n isLoading: false,\n error: null,\n };\n\n // Start automatic pulling if pullInterval is set\n if (this.config.pullInterval && this.config.pullInterval > 0) {\n this.startPulling();\n }\n }\n\n /**\n * Identify user for A/B testing and user-specific flags\n */\n identifyUser(options: IdentifyUserOptions): void {\n this.config.userId = options.userId;\n\n // Clear A/B test cache since user changed\n this.clearABTestCache();\n\n // If we have a user, we might want to refresh immediately\n if (this.config.pullInterval && this.config.pullInterval > 0) {\n this.pullData();\n }\n }\n\n /**\n * Get current SDK state\n */\n getState(): SDKState {\n return { ...this.state };\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(callback: (state: SDKState) => void): () => void {\n this.stateListeners.add(callback);\n\n // Return unsubscribe function\n return () => {\n this.stateListeners.delete(callback);\n };\n }\n\n /**\n * Get a feature flag value from current state\n */\n getFlagValue(flagName: string): boolean {\n return this.state.flags[flagName] ?? false;\n }\n\n /**\n * Get A/B test variant from current state\n */\n getABTestVariant(testName: string): ABTestResponse | null {\n return this.state.abTests[testName] || null;\n }\n\n /**\n * Start automatic data pulling\n */\n private startPulling(): void {\n if (this.pullIntervalId) {\n clearInterval(this.pullIntervalId);\n }\n\n this.pullIntervalId = setInterval(() => {\n this.pullData();\n }, this.config.pullInterval!);\n\n // Initial pull\n this.pullData();\n }\n\n /**\n * Stop automatic data pulling\n */\n stopPulling(): void {\n if (this.pullIntervalId) {\n clearInterval(this.pullIntervalId);\n this.pullIntervalId = undefined;\n }\n }\n\n /**\n * Pull fresh data from API\n */\n private async pullData(): Promise<void> {\n try {\n this.updateState({ isLoading: true, error: null });\n\n // Pull flags\n const flagsResponse = await this.fetchAllFlags();\n\n // Pull A/B tests if user is identified\n let abTestsResponse: ABTestsResponse | null = null;\n if (this.config.userId) {\n try {\n abTestsResponse = await this.fetchAllABTests();\n } catch (error) {\n console.warn(\"Failed to fetch A/B tests:\", error);\n }\n }\n\n const newState: Partial<SDKState> = {\n flags: flagsResponse?.flags || {},\n lastFetch: new Date(),\n isLoading: false,\n error: null,\n };\n\n if (abTestsResponse) {\n const abTestsMap: Record<string, ABTestResponse> = {};\n abTestsResponse.abTests.forEach((test) => {\n // For each test, get the variant for current user\n if (this.config.userId) {\n // This would normally fetch the variant, but for demo we'll simulate\n abTestsMap[test.name] = {\n testName: test.name,\n testId: test.id,\n variantId: \"variant_a\", // Default variant\n variant: test.variants[0] || {\n id: \"default\",\n name: \"Default\",\n value: null,\n weight: 100,\n },\n timestamp: new Date().toISOString(),\n };\n }\n });\n newState.abTests = abTestsMap;\n }\n\n this.updateState(newState);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n this.updateState({\n isLoading: false,\n error: errorMessage,\n });\n console.error(\"Failed to pull data:\", error);\n }\n }\n\n /**\n * Update state and notify listeners\n */\n private updateState(newState: Partial<SDKState>): void {\n this.state = { ...this.state, ...newState };\n\n // Notify all listeners\n this.stateListeners.forEach((callback) => {\n try {\n callback(this.state);\n } catch (error) {\n console.error(\"State listener error:\", error);\n }\n });\n }\n\n /**\n * Fetch all flags from API\n */\n private async fetchAllFlags(): Promise<FeatureFlagsResponse | null> {\n try {\n return await this.makeRequest<FeatureFlagsResponse>(\n `/sdk/flags/${this.config.projectId}`\n );\n } catch (error) {\n console.error(\"Failed to fetch flags:\", error);\n return null;\n }\n }\n\n /**\n * Fetch all A/B tests from API\n */\n private async fetchAllABTests(): Promise<ABTestsResponse | null> {\n try {\n return await this.makeRequest<ABTestsResponse>(\n `/sdk/ab-tests/${this.config.projectId}`\n );\n } catch (error) {\n console.error(\"Failed to fetch A/B tests:\", error);\n return null;\n }\n }\n\n /**\n * Clear A/B test cache\n */\n private clearABTestCache(): void {\n const abTestKeys = Array.from(this.cache.keys()).filter((key) =>\n key.startsWith(\"abtest:\")\n );\n abTestKeys.forEach((key) => this.cache.delete(key));\n }\n\n /**\n * Get all feature flags for a project\n */\n async getFlags(\n projectId: string = this.config.projectId,\n environment?: string\n ): Promise<FeatureFlagsResponse> {\n const cacheKey = `flags:${projectId}:${environment || \"all\"}`;\n const cached = this.getFromCache<FeatureFlagsResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(`/sdk/flags/${projectId}`, this.config.baseUrl);\n if (environment || this.config.environment) {\n url.searchParams.set(\n \"environment\",\n environment || this.config.environment!\n );\n }\n\n const response = await this.makeRequest<FeatureFlagsResponse>(\n url.toString()\n );\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Get a specific feature flag value\n */\n async getFlag(\n flagName: string,\n projectId: string = this.config.projectId,\n environment?: string\n ): Promise<FeatureFlagResponse> {\n // If we have the flag in state, return it immediately\n if (this.state.flags[flagName] !== undefined) {\n return {\n projectId: this.config.projectId,\n flagName,\n environment: this.config.environment || \"all\",\n value: this.state.flags[flagName],\n timestamp:\n this.state.lastFetch?.toISOString() || new Date().toISOString(),\n };\n }\n\n const cacheKey = `flag:${projectId}:${flagName}:${environment || \"all\"}`;\n const cached = this.getFromCache<FeatureFlagResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(\n `/sdk/flags/${projectId}/${flagName}`,\n this.config.baseUrl\n );\n if (environment || this.config.environment) {\n url.searchParams.set(\n \"environment\",\n environment || this.config.environment!\n );\n }\n\n const response = await this.makeRequest<FeatureFlagResponse>(\n url.toString()\n );\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Get A/B test variant for a user\n */\n async getAbTestVariant(\n testName: string,\n userId: string,\n projectId: string = this.config.projectId\n ): Promise<ABTestResponse> {\n // If we have the A/B test in state, return it immediately\n const stateVariant = this.state.abTests[testName];\n if (stateVariant && stateVariant.testName === testName) {\n return stateVariant;\n }\n\n const cacheKey = `abtest:${projectId}:${testName}:${userId}`;\n const cached = this.getFromCache<ABTestResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}`;\n\n const response = await this.makeRequest<ABTestResponse>(url, {\n headers: {\n \"X-User-ID\": userId,\n },\n });\n\n // Cache A/B test variants for longer since they shouldn't change frequently for a user\n this.setCache(cacheKey, response, this.config.cacheTimeout! * 10);\n\n return response;\n }\n\n /**\n * Record an A/B test event\n */\n async recordAbTestEvent(\n testName: string,\n userId: string,\n event: string,\n variantId: string,\n eventData?: Record<string, any>,\n projectId: string = this.config.projectId\n ): Promise<ABTestEventResponse> {\n const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}/event`;\n\n return this.makeRequest<ABTestEventResponse>(url, {\n method: \"POST\",\n headers: {\n \"X-User-ID\": userId,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n event,\n variantId,\n eventData,\n }),\n });\n }\n\n /**\n * Get all A/B tests for a project\n */\n async getAbTests(\n projectId: string = this.config.projectId\n ): Promise<ABTestsResponse> {\n const cacheKey = `abtests:${projectId}`;\n const cached = this.getFromCache<ABTestsResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = `${this.config.baseUrl}/sdk/ab-tests/${projectId}`;\n\n const response = await this.makeRequest<ABTestsResponse>(url);\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Clear cache for specific key or all cache\n */\n clearCache(key?: string): void {\n if (key) {\n this.cache.delete(key);\n } else {\n this.cache.clear();\n }\n }\n\n /**\n * Update configuration\n */\n updateConfig(newConfig: Partial<FlipFlagConfig>): void {\n this.config = { ...this.config, ...newConfig };\n }\n\n private async makeRequest<T>(\n url: string,\n options: RequestInit = {}\n ): Promise<T> {\n const headers = {\n \"X-API-Key\": this.config.apiKey,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n };\n\n const requestOptions: RequestInit = {\n ...options,\n headers,\n };\n\n return this.makeRequestWithRetry<T>(url, requestOptions);\n }\n\n private async makeRequestWithRetry<T>(\n url: string,\n options: RequestInit,\n retryOptions: RetryOptions = {\n attempts: this.config.retryAttempts!,\n delay: this.config.retryDelay!,\n backoff: 2,\n }\n ): Promise<T> {\n let lastError: Error;\n\n for (let attempt = 1; attempt <= retryOptions.attempts; attempt++) {\n try {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(\n `HTTP ${response.status}: ${errorData.error || response.statusText}`\n );\n }\n\n return await response.json();\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on client errors (4xx) except 429 (rate limit)\n if (error instanceof Error && error.message.includes(\"HTTP 4\")) {\n if (!error.message.includes(\"HTTP 429\")) {\n throw error;\n }\n }\n\n if (attempt < retryOptions.attempts) {\n const delay =\n retryOptions.delay * Math.pow(retryOptions.backoff, attempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n throw lastError!;\n }\n\n private getFromCache<T>(key: string): T | null {\n const entry = this.cache.get(key);\n\n if (!entry) {\n return null;\n }\n\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.data;\n }\n\n private setCache<T>(key: string, data: T, ttl: number): void {\n this.cache.set(key, {\n data,\n timestamp: Date.now(),\n ttl,\n });\n }\n\n /**\n * Cleanup method - should be called when SDK is no longer needed\n */\n public destroy(): void {\n this.stopPulling();\n this.stateListeners.clear();\n this.cache.clear();\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/core/FlipFlagSDK.ts"],"sourcesContent":["import {\n FlipFlagConfig,\n FeatureFlagResponse,\n FeatureFlagsResponse,\n ABTestResponse,\n ABTestEventResponse,\n ABTestsResponse,\n FlipFlagError,\n CacheEntry,\n RetryOptions,\n SDKState,\n IdentifyUserOptions,\n} from \"../types\";\n\nexport class FlipFlagSDK {\n private config: FlipFlagConfig;\n private cache = new Map<string, CacheEntry<any>>();\n private defaultBaseUrl = \"https://app.flipflag.ru\";\n private pullIntervalId?: NodeJS.Timeout;\n private state: SDKState;\n private stateListeners: Set<(state: SDKState) => void> = new Set();\n\n constructor(config: FlipFlagConfig) {\n this.config = {\n baseUrl: this.defaultBaseUrl,\n cacheTimeout: 30000, // 30 seconds\n retryAttempts: 3,\n retryDelay: 1000, // 1 second\n pullInterval: 60000, // 1 minute\n ...config,\n };\n\n this.state = {\n flags: {},\n abTests: {},\n lastFetch: null,\n isLoading: false,\n error: null,\n };\n\n // Start automatic pulling if pullInterval is set\n if (this.config.pullInterval && this.config.pullInterval > 0) {\n this.startPulling();\n }\n }\n\n /**\n * Identify user for A/B testing and user-specific flags\n */\n identifyUser(options: IdentifyUserOptions): void {\n this.config.userId = options.userId;\n\n // Clear A/B test cache since user changed\n this.clearABTestCache();\n\n // If we have a user, we might want to refresh immediately\n if (this.config.pullInterval && this.config.pullInterval > 0) {\n this.pullData();\n }\n }\n\n /**\n * Get current SDK state\n */\n getState(): SDKState {\n return { ...this.state };\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(callback: (state: SDKState) => void): () => void {\n this.stateListeners.add(callback);\n\n // Return unsubscribe function\n return () => {\n this.stateListeners.delete(callback);\n };\n }\n\n /**\n * Get a feature flag value from current state\n */\n getFlagValue(flagName: string): boolean {\n return this.state.flags[flagName] ?? false;\n }\n\n /**\n * Get A/B test variant from current state\n */\n getABTestVariant(testName: string): ABTestResponse | null {\n return this.state.abTests[testName] || null;\n }\n\n /**\n * Start automatic data pulling\n */\n private startPulling(): void {\n if (this.pullIntervalId) {\n clearInterval(this.pullIntervalId);\n }\n\n this.pullIntervalId = setInterval(() => {\n this.pullData();\n }, this.config.pullInterval!);\n\n // Initial pull\n this.pullData();\n }\n\n /**\n * Stop automatic data pulling\n */\n stopPulling(): void {\n if (this.pullIntervalId) {\n clearInterval(this.pullIntervalId);\n this.pullIntervalId = undefined;\n }\n }\n\n /**\n * Pull fresh data from API\n */\n private async pullData(): Promise<void> {\n try {\n this.updateState({ isLoading: true, error: null });\n\n // Pull flags\n const flagsResponse = await this.fetchAllFlags();\n\n // Pull A/B tests if user is identified\n let abTestsResponse: ABTestsResponse | null = null;\n if (this.config.userId) {\n try {\n abTestsResponse = await this.fetchAllABTests();\n } catch (error) {\n console.warn(\"Failed to fetch A/B tests:\", error);\n }\n }\n\n const newState: Partial<SDKState> = {\n flags: flagsResponse?.flags || {},\n lastFetch: new Date(),\n isLoading: false,\n error: null,\n };\n\n if (abTestsResponse) {\n const abTestsMap: Record<string, ABTestResponse> = {};\n abTestsResponse.abTests.forEach((test) => {\n // For each test, get the variant for current user\n if (this.config.userId) {\n // This would normally fetch the variant, but for demo we'll simulate\n abTestsMap[test.name] = {\n testName: test.name,\n testId: test.id,\n variantId: \"variant_a\", // Default variant\n variant: test.variants[0] || {\n id: \"default\",\n name: \"Default\",\n value: null,\n weight: 100,\n },\n timestamp: new Date().toISOString(),\n };\n }\n });\n newState.abTests = abTestsMap;\n }\n\n this.updateState(newState);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n this.updateState({\n isLoading: false,\n error: errorMessage,\n });\n console.error(\"Failed to pull data:\", error);\n }\n }\n\n /**\n * Update state and notify listeners\n */\n private updateState(newState: Partial<SDKState>): void {\n this.state = { ...this.state, ...newState };\n\n // Notify all listeners\n this.stateListeners.forEach((callback) => {\n try {\n callback(this.state);\n } catch (error) {\n console.error(\"State listener error:\", error);\n }\n });\n }\n\n /**\n * Fetch all flags from API\n */\n private async fetchAllFlags(): Promise<FeatureFlagsResponse | null> {\n try {\n return await this.makeRequest<FeatureFlagsResponse>(\n `/api/sdk/flags/${this.config.projectId}`\n );\n } catch (error) {\n console.error(\"Failed to fetch flags:\", error);\n return null;\n }\n }\n\n /**\n * Fetch all A/B tests from API\n */\n private async fetchAllABTests(): Promise<ABTestsResponse | null> {\n try {\n return await this.makeRequest<ABTestsResponse>(\n `/api/sdk/ab-tests/${this.config.projectId}`\n );\n } catch (error) {\n console.error(\"Failed to fetch A/B tests:\", error);\n return null;\n }\n }\n\n /**\n * Clear A/B test cache\n */\n private clearABTestCache(): void {\n const abTestKeys = Array.from(this.cache.keys()).filter((key) =>\n key.startsWith(\"abtest:\")\n );\n abTestKeys.forEach((key) => this.cache.delete(key));\n }\n\n /**\n * Get all feature flags for a project\n */\n async getFlags(\n projectId: string = this.config.projectId,\n environment?: string\n ): Promise<FeatureFlagsResponse> {\n const cacheKey = `flags:${projectId}:${environment || \"all\"}`;\n const cached = this.getFromCache<FeatureFlagsResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(`/api/sdk/flags/${projectId}`, this.config.baseUrl);\n if (environment || this.config.environment) {\n url.searchParams.set(\n \"environment\",\n environment || this.config.environment!\n );\n }\n\n const response = await this.makeRequest<FeatureFlagsResponse>(\n url.toString()\n );\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Get a specific feature flag value\n */\n async getFlag(\n flagName: string,\n projectId: string = this.config.projectId,\n environment?: string\n ): Promise<FeatureFlagResponse> {\n // If we have the flag in state, return it immediately\n if (this.state.flags[flagName] !== undefined) {\n return {\n projectId: this.config.projectId,\n flagName,\n environment: this.config.environment || \"all\",\n value: this.state.flags[flagName],\n timestamp:\n this.state.lastFetch?.toISOString() || new Date().toISOString(),\n };\n }\n\n const cacheKey = `flag:${projectId}:${flagName}:${environment || \"all\"}`;\n const cached = this.getFromCache<FeatureFlagResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(\n `/api/sdk/flags/${projectId}/${flagName}`,\n this.config.baseUrl\n );\n if (environment || this.config.environment) {\n url.searchParams.set(\n \"environment\",\n environment || this.config.environment!\n );\n }\n\n const response = await this.makeRequest<FeatureFlagResponse>(\n url.toString()\n );\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Get A/B test variant for a user\n */\n async getAbTestVariant(\n testName: string,\n userId: string,\n projectId: string = this.config.projectId\n ): Promise<ABTestResponse> {\n // If we have the A/B test in state, return it immediately\n const stateVariant = this.state.abTests[testName];\n if (stateVariant && stateVariant.testName === testName) {\n return stateVariant;\n }\n\n const cacheKey = `abtest:${projectId}:${testName}:${userId}`;\n const cached = this.getFromCache<ABTestResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(\n `/api/sdk/ab-test/${projectId}/${testName}`,\n this.config.baseUrl\n );\n\n const response = await this.makeRequest<ABTestResponse>(url, {\n headers: {\n \"X-User-ID\": userId,\n },\n });\n\n // Cache A/B test variants for longer since they shouldn't change frequently for a user\n this.setCache(cacheKey, response, this.config.cacheTimeout! * 10);\n\n return response;\n }\n\n /**\n * Record an A/B test event\n */\n async recordAbTestEvent(\n testName: string,\n userId: string,\n event: string,\n variantId: string,\n eventData?: Record<string, any>,\n projectId: string = this.config.projectId\n ): Promise<ABTestEventResponse> {\n const url = new URL(\n `/api/sdk/ab-test/${projectId}/${testName}/event`,\n this.config.baseUrl\n );\n\n return this.makeRequest<ABTestEventResponse>(url, {\n method: \"POST\",\n headers: {\n \"X-User-ID\": userId,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n event,\n variantId,\n eventData,\n }),\n });\n }\n\n /**\n * Get all A/B tests for a project\n */\n async getAbTests(\n projectId: string = this.config.projectId\n ): Promise<ABTestsResponse> {\n const cacheKey = `abtests:${projectId}`;\n const cached = this.getFromCache<ABTestsResponse>(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const url = new URL(`/api/sdk/ab-tests/${projectId}`, this.config.baseUrl);\n\n const response = await this.makeRequest<ABTestsResponse>(url);\n this.setCache(cacheKey, response, this.config.cacheTimeout!);\n\n return response;\n }\n\n /**\n * Clear cache for specific key or all cache\n */\n clearCache(key?: string): void {\n if (key) {\n this.cache.delete(key);\n } else {\n this.cache.clear();\n }\n }\n\n /**\n * Update configuration\n */\n updateConfig(newConfig: Partial<FlipFlagConfig>): void {\n this.config = { ...this.config, ...newConfig };\n }\n\n private async makeRequest<T>(\n url: string | URL,\n options: RequestInit = {}\n ): Promise<T> {\n // Convert URL object to string if needed\n const urlString = url instanceof URL ? url.toString() : url;\n\n // If URL starts with '/', prepend baseUrl and handle trailing slashes\n const fullUrl = urlString.startsWith(\"/\")\n ? `${this.config.baseUrl?.replace(/\\/$/, \"\") || this.defaultBaseUrl}${urlString}`\n : urlString;\n\n const headers = {\n \"X-API-Key\": this.config.apiKey,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n };\n\n const requestOptions: RequestInit = {\n ...options,\n headers,\n };\n\n return this.makeRequestWithRetry<T>(fullUrl, requestOptions);\n }\n\n private async makeRequestWithRetry<T>(\n url: string,\n options: RequestInit,\n retryOptions: RetryOptions = {\n attempts: this.config.retryAttempts!,\n delay: this.config.retryDelay!,\n backoff: 2,\n }\n ): Promise<T> {\n let lastError: Error;\n\n for (let attempt = 1; attempt <= retryOptions.attempts; attempt++) {\n try {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(\n `HTTP ${response.status}: ${errorData.error || response.statusText}`\n );\n }\n\n return await response.json();\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on client errors (4xx) except 429 (rate limit)\n if (error instanceof Error && error.message.includes(\"HTTP 4\")) {\n if (!error.message.includes(\"HTTP 429\")) {\n throw error;\n }\n }\n\n if (attempt < retryOptions.attempts) {\n const delay =\n retryOptions.delay * Math.pow(retryOptions.backoff, attempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n throw lastError!;\n }\n\n private getFromCache<T>(key: string): T | null {\n const entry = this.cache.get(key);\n\n if (!entry) {\n return null;\n }\n\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.data;\n }\n\n private setCache<T>(key: string, data: T, ttl: number): void {\n this.cache.set(key, {\n data,\n timestamp: Date.now(),\n ttl,\n });\n }\n\n /**\n * Cleanup method - should be called when SDK is no longer needed\n */\n public destroy(): void {\n this.stopPulling();\n this.stateListeners.clear();\n this.cache.clear();\n }\n}\n"],"names":[],"mappings":"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"}
package/dist/js.js CHANGED
@@ -3,7 +3,7 @@
3
3
  class FlipFlagSDK {
4
4
  constructor(config) {
5
5
  this.cache = new Map();
6
- this.defaultBaseUrl = "https://app.flipflag.ru/api";
6
+ this.defaultBaseUrl = "https://app.flipflag.ru";
7
7
  this.stateListeners = new Set();
8
8
  this.config = {
9
9
  baseUrl: this.defaultBaseUrl,
@@ -165,7 +165,7 @@ class FlipFlagSDK {
165
165
  */
166
166
  async fetchAllFlags() {
167
167
  try {
168
- return await this.makeRequest(`/sdk/flags/${this.config.projectId}`);
168
+ return await this.makeRequest(`/api/sdk/flags/${this.config.projectId}`);
169
169
  }
170
170
  catch (error) {
171
171
  console.error("Failed to fetch flags:", error);
@@ -177,7 +177,7 @@ class FlipFlagSDK {
177
177
  */
178
178
  async fetchAllABTests() {
179
179
  try {
180
- return await this.makeRequest(`/sdk/ab-tests/${this.config.projectId}`);
180
+ return await this.makeRequest(`/api/sdk/ab-tests/${this.config.projectId}`);
181
181
  }
182
182
  catch (error) {
183
183
  console.error("Failed to fetch A/B tests:", error);
@@ -200,7 +200,7 @@ class FlipFlagSDK {
200
200
  if (cached) {
201
201
  return cached;
202
202
  }
203
- const url = new URL(`/sdk/flags/${projectId}`, this.config.baseUrl);
203
+ const url = new URL(`/api/sdk/flags/${projectId}`, this.config.baseUrl);
204
204
  if (environment || this.config.environment) {
205
205
  url.searchParams.set("environment", environment || this.config.environment);
206
206
  }
@@ -228,7 +228,7 @@ class FlipFlagSDK {
228
228
  if (cached) {
229
229
  return cached;
230
230
  }
231
- const url = new URL(`/sdk/flags/${projectId}/${flagName}`, this.config.baseUrl);
231
+ const url = new URL(`/api/sdk/flags/${projectId}/${flagName}`, this.config.baseUrl);
232
232
  if (environment || this.config.environment) {
233
233
  url.searchParams.set("environment", environment || this.config.environment);
234
234
  }
@@ -250,7 +250,7 @@ class FlipFlagSDK {
250
250
  if (cached) {
251
251
  return cached;
252
252
  }
253
- const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}`;
253
+ const url = new URL(`/api/sdk/ab-test/${projectId}/${testName}`, this.config.baseUrl);
254
254
  const response = await this.makeRequest(url, {
255
255
  headers: {
256
256
  "X-User-ID": userId,
@@ -264,7 +264,7 @@ class FlipFlagSDK {
264
264
  * Record an A/B test event
265
265
  */
266
266
  async recordAbTestEvent(testName, userId, event, variantId, eventData, projectId = this.config.projectId) {
267
- const url = `${this.config.baseUrl}/sdk/ab-test/${projectId}/${testName}/event`;
267
+ const url = new URL(`/api/sdk/ab-test/${projectId}/${testName}/event`, this.config.baseUrl);
268
268
  return this.makeRequest(url, {
269
269
  method: "POST",
270
270
  headers: {
@@ -287,7 +287,7 @@ class FlipFlagSDK {
287
287
  if (cached) {
288
288
  return cached;
289
289
  }
290
- const url = `${this.config.baseUrl}/sdk/ab-tests/${projectId}`;
290
+ const url = new URL(`/api/sdk/ab-tests/${projectId}`, this.config.baseUrl);
291
291
  const response = await this.makeRequest(url);
292
292
  this.setCache(cacheKey, response, this.config.cacheTimeout);
293
293
  return response;
@@ -310,6 +310,13 @@ class FlipFlagSDK {
310
310
  this.config = { ...this.config, ...newConfig };
311
311
  }
312
312
  async makeRequest(url, options = {}) {
313
+ var _a;
314
+ // Convert URL object to string if needed
315
+ const urlString = url instanceof URL ? url.toString() : url;
316
+ // If URL starts with '/', prepend baseUrl and handle trailing slashes
317
+ const fullUrl = urlString.startsWith("/")
318
+ ? `${((_a = this.config.baseUrl) === null || _a === void 0 ? void 0 : _a.replace(/\/$/, "")) || this.defaultBaseUrl}${urlString}`
319
+ : urlString;
313
320
  const headers = {
314
321
  "X-API-Key": this.config.apiKey,
315
322
  "Content-Type": "application/json",
@@ -319,7 +326,7 @@ class FlipFlagSDK {
319
326
  ...options,
320
327
  headers,
321
328
  };
322
- return this.makeRequestWithRetry(url, requestOptions);
329
+ return this.makeRequestWithRetry(fullUrl, requestOptions);
323
330
  }
324
331
  async makeRequestWithRetry(url, options, retryOptions = {
325
332
  attempts: this.config.retryAttempts,