@finatic/client 0.9.1 → 0.9.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/dist/index.mjs CHANGED
@@ -1,6 +1,4 @@
1
1
  import pRetry, { AbortError } from 'p-retry';
2
- import pino from 'pino';
3
- import NodeCache from 'node-cache';
4
2
  import * as z from 'zod';
5
3
  import globalAxios from 'axios';
6
4
 
@@ -72,14 +70,12 @@ async function retryApiCall(fn, options = {}, config) {
72
70
  }
73
71
 
74
72
  /**
75
- * Structured logger utility with browser-safe fallback (Phase 2C).
73
+ * Structured logger utility with browser-safe console logging (Phase 2C).
76
74
  *
77
75
  * Generated - do not edit directly.
78
76
  *
79
- * This logger automatically falls back to console-based logging when pino fails
80
- * in browser environments (Vite, Next.js, etc.).
77
+ * This logger uses browser console APIs for all logging in browser environments.
81
78
  */
82
- // @ts-ignore - pino types available via @types/pino
83
79
  let _loggerInstance = null;
84
80
  /**
85
81
  * Get environment variable from various sources (browser and Node.js).
@@ -124,30 +120,6 @@ function isProduction() {
124
120
  return true;
125
121
  return false;
126
122
  }
127
- /**
128
- * Detect if we're in a browser environment.
129
- */
130
- function isBrowser() {
131
- // Check for window object (browser)
132
- if (typeof window !== 'undefined') {
133
- return true;
134
- }
135
- // Check for globalThis in browser-like environments
136
- if (typeof globalThis !== 'undefined') {
137
- // In browsers, process might be polyfilled but process.stdout won't exist
138
- try {
139
- const proc = globalThis.process;
140
- if (proc && typeof proc.stdout === 'undefined') {
141
- return true;
142
- }
143
- }
144
- catch {
145
- // If we can't check, assume browser if window exists
146
- return typeof window !== 'undefined';
147
- }
148
- }
149
- return false;
150
- }
151
123
  /**
152
124
  * Get or create a logger instance with browser-safe fallback.
153
125
  */
@@ -155,36 +127,13 @@ function getLogger(config) {
155
127
  if (_loggerInstance) {
156
128
  return _loggerInstance;
157
129
  }
158
- // In browser environments, skip pino entirely and use browser-safe logger
159
- if (isBrowser()) {
160
- return getBrowserSafeLogger(config);
161
- }
162
- // Try to use pino first (Node.js environments)
163
- try {
164
- const logLevel = (config?.logLevel || getEnvVar('FINATIC_LOG_LEVEL') || 'error');
165
- const pinoConfig = {
166
- level: logLevel === 'silent' ? 'silent' : logLevel,
167
- ...(config?.structuredLogging !== false && {
168
- formatters: {
169
- level: (label) => {
170
- return { level: label };
171
- },
172
- },
173
- timestamp: true,
174
- }),
175
- };
176
- _loggerInstance = pino(pinoConfig);
177
- return _loggerInstance;
178
- }
179
- catch (error) {
180
- // Fallback to browser-safe logger if pino fails
181
- return getBrowserSafeLogger(config, error);
182
- }
130
+ // Client SDK always uses browser-safe logger (no pino)
131
+ return getBrowserSafeLogger(config);
183
132
  }
184
133
  /**
185
- * Browser-safe logger fallback for environments where pino fails.
134
+ * Browser-safe logger for Client SDK.
186
135
  */
187
- function getBrowserSafeLogger(config, pinoError) {
136
+ function getBrowserSafeLogger(config) {
188
137
  // Log level hierarchy (matching pino's numeric levels)
189
138
  const LOG_LEVELS = {
190
139
  silent: 0,
@@ -215,7 +164,7 @@ function getBrowserSafeLogger(config, pinoError) {
215
164
  };
216
165
  const logLevel = getEffectiveLogLevel();
217
166
  const structuredLogging = config?.structuredLogging ?? false;
218
- const isProd = isProduction();
167
+ isProduction();
219
168
  /**
220
169
  * Check if we should log at this level.
221
170
  */
@@ -348,10 +297,6 @@ function getBrowserSafeLogger(config, pinoError) {
348
297
  }
349
298
  },
350
299
  };
351
- // Only warn about fallback logger if pino failed (not if we're in browser)
352
- if (pinoError && !isProd) {
353
- console.warn('[Finatic SDK] Using fallback logger due to pino initialization error:', pinoError);
354
- }
355
300
  _loggerInstance = fallbackLogger;
356
301
  return _loggerInstance;
357
302
  }
@@ -419,11 +364,96 @@ function handleError(error, requestId) {
419
364
  }
420
365
 
421
366
  /**
422
- * Response caching utility with node-cache (Phase 2B).
367
+ * Response caching utility with browser-compatible Map-based cache (Phase 2B).
423
368
  *
424
369
  * Generated - do not edit directly.
425
370
  */
426
- // @ts-ignore - node-cache types available via @types/node-cache
371
+ class MapBasedCache {
372
+ constructor(maxSize = 1000, defaultTtl = 300) {
373
+ this.cleanupInterval = null;
374
+ this.cache = new Map();
375
+ this.maxSize = maxSize;
376
+ this.defaultTtl = defaultTtl;
377
+ this.startCleanup();
378
+ }
379
+ startCleanup() {
380
+ // Clean up expired entries every minute
381
+ if (typeof window !== 'undefined') {
382
+ this.cleanupInterval = window.setInterval(() => {
383
+ this.cleanup();
384
+ }, 60000);
385
+ }
386
+ }
387
+ cleanup() {
388
+ const now = Date.now();
389
+ const keysToDelete = [];
390
+ for (const [key, entry] of this.cache.entries()) {
391
+ if (entry.expires < now) {
392
+ keysToDelete.push(key);
393
+ }
394
+ }
395
+ keysToDelete.forEach(key => this.cache.delete(key));
396
+ }
397
+ evictLRU() {
398
+ if (this.cache.size < this.maxSize) {
399
+ return;
400
+ }
401
+ // Simple LRU: remove oldest entry (first in Map)
402
+ const firstKey = this.cache.keys().next().value;
403
+ if (firstKey) {
404
+ this.cache.delete(firstKey);
405
+ }
406
+ }
407
+ get(key) {
408
+ const entry = this.cache.get(key);
409
+ if (!entry) {
410
+ return undefined;
411
+ }
412
+ // Check if expired
413
+ if (entry.expires < Date.now()) {
414
+ this.cache.delete(key);
415
+ return undefined;
416
+ }
417
+ return entry.value;
418
+ }
419
+ set(key, value, ttl) {
420
+ // Evict if at max size
421
+ if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
422
+ this.evictLRU();
423
+ }
424
+ const expires = Date.now() + (ttl || this.defaultTtl) * 1000;
425
+ this.cache.set(key, { value, expires });
426
+ return true;
427
+ }
428
+ del(key) {
429
+ return this.cache.delete(key) ? 1 : 0;
430
+ }
431
+ clear() {
432
+ this.cache.clear();
433
+ }
434
+ keys() {
435
+ return Array.from(this.cache.keys());
436
+ }
437
+ has(key) {
438
+ const entry = this.cache.get(key);
439
+ if (!entry) {
440
+ return false;
441
+ }
442
+ // Check if expired
443
+ if (entry.expires < Date.now()) {
444
+ this.cache.delete(key);
445
+ return false;
446
+ }
447
+ return true;
448
+ }
449
+ destroy() {
450
+ if (this.cleanupInterval !== null && typeof window !== 'undefined') {
451
+ window.clearInterval(this.cleanupInterval);
452
+ this.cleanupInterval = null;
453
+ }
454
+ this.cache.clear();
455
+ }
456
+ }
427
457
  let _cacheInstance = null;
428
458
  /**
429
459
  * Get or create cache instance.
@@ -435,11 +465,7 @@ function getCache(config) {
435
465
  if (_cacheInstance) {
436
466
  return _cacheInstance;
437
467
  }
438
- _cacheInstance = new NodeCache({
439
- stdTTL: config.cacheTtl || 300,
440
- maxKeys: config.cacheMaxSize || 1000,
441
- useClones: false,
442
- });
468
+ _cacheInstance = new MapBasedCache(config.cacheMaxSize || 1000, config.cacheTtl || 300);
443
469
  return _cacheInstance;
444
470
  }
445
471
  /**