Skip to main content
darkship docs
Open console

SDKs · OpenFeature

OpenFeature provider

Write your application against the vendor-neutral OpenFeature API and plug darkship in as the provider. It wraps the native JavaScript SDK and adds no behaviour of its own, so both paths give the same answers.

Updated Oct 28, 20263 min read Edit this page on GitHub (opens in a new tab)

When to use it#

  • You already use OpenFeature, or want to keep the option to swap providers.
  • You want the standard hooks, evaluation-context and event APIs across several services.

Use the native SDK when you need the get*Detail variants with darkship-specific reasons and bucket, date flags as Date, or the bootstrap option. The provider is a thin mapping on top; it cannot return anything the native SDK couldn't.

Availability

The JavaScript package @darkship/openfeature-provider ships two providers, DarkshipServerProvider (import from @darkship/openfeature-provider/server, for Node) and DarkshipWebProvider (import from @darkship/openfeature-provider/web, for browsers). Python has its own provider in the Python SDK (pip install "darkship[openfeature]"). Other languages use the REST API.

Install#

Shellterminal
$ npm install @openfeature/server-sdk @darkship/openfeature-provider

Register the provider#

TypeScriptopenfeature.ts
import { OpenFeature } from '@openfeature/server-sdk';
import { DarkshipServerProvider } from '@darkship/openfeature-provider/server'; // alias: DarkshipProvider

await OpenFeature.setProviderAndWait(
  new DarkshipServerProvider({ sdkKey: process.env.DARKSHIP_SDK_KEY! }),   // ds_srv_...
);

const client = OpenFeature.getClient();

const enabled = await client.getBooleanValue(
  'new-checkout-flow',
  false,
  { targetingKey: 'usr_marta', plan: 'pro', country: 'BR' },
);

The provider constructor accepts all native init() options (see init options) plus client (reuse an existing SDK client), hooks, initTimeoutMs (server, default 3000) and offReason (STATIC by default; DISABLED if you want that reason for an environment switched off). The package depends on @darkship/sdk. With setProviderAndWait, OpenFeature waits for the provider's READY event, which maps to the SDK's ready.

Mapping reference#

API#

How OpenFeature concepts map onto darkship.
OpenFeaturedarkship
Provider metadata.namedarkship
resolveBooleanEvaluationgetBooleanDetail
resolveStringEvaluationgetStringDetail
resolveNumberEvaluationgetIntDetail or getFloatDetail, chosen by the flag's type
resolveObjectEvaluationgetJsonDetail. Also used for date flags (see below).
EvaluationContext.targetingKeycontext.key, used for rollout hashing and key target lists
Other context fields (email, groups, ...)Context attributes: email and groups are matched by email and group target lists; the rest are available to targeting rules
variantThe variation name (variationKey). flagMetadata carries ruleId, bucket and flagType
Dates have no OpenFeature type

A date flag is resolved through getObjectValue and arrives as an object carrying an ISO-8601 string. Parse it yourself: new Date(value.iso). Prefer the native SDK if you use date flags heavily.

TypeScriptevaluation context
await client.getBooleanValue('ai-search-beta', false, {
  targetingKey: 'usr_marta',            // becomes context.key
  email: 'Marta@Acme.com',               // becomes the email attribute
  groups: ['beta-testers', 'acme-staff'], // becomes the groups attribute
  plan: 'pro',
});

Reasons#

Native reason on the left; OpenFeature reason returned by the provider on the right.
darkship reasonOpenFeature reason
OFFSTATIC
TARGET_MATCH, RULE_MATCHTARGETING_MATCH, or SPLIT when a percentage rollout decided (the detail has a bucket)
FALLTHROUGHDEFAULT, or SPLIT when a percentage rollout decided
DEFAULTDEFAULT
NOT_READY, ERRORERROR (with an error code; your default is returned)

Error codes#

When resolution fails, OpenFeature returns your default and the error code.
darkshipOpenFeature errorCode
FLAG_NOT_FOUNDFLAG_NOT_FOUND
TYPE_MISMATCHTYPE_MISMATCH
INVALID_CONTEXTINVALID_CONTEXT
NOT_READY (reason; the SDK's code is PROVIDER_NOT_READY)PROVIDER_NOT_READY
MALFORMED_FLAG, GENERALGENERAL

Provider events#

SDK events surface as OpenFeature provider events.
SDK eventOpenFeature event
ready, recoveredPROVIDER_READY
updatePROVIDER_CONFIGURATION_CHANGED (with flagsChanged)
stalePROVIDER_STALE
errorPROVIDER_ERROR

Hooks and shutdown#

OpenFeature hooks (logging, telemetry, validation) work unchanged because they sit above the provider. On shutdown call await OpenFeature.close(); it calls the provider's onClose, which runs the SDK's close() and flushes counters.

TypeScripthooks.ts
import { OpenFeature, type Hook } from '@openfeature/server-sdk';

const audit: Hook = {
  after: (ctx, details) => metrics.count('flag', { key: ctx.flagKey, variant: details.variant, reason: details.reason }),
};
OpenFeature.addHooks(audit);

Parity with the native SDK#

The provider depends on @darkship/sdk and calls it; it has no evaluation code of its own. That is deliberate: native and OpenFeature paths cannot drift apart, and the package's parity test runs every shared conformance vector through the provider and compares it with the native SDK. There is no official OpenFeature conformance suite for JavaScript providers. If you see a different result between them for the same flag and context, please report it as a bug.

Was this helpful?