Requirements
Node.js 18 or later.Installation
Quick start
Store your API key in an environment variable such as
FOFF_API_KEY and read it with process.env.FOFF_API_KEY. Never hard-code it in source files.Configuration
Create aConfig instance with the fields below and pass it to Client.newClient.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
APIKey | string | Yes | Your Foff API key. | |
BaseURL | string | Yes | Base URL of the Foff API. Use https://foff.twospoon.ai/live. | |
Scope | string | Yes | The scope to fetch configs for, such as production or staging. | |
PollingInterval | number | No | 30 | How often, in seconds, to poll for config updates. Use 0 to disable polling. |
Validation
Client.newClient validates the config before creating the client. It throws an error if APIKey, BaseURL, or Scope is missing or empty.
Polling interval normalization
The polling interval is clamped to safe bounds automatically before the client starts.Creating a client
Client.newClient performs the following steps in order:
Validate the config
Checks that
APIKey, BaseURL, and Scope are non-empty. Throws if any required field is missing.Normalize the polling interval
Clamps
PollingInterval to the range 10–3600 seconds (unless it is 0).Fetch all configs (blocking)
Makes an HTTP
GET request to {BaseURL}/api/v1/scopes/{scope}/configs and populates the in-memory cache.The initial fetch is blocking. If the Foff API is unreachable or returns an error at startup,
newClient throws that error immediately. Handle it at startup so your process fails fast rather than serving stale or empty configs.Resolving feature configs
getFeatureConfig(featureName, orderedHierarchy)
Hierarchy resolution algorithm
The SDK resolves from most-specific to least-specific:- It checks the full combination first —
org-1 + team-a + user-123. - It then tries shorter prefixes —
org-1 + team-a, thenorg-1. - If no override matches, it returns the feature’s
"default"value. - If the feature does not exist at all, it returns
null.
Polling
WhenPollingInterval is greater than 0, the SDK polls GET {BaseURL}/api/v1/scopes/{scope}/configs in the background and replaces the in-memory cache on each successful response.
- Polling errors are silently ignored. The SDK continues serving the last successfully fetched config.
- Calling
client.close()stops the background timer and releases all resources.
Recommended polling intervals
| Use case | Interval |
|---|---|
| Near-real-time | 10s |
| Standard | 30–60s |
| Low-traffic / batch | 300–600s |
Client lifecycle
For short-lived scripts, use atry/finally block to guarantee the client is closed: