# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.50.0] - 2026-05-29

This release introduces **Wingify** as the primary SDK branding and a new npm package namespace, while keeping existing **VWO** integrations fully supported on `vwo-fme-node-sdk`.

### Added

- **Wingify npm package** — `wingify-fme-node-sdk` (Node) and `wingify-fme-javascript-sdk` (browser) are built from the same codebase as the VWO packages. Install the Wingify package for new integrations:

  ```bash
  npm install wingify-fme-node-sdk
  ```

- **Wingify public API** — use `init`, `onInit`, `IWingifyOptions`, `IWingifyClient`, and `IWingifyContextModel` as the recommended entry point for new integrations:

  ```javascript
  const { init } = require('wingify-fme-node-sdk');

  (async () => {
    const client = await init({
      accountId: '123456',
      sdkKey: '32-alpha-numeric-sdk-key',
      logger: { level: 'DEBUG' },
    });

    const context = { id: 'user-123' };

    const flag = await client.getFlag('feature-key', context);
    console.log(flag.isEnabled(), flag.getVariation());
  })();
  ```

  TypeScript:

  ```typescript
  import { init, IWingifyOptions, IWingifyClient } from 'wingify-fme-node-sdk';
  ```

### Changed

- The SDK implementation now uses a shared core with build-time brand selection (`vwo` vs `wingify`). Wingify builds use Wingify-specific hosts (`edge.wingify.net` for settings, `collect.wingify.net` for events) and log prefix (`Wingify-SDK`).
- **No breaking changes for existing `vwo-fme-node-sdk` integrations** — public exports, method signatures, server event names, payload keys, and runtime behavior remain compatible with the VWO platform.

### Deprecated

Nothing is deprecated on **`vwo-fme-node-sdk`**. Existing imports and types continue to work without modification.

For **new projects**, install `wingify-fme-node-sdk` instead of `vwo-fme-node-sdk`. The API surface is equivalent; only package name and exported type names differ:

| Existing VWO package (`vwo-fme-node-sdk`)             | Wingify package (`wingify-fme-node-sdk`) |
| ----------------------------------------------------- | ---------------------------------------- |
| `init`, `onInit`                                      | `init`, `onInit`                         |
| `IVWOOptions`                                         | `IWingifyOptions`                        |
| `IVWOClient`                                          | `IWingifyClient`                         |
| `IVWOContextModel`                                    | `IWingifyContextModel`                   |
| `LogLevelEnum`, `StorageConnector`, `Flag`, `getUUID` | Same exports (names unchanged)           |

Existing code on **`vwo-fme-node-sdk` does not need to change**:

```javascript
const { init } = require('vwo-fme-node-sdk');

(async () => {
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
  });

  const context = { id: 'user-123', _vwo: { ua: 'Mozilla/5.0...' } };

  const flag = await vwoClient.getFlag('feature-key', context);
})();
```

**Migration tip (optional, for new Wingify installs only):** Change the npm package from `vwo-fme-node-sdk` to `wingify-fme-node-sdk`, and replace type names `IVWOOptions` → `IWingifyOptions`, `IVWOClient` → `IWingifyClient`, and `IVWOContextModel` → `IWingifyContextModel`. Method signatures and SDK behavior are unchanged. Legacy options such as `vwoBuilder` and context fields such as `_vwo` remain supported on the VWO package.

## [1.43.1] - 2026-05-11

### Added

- Fixed an issue where `collectionPrefix` was incorrectly prepended to event endpoint URLs when a gateway service was configured.

## [1.43.0] - 2026-04-07

### Added

- Added support for whitelisting based on custom variables via `variationTargetingVariables` in the context. This allows users to be forcefully bucketed into specific variations based on custom evaluating rules, bypassing standard traffic allocation.

  Example usage:

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
  });

  // Force users with 'premium' plan into a specific whitelisted variation
  const userContext = {
    id: 'user-123',
    variationTargetingVariables: {
      plan: 'premium',
    },
  };

  const flag = await vwoClient.getFlag('feature-key', userContext);
  ```

- Added support for `isDevMode` in `userContext` that disables event dispatching for that user when enabled in both `userContext` and VWO settings.

  Example usage:

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
  });

  // send isDevMode in userContext
  const userContext = {
    id: 'user-123',
    isDevMode: true,
  };

  // Decisions are returned as normal, but events are not sent to DaCDN
  const flag = await vwoClient.getFlag('feature-key', userContext);
  await vwoClient.trackEvent('event-name', userContext, eventProperties);
  ```

## [1.42.0] - 2026-04-01

### Added

- Added a `shutdown()` API on `VWOClient` to support graceful teardown in long-running environments. Calling `shutdown()` now stops the internal settings polling loop, flushes any pending batched events, clears batch timers, and releases batching resources.

  Example usage:

  ```javascript
  const { init } = require('vwo-fme-node-sdk');

  (async () => {
    const vwoClient = await init({
      accountId: '123456',
      sdkKey: '32-alpha-numeric-sdk-key',
    });

    // When your app/process is about to exit:
    await vwoClient.shutdown();
  })();
  ```

### Changed

- Optimized the batch events queue to enforce `eventsPerRequest` as a hard per-dispatch cap, preserve event ordering when retries occur and avoid unnecessary timer wakeups when the queue is empty.
- Improved Node.js HTTPS networking by introducing a configurable HTTPS agent (`httpsAgentConfig`) in the network layer, including validation and sensible defaults for `keepAlive`, `maxSockets`, `maxFreeSockets`, and `timeout` to provide better socket reuse and connection management.

  Example usage:

  ```javascript
  const { init } = require('vwo-fme-node-sdk');

  (async () => {
    const vwoClient = await init({
      accountId: '123456',
      sdkKey: '32-alpha-numeric-sdk-key',
      httpsAgentConfig: {
        keepAlive: true, // default: true
        maxSockets: 100, // default: 100, minimum 50
        maxFreeSockets: 20, // default: 20, minimum 10
        timeout: 60000, // in milliseconds, default: 60000, minimum 30000
      },
    });

    // ...use the client...
  })();
  ```

## [1.41.0] - 2026-03-18

### Added

- Added support for custom bucketing seed via `bucketingSeed` in the context. This allows users to bucket by a shared identifier instead of the individual user ID, ensuring all users within the same group receive the same variation.

  Example usage:

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
  });

  // All employees of company-abc will get the same variation
  const context = {
    id: 'employee-123',
    bucketingSeed: 'company-abc',
  };
  const flag = await vwoClient.getFlag('feature-key', context);
  ```

## [1.40.1] - 2026-03-02

### Changed

- Introduced `SDKMetaUtil` and `sdkMeta` config to allow overriding the default SDK name and version used in events. VWO FE React SDK will consume via it.

## [1.40.0] - 2026-02-26

### Added

- Enhanced browser tracking implementation: now uses `navigator.sendBeacon` by default for sending events, falling back to XHR when needed. This behavior is configurable via `browserConfig.networkTransportMode` (`'sendBeacon'` or `'xhr'`).
- Added `browserConfig` for browser-specific configuration, including `networkTransportMode` and `clientStorage`. `browserConfig.clientStorage` is preferred over the top-level `clientStorage`, with a safe `{}` fallback when neither is provided.

  Example usage:

  ```javascript
  // Default: use sendBeacon in browser (with XHR fallback)
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
    // browserConfig.networkTransportMode defaults to 'sendBeacon'
  });

  // Force XHR for all browser tracking requests
  const vwoClientWithXHR = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
    browserConfig: {
      networkTransportMode: NetworkTransportMode.XHR,
    },
  });
  ```

## [1.39.0] - 2025-02-26

### Added

- Added support for holdout groups to exclude users from features based on segmentation and traffic allocation.

## [1.38.0] - 2026-02-16

### Added

- Added support to use the context `id` as the visitor UUID instead of auto-generating one. You can read the visitor UUID from the flag result via `flag.getUUID()` (e.g. to pass to the web client).

  Example usage:

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
  });

  // Default: SDK generates a UUID from id and account
  const contextWithGeneratedUuid = { id: 'user-123' };
  const flag1 = await vwoClient.getFlag('feature-key', contextWithGeneratedUuid);

  // Use your own UUID (e.g. from web client) by disabling UUID generation
  const contextWithCustomUuid = {
    id: 'D7E2EAA667909A2DB8A6371FF0975C2A5', // your existing UUID
  };
  const flag2 = await vwoClient.getFlag('feature-key', contextWithCustomUuid);

  // Get the UUID from the flag result (e.g. to pass to web client)
  const uuid = flag1.getUUID();
  console.log('Visitor UUID:', uuid);
  ```

## [1.37.1] - 2026-02-09

### Fixed

- Exposed `postSegmentationVariables` and `sessionId` in the `IVWOContextModel` TypeScript interface to enable direct access for SDK users.

## [1.37.0] - 2026-01-28

### Added

- Added session management capabilities to enable integration with VWO's web client testing campaigns. The SDK now automatically generates and manages session IDs to connect server-side feature flag decisions with client-side user sessions.

  Example usage:

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
  });

  // Session ID is automatically generated if not provided
  const context = { id: 'user-123' };
  const flag = await vwoClient.getFlag('feature-key', context);

  // Access the session ID to pass to web client for session recording
  const sessionId = flag.getSessionId();
  console.log('Session ID for web client:', sessionId);
  ```

  You can also explicitly set a session ID to match web client session

  ```javascript
  const context = {
    id: 'user-123',
    sessionId: 1697123456, // Custom session ID matching web client
  };
  const flag = await vwoClient.getFlag('feature-key', context);
  ```

  This enhancement enables seamless integration between server-side feature flag decisions and client-side session recording, allowing for comprehensive user behavior analysis across both server and client environments.

## [1.36.0] - 2026-01-28

### Added

- Refactored the SDK to provide support for multiple instances. Previously, the SDK was singleton-based, which caused state to be shared across multiple SDK instances. Now, you can create any number of SDK instances, each with its own isolated utils, services, and associated state.

  ```javascript
  const { init } = require('vwo-fme-node-sdk');

  // Initialize multiple VWO clients with different account IDs and SDK keys
  (async function () {
    // First instance for production environment
    const vwoClientProd = await init({
      accountId: '123456',
      sdkKey: '32-alpha-numeric-sdk-key-prod',
    });

    // Second instance for staging environment
    const vwoClientStaging = await init({
      accountId: '789012',
      sdkKey: '32-alpha-numeric-sdk-key-staging',
    });

    // Each instance operates independently with its own settings and state
    const userContext = { id: 'unique_user_id' };

    // Use production client
    const prodFeature = await vwoClientProd.getFlag('feature_key', userContext);
    console.log('Production feature enabled:', prodFeature.isEnabled());

    // Use staging client
    const stagingFeature = await vwoClientStaging.getFlag('feature_key', userContext);
    console.log('Staging feature enabled:', stagingFeature.isEnabled());
  })();
  ```

  Each SDK instance maintains its own:

  - Settings and configuration
  - Services (storage, logger, network layer, etc.)
  - Utils and helper functions
  - State and cached data

  This ensures complete isolation between instances, allowing you to safely use multiple VWO accounts or environments in the same application without any interference.

## [1.35.0] - 2025-12-27

### Added

- Introduced `setSettings` and `getSettings` methods in the `Connector` class, enabling persistent storage and retrieval of VWO settings through custom storage connectors.

```javascript
class StorageConnector extends StorageConnector {
  protected ttl = 7200000; // 2 hours in milliseconds
  protected alwaysUseCachedSettings = false;

  constructor() {
    super();
  }

  /**
   * Get data from storage
   * @param {string} featureKey
   * @param {string} userId
   * @returns {Promise<any>}
   */
  async get(featureKey, userId) {
    // return await data (based on featureKey and userId)
  }

  /**
   * Set data in storage
   * @param {object} data
   */
  async set(data) {
    // Set data corresponding to a featureKey and user ID
    // Use data.featureKey and data.userId to store the above data for a specific feature and a user
  }

  /**
   * Get settingsData from storage
   * @param {number} accountId
   * @param {string} sdkKey
   * @returns {Promise<ISettingsData>}
   */
  async getSettings(accountId, sdkKey) {
    // Implement logic to retrieve cached settings based on accountId and sdkKey
    // Must return an object with structure: { settings: {...}, timestamp: number }
  }

  /**
   * Set settingsData in storage
   * @param {ISettingsData} data
   */
  async setSettings(data) {
    // Implement logic to store settings data
    // Use data.settings.accountId and data.settings.sdkKey to store the above data for a specific accountId and sdkKey
  }

}
```

## [1.34.1] - 2025-12-12

### Fixed

- Fixed parameter types for `Connector` class `get` and `set` methods to ensure correct usage and TypeScript compatibility.
- Improved log transport so that console logging consistently respects the configured `shouldLogToStandardOutput` if transports are provided.

## [1.34.0] - 2025-12-10

### Added

- Added support for `edgeConfig` option to enable edge/serverless environment optimizations. This configuration should only be passed in serverless environments (e.g., Cloudflare Workers, Vercel, Fastl, etc.). When used in environments like Cloudflare, Vercel, and Fastly,events areflushed using `ctx.waitUntil(vwoClient.flushEvents());` to ensure proper event tracking after execution completes.

```javascript
vwoClient = await init({
  accountId: '123456',
  sdkKey: '32-alpha-numeric-sdk-key',
  edgeConfig: {
    shouldWaitForTrackingCalls: true,
  },
});

// at the end flush all events
await vwoClient.flushEvents();
```

**Note:** In Cloudflare/Vercel/Fastly environments, use `ctx.waitUntil(vwoClient.flushEvents());` to ensure all events flush and data is sent to VWO servers for reporting purposes.

## [1.33.1] - 2025-12-05

### Changed

- Asynchronous dispatch of the `sdkInit` event during initialization to further optimize the init method execution time.

## [1.33.0] - 2025-12-04

### Changed

- Improved compatibility and dependency handling for modern JavaScript environments and build systems (including ESM and Shopify Hydrogen).

## [1.32.0] - 2025-11-26

### Fixed

- Enhanced Logging capabilities for `batch-events-v2` endpoint.

## [1.31.0] - 2025-11-17

### Added

- Enhanced Logging capabilities at VWO by sending `vwo_sdkDebug` event with additional debug properties.

## [1.30.2] - 2025-11-13

### Fixed

- Fixed an issue where type definitions were not properly exported in `package.json`.

## [1.30.1] - 2025-11-12

### Fixed

- Resolved issues causing `Range Error` and `undefined (setting)` during settings polling.

## [1.30.0] - 2025-11-06

### Added

- Exposed `getUUID` method that deterministically generates a UUID for a given `userId` and VWO `accountId` combination. The generated UUID is used in VWO and remains consistent for the same user-account pair.

```javascript
const { getUUID } = require('vwo-fme-node-sdk');

// Generate UUID for a user
const userId = 'user-123';
const accountId = '123456';
const uuid = getUUID(userId, accountId);

console.log('Generated UUID:', uuid);
// Output: Generated UUID: CC25A368ADA0542699EAD62489811105
```

## [1.29.0] - 2025-09-25

### Added

- Add support for user aliasing (will work with [Gateway Service](https://developers.vwo.com/v2/docs/gateway-service) only)

```javascript
vwoClient = await init({
  accountId: '123456',
  sdkKey: '32-alpha-numeric-sdk-key',

  gatewayService: {
    url: 'http://your-custom-gateway-url',
  },
  // Required to use Aliasing
  isAliasingEnabled: true,
});

vwoClient.setAlias(userContext, 'aliasId');
```

## [1.28.1] - 2025-09-15

### Changed

- Update schema validation to enforce required fields while allowing additional dynamic properties without validation failures
- Fix Usage Stats bug and retry minor bug

## [1.28.0] - 2025-09-09

### Added

- Post-segmentation variables are now automatically included as unregistered attributes, enabling post-segmentation without requiring manual setup.
- Added support for built-in targeting conditions, including `browser version`, `OS version`, and `IP address`, with advanced operator support (greaterThan, lessThan, regex).`

## [1.27.0] - 2025-09-05

### Added

- Fixed conversion of alphanumeric string to numeric values

## [1.26.0] - 2025-08-26

### Added

- Sends usage statistics to VWO servers automatically during SDK initialization

## [1.25.2] - 2025-08-12

### Added

- Enhanced logging capabilities at VWO by adding additional debug information to VWO Error log messages including relevant metadata for better troubleshooting

## [1.25.1] - 2025-08-14

### Fixed

- Hardcode SDK name and extract version to a separate file to reduce bundle size by avoiding imports of the entire `package.json` file.
- Update log message showing incorrect retry time interval

## [1.25.0] - 2025-08-07

### Changed

- Added ES Module (ESM) build support for projects using `"type": "module"` in their `package.json` file.

## [1.24.0] - 2025-08-05

### Added

- Added support for sending a one-time initialization event to the server to verify correct SDK setup.

## [1.23.4] - 2025-07-29

### Fixed

- Remove extra logs from the distributable bundle

## [1.23.3] - 2025-07-25

### Added

- Send the SDK name and version in the events and batching call to VWO as query parameters.

## [1.23.2] - 2025-07-24

### Added

- Send the SDK name and version in the settings call to VWO as query parameters.

## [1.23.1] - 2025-07-24

### Fixed

- Updated regex in `addIsGatewayServiceRequiredFlag` method to remove unsupported lookbehind and named capture groups, ensuring compatibility with older browsers like Safari 16.3 (`SyntaxError: Invalid regular expression: invalid group specifier name`).

## [1.23.0] - 2025-07-18

### Added

- Added support for polling intervals to periodically fetch and update settings:

  - If `pollInterval` is set in options (must be >= 1000 milliseconds), that interval will be used
  - If `pollInterval` is configured in VWO application settings, that will be used
  - If neither is set, defaults to 10 minute polling interval

  Example usage:

  ```javascript
  vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
    pollInterval: 60000, // Set the poll interval to 60 seconds,
  });
  ```

## [1.22.0] - 2025-07-17

### Added

- Added support for redirecting all network calls through a custom proxy URL for browser environments. This feature allows users to route all SDK network requests (settings, tracking, etc.) through their own proxy server. This is particularly useful for bypassing ad-blockers that may interfere with VWO's default network requests.

```javascript
const vwoClient = await init({
  sdkKey: 'VWO_SDK_KEY',
  accountId: 'VWO_ACCOUNT_ID',

  // All network calls will be routed through this URL
  proxyUrl: 'https://your-proxy-server.com',
});
```

## [1.21.0] - 2025-07-03

### Added

- Added configurable retry mechanism for network requests with partial override support. You can now customize retry behavior by passing a `retryConfig` in the `network` options:

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',

    retryConfig: {
      shouldRetry: true, // Turn retries on/off (default: true)
      maxRetries: 3, // How many times to retry (default: 3)
      initialDelay: 2, // First retry after 2 seconds (default: 2)
      backoffMultiplier: 2, // Double the delay each time (delays: 2s, 4s, 8s)
    },
  });
  ```

## [1.20.2] - 2025-06-26

### Fixed

- Fixed settings fetch failure on Serverless environment by improving network request handling and compatibility

## [1.20.1] - 2025-06-19

### Fixed

- Enhanced security for browser storage by implementing Base64 encoding for SDK key stored in localStorage.

## [1.20.0] - 2025-06-18

### Added

- Enhanced storage configuration options for browser environments with new features:

  - Added custom `ttl` (Time To Live) option to control how long settings remain valid in storage
  - Added `alwaysUseCachedSettings` option to always use cached settings regardless of TTL
  - Default TTL remains 2 hours if not specified

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
    clientStorage: {
      key: 'vwo_data', // defaults to vwo_fme_settings
      provider: sessionStorage, // defaults to localStorage
      isDisabled: false, // defaults to false
      alwaysUseCachedSettings: true, // defaults to false
      ttl: 3600000, // 1 hour in milliseconds, defaults to 2 hours
    },
  });
  ```

  These new options provide more control over how settings are cached and refreshed:

  - When `alwaysUseCachedSettings` is true, the SDK will always use cached settings if available, regardless of TTL
  - Custom `ttl` allows you to control how frequently settings are refreshed from the server
  - Settings are still updated in the background to keep the cache fresh

  Read more [here](https://developers.vwo.com/v2/docs/fme-javascript-cache-settings)

## [1.19.0] - 2025-05-29

### Added

- Enhanced browser environment support by enabling direct communication with VWO's DACDN when no `VWO Gateway Service` is configured to reduce network latency and improves performance by eliminating the need for seting up an intermediate service for browser-based environments.

- Added built-in persistent storage functionality for browser environments. The JavaScript SDK automatically stores feature flag decisions in `localStorage` to ensure consistent user experiences across sessions and optimize performance by avoiding re-evaluating users. You can customize or disable this behavior using the `clientStorage` option while initializing the JavaScript SDK:

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
    clientStorage: {
      key: 'vwo_data', // defaults to vwo_fme_data
      provider: sessionStorage, // defaults to localStorage
      isDisabled: false, // defaults to false, set to true to disable storage
    },
  });
  ```

## [1.18.0] - 2025-05-19

### Changed

- Merged [#3](https://github.com/wingify/vwo-fme-node-sdk/pull/3) by [@thomasdbock](https://github.com/thomasdbock)
- Exported interfaces `IVWOClient`, `IVWOOptions`, `IVWOContextModel`, and `Flag` to provide better TypeScript support and enable type checking for SDK configuration and usage

  ```typescript
  import { init, IVWOClient, IVWOOptions, Flag } from 'vwo-fme-node-sdk';

  // Example of using IVWOOptions for type-safe configuration
  const options: IVWOOptions = {
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
  };

  // Example of using IVWOClient for type-safe client usage
  const vwoClient: IVWOClient = await init(options);

  // Example of using Flag interface for type-safe flag handling
  const flag: Flag = await vwoClient.getFlag('feature-key', { id: 'user-123' });
  const isEnabled: boolean = flag.isEnabled();

  const stringVariable: string = flag.getVariable('variable_key', 'default_value');
  const booleanVariable: boolean = flag.getVariable('variable_key', true);
  const numberVariable: number = flag.getVariable('variable_key', 10);
  ```

## [1.17.1] - 2025-05-13

### Added

- Added a feature to track and collect usage statistics related to various SDK features and configurations which can be useful for analytics, and gathering insights into how different features are being utilized by end users.

## [1.17.0] - 2025-05-06

### Added

- Added support for `batchEventData` configuration to optimize network requests by batching multiple events together. This allows you to:

  - Configure `requestTimeInterval` to flush events after a specified time interval
  - Set `eventsPerRequest` to control maximum events per batch
  - Implement `flushCallback` to handle batch processing results
  - Manually trigger event flushing via `flushEvents()` method

  ```javascript
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
    batchEventData: {
      requestTimeInterval: 60, // Flush events every 60 seconds
      eventsPerRequest: 100, // Send up to 100 events per request
      flushCallback: (error, events) => {
        console.log('Events flushed successfully');
        // custom implementation here
      },
    },
  });
  ```

  - You can also manually flush events using the `flushEvents()` method:

  ```javascript
  vwoClient.flushEvents();
  ```

## [1.16.0] - 2025-05-01

### Fixed

- Fixed schema validation error that occurred when no feature flags were configured in the VWO application by properly handling empty `features` and `campaigns` from settings response

## [1.15.0] - 2025-04-18

### Added

- Added exponential backoff retry mechanism for failed network requests. This improves reliability by automatically retrying failed requests with increasing delays between attempts.

## [1.14.1] - 2025-03-13

### Fixed

- Fixed the issue where the SDK was not sending error logs to VWO server for better debugging.

## [1.14.0] - 2025-03-12

### Added

- Added support for sending error logs to VWO server for better debugging.

## [1.13.0] - 2025-02-21

### Fixed

- Fixed network request handling in serverless environments by replacing `XMLHttpRequest` with `fetch` API for improved compatibility and reliability.

## [1.12.0] - 2024-02-13

### Added

- Support for `Object` in `setAttribute` method to send multiple attributes at once.

  ```javascript
  const attributes = { attr1: value1, attr2: value2 };
  client.setAttribute(attributes, context);
  ```

## [1.11.0] - 2024-12-20

### Added

- added support for custom salt values in campaign rules to ensure consistent user bucketing across different campaigns. This allows multiple campaigns to share the same salt value, resulting in users being assigned to the same variations across those campaigns. Salt for a campaign can be configured inside VWO application only when the campaign is in the draft state.

## [1.10.0] - 2024-11-22

### Added

- added new method `updateSettings` to update settings on the client instance.

## [1.9.0] - 2024-11-14

### Added

- Added support to pass settings in `init` method.

## [1.8.0] - 2024-09-25

### Added

- added support for Personalise rules within `Mutually Exclusive Groups`.

## [1.7.0] - 2024-09-03

### Added

- added support to wait for network response incase of edge like environment.

  ```javascript
  const { init } = require('vwo-fme-node-sdk');

  const vwoClient = await init({
    accountId: '123456', // VWO Account ID
    sdkKey: '32-alpha-numeric-sdk-key', // SDK Key
    shouldWaitForTrackingCalls: true, // if running on edge env
  });
  ```

## [1.6.0] - 2024-08-27

### Fixed

- Update key name from `user` to `userId` for storing User ID in storage connector.

  ```javascript
  class StorageConnector extends StorageConnector {
    constructor() {
      super();
    }

    /**
     * Get data from storage
     * @param {string} featureKey
     * @param {string} userId
     * @returns {Promise<any>}
     */
    async get(featureKey, userId) {
      // return await data (based on featureKey and userId)
    }

    /**
     * Set data in storage
     * @param {object} data
     */
    async set(data) {
      // Set data corresponding to a featureKey and user ID
      // Use data.featureKey and data.userId to store the above data for a specific feature and a user
    }
  }
  ```

## [1.5.2] - 2024-08-20

### Fixed

- Updated regular expressions for `GREATER_THAN_MATCH`, `GREATER_THAN_EQUAL_TO_MATCH`, `LESS_THAN_MATCH`, and `LESS_THAN_EQUAL_TO_MATCH` segmentation operators

## [1.5.1] - 2024-08-13

### Fixed

- Encode user-agent in `setAttribute` and `trackEvent` APIs before making a call to VWO server`

## [1.5.0] - 2024-08-01

### Changed

- Modified code to support browser and Node.js environment
- The same SDK can be used in the browser and Node.js environment without any changes in the code from the customer side
- Refactored code to use interfaces and types wherever missing or required

### Added

Client-side Javascript SDK

- Used webpack for bundling code
- Separate builds for Node.js and browser using `webpack`
- SDK is compatible to be run on browser(as a Script, client-side rendering with React ,Ionic framework, etc.)
- Node.js environment can now use one single bundled file too, if required

## [1.3.1] - 2024-07-225

### Fixed

- fix: add support for DSL where featureIdValue could be `off`
- refactor: make eventProperties as third parameter

## [1.3.0] - 2024-06-20

### Fixed

- Update dist folder

## [1.2.4] - 2024-06-14

### Fixed

- Fix: add revenueProp in metricSchema for settings validation
- Optimizaton: if userAgent and ipAddress both are null, then no need to send call to gatewayService

## [1.2.2] - 2024-06-05

### Fixed

- Fix: use experiment-key from rule instead of whitelisted object
- Use [vwo-fme-sdk-e2e-test-settings-n-cases](https://github.com/wingify/vwo-fme-sdk-e2e-test-settings-n-cases) for importing segmentation tests instead of using hardcoded

## [1.2.1] - 2024-05-30

### Fixed

- Handle how device was being used by User-Agent parser.
- Refactor VWO Gateway service code to handle non-US accounts
- Fix passing required headers in the network-calls for tracking user details to VWO servers
- Fix some log messages where variables were not getting interpolated correctly

### Changed

- Instead of hardcoding the test-cases and expectations for `getFlag` API, we create a separate repo where tests and expectations were written in a JSON format. This is done to make sure we have common and same tests passing across our FME SDKs. Node SDK is using it as dependency - [vwo-fme-sdk-e2e-test-settings-n-cases](https://github.com/wingify/vwo-fme-sdk-e2e-test-settings-n-cases)
- SDK is now fully supported from Node 12+ versions. We ensured this by running exhaustive unit/E2E tests via GitHub actions for all the Node 12+ versions
- Add a new github-action to generate and publish code documentation generated via `typedoc`

## [1.2.0] - 2024-05-22

### Changed

- **Segmentation module**

  - Modify how context and settings are being used inside modular segmentor code
  - Cache location / User-Agent data per `getFlag` API
  - Single endpoint for location and User-Agent at gateway-service so that at max one call will be required to fetch data from gateway service

- **Context refactoring**

  - Context is now flattened out

    ```javascript
    {
      id: 'user-id',           // MANDATORY
      ipAddress: '1.2.3.4',    // OPTIONAL - required for user targeting
      userAgent: '...',        // OPTIONAL - required for user targeting
      // For pre-segmentation in campaigns
      customVariables: {
        price: 300
        // ...
      }
    }
    ```

- **Storage optimizations**

  - Optimized how data is being stored and retrieved

  - Example on how to pass storage

  ```javascript
  class StorageConnector extends StorageConnector {
    constructor() {
      super();
    }

    /**
     * Get data from storage
     * @param {string} featureKey
     * @param {string} userId
     * @returns {Promise<any>}
     */
    async get(featureKey, userId) {
      // return await data (based on featureKey and userId)
    }

    /**
     * Set data in storage
     * @param {object} data
     */
    async set(data) {
      // Set data corresponding to a featureKey and user ID
      // Use data.featureKey and data.userId to store the above data for a specific feature and a user
    }
  }

  init({
    sdkKey: '...',
    accountId: '123456',
    storage: StorageConnector,
  });
  ```

- **Using interfaces, types, and model-driven code**

  - Since we are using TypeScript which helps in the definition types and catching errors while developing.

- **Overall Code refactoring**

  - Simplified the flow of `getFlag` API

- **Log messages**

  - Separate Repo to have all the logs in one place.
  - Log messages were updated

  ```javascript
  logger:  {
    level: LogLevelEnum.DEBUG,    // DEBUG, INFO, ERROR, TRACE< WARN
    prefix: 'CUSTOM LOG PREFIX',      // VWO-SDK default
    transport: {                      // Custom Logger
      debug: msg => console.log(msg),
      info: msg => console.log(msg),
      warn: msg => console.log(msg),
      error: msg => console.log(msg),
      trace: msg => console.log(msg)
    }
  }

  init({
    sdkKey: '...',
    accountId: '123456',
    logger: logger
  });
  ```

### Added

- **Code inline documentation**

  - Entire Code was documented as per JavaScript Documentation convention.

- **Unit and E2E Testing**

  - Set up Test framework using `Jest`
  - Wrote unit and E2E tests to ensure nothing breaks while pushing new code
  - Ensure criticla components are working properly on every build
  - Integrate with Codecov to show coverage percentage in README
  - Post status of tests running on different node versions to Wingify slack channel

- **onInit hook**

  ```javaScript
  init({
    sdkKey: '...',
    accountId: '123456'
  });

  onInit().then(async (vwoClient) => {
    const feature = await vwoClient.getFlag('feature-key', context);
    console.log('getFlag is: ', feature.isEnabled());
  }).catch(err => {
    console.log('Error: ', err);
  });
  ```

- **Error handling**

  - Gracefully handle any kind of error - TypeError, NetworkError, etc.

- **Polling support**

  - Provide a way to fetch settings periodically and update the instance to use the latest settings

  ```javaScript
  const vwoClient = await init({
    sdkKey: '...',
    accountId: '123456',
    pollInterval: 5000 // in milliseconds
  });
  ```

## [1.0.0] - 2024-02-22

### Added

- First release of VWO Feature Management and Experimentation capabilities

  ```javascript
  const { init } = require('vwo-fme-node-sdk');

  const vwoClient = await init({
    accountId: '123456', // VWO Account ID
    sdkKey: '32-alpha-numeric-sdk-key', // SDK Key
  });

  // set user context
  const userContext = { id: 'unique_user_id' };
  // returns a flag object
  const getFlag = await vwoClient.getFlag('feature_key', userContext);
  // check if flag is enabled
  const isFlagEnabled = getFlag.isEnabled();
  // get variable
  const intVar = getFlag.getVariable('int_variable_key');

  // track event
  vwoClient.trackEvent('addToCart', eventProperties, userContext);
  ```
