@openfeature/js-sdk
Advanced tools
Comparing version 1.1.0-experimental-9d746fab8c970534ef33d8da3fa80a5e44601b1e to 1.1.0
@@ -60,3 +60,2 @@ "use strict"; | ||
__export(src_exports, { | ||
ApiEvents: () => ApiEvents, | ||
ErrorCode: () => ErrorCode, | ||
@@ -69,3 +68,2 @@ FlagNotFoundError: () => FlagNotFoundError, | ||
ParseError: () => ParseError, | ||
ProviderEvents: () => ProviderEvents, | ||
StandardResolutionReasons: () => StandardResolutionReasons, | ||
@@ -77,5 +75,2 @@ TargetingKeyMissingError: () => TargetingKeyMissingError, | ||
// src/open-feature.ts | ||
var import_events = require("events"); | ||
// src/logger.ts | ||
@@ -133,13 +128,2 @@ var LOG_LEVELS = ["error", "warn", "info", "debug"]; | ||
// src/types.ts | ||
var ProviderEvents = /* @__PURE__ */ ((ProviderEvents2) => { | ||
ProviderEvents2["Ready"] = "PROVIDER_READY"; | ||
ProviderEvents2["Error"] = "PROVIDER_ERROR"; | ||
ProviderEvents2["ConfigurationChanged"] = "PROVIDER_CONFIGURATION_CHANGED"; | ||
ProviderEvents2["Shutdown"] = "PROVIDER_SHUTDOWN"; | ||
return ProviderEvents2; | ||
})(ProviderEvents || {}); | ||
var ApiEvents = /* @__PURE__ */ ((ApiEvents2) => { | ||
ApiEvents2["ProviderChanged"] = "providerChanged"; | ||
return ApiEvents2; | ||
})(ApiEvents || {}); | ||
var StandardResolutionReasons = { | ||
@@ -151,2 +135,3 @@ TARGETING_MATCH: "TARGETING_MATCH", | ||
UNKNOWN: "UNKNOWN", | ||
STATIC: "STATIC", | ||
CACHED: "CACHED", | ||
@@ -172,3 +157,2 @@ ERROR: "ERROR" | ||
this._hooks = []; | ||
this._handlerWrappers = []; | ||
this.metadata = { | ||
@@ -179,11 +163,3 @@ name: options.name, | ||
this._context = context; | ||
this.attachListeners(); | ||
OpenFeatureAPI.getInstance().events.on("providerChanged" /* ProviderChanged */, () => this.attachListeners()); | ||
} | ||
addHandler(eventType, handler) { | ||
this._handlerWrappers.push({ eventType, handler }); | ||
if (eventType === "PROVIDER_READY" /* Ready */ && this.providerAccessor().ready) { | ||
handler(); | ||
} | ||
} | ||
setLogger(logger) { | ||
@@ -363,10 +339,2 @@ this._clientLogger = new SafeLogger(logger); | ||
} | ||
attachListeners() { | ||
Object.values(ProviderEvents).forEach((e) => { | ||
var _a; | ||
return (_a = this.providerAccessor().events) == null ? void 0 : _a.on(e, () => { | ||
this._handlerWrappers.filter((wrapper) => wrapper.eventType === e).forEach((wrapper) => wrapper.handler()); | ||
}); | ||
}); | ||
} | ||
}; | ||
@@ -419,3 +387,2 @@ | ||
constructor() { | ||
this.events = new import_events.EventEmitter(); | ||
this._provider = NOOP_PROVIDER; | ||
@@ -463,6 +430,3 @@ this._transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR; | ||
setProvider(provider) { | ||
if (this._provider !== provider) { | ||
this.events.emit("providerChanged" /* ProviderChanged */); | ||
this._provider = provider; | ||
} | ||
this._provider = provider; | ||
return this; | ||
@@ -574,3 +538,2 @@ } | ||
0 && (module.exports = { | ||
ApiEvents, | ||
ErrorCode, | ||
@@ -583,3 +546,2 @@ FlagNotFoundError, | ||
ParseError, | ||
ProviderEvents, | ||
StandardResolutionReasons, | ||
@@ -586,0 +548,0 @@ TargetingKeyMissingError, |
@@ -41,5 +41,2 @@ var __defProp = Object.defineProperty; | ||
// src/open-feature.ts | ||
import { EventEmitter } from "events"; | ||
// src/logger.ts | ||
@@ -97,13 +94,2 @@ var LOG_LEVELS = ["error", "warn", "info", "debug"]; | ||
// src/types.ts | ||
var ProviderEvents = /* @__PURE__ */ ((ProviderEvents2) => { | ||
ProviderEvents2["Ready"] = "PROVIDER_READY"; | ||
ProviderEvents2["Error"] = "PROVIDER_ERROR"; | ||
ProviderEvents2["ConfigurationChanged"] = "PROVIDER_CONFIGURATION_CHANGED"; | ||
ProviderEvents2["Shutdown"] = "PROVIDER_SHUTDOWN"; | ||
return ProviderEvents2; | ||
})(ProviderEvents || {}); | ||
var ApiEvents = /* @__PURE__ */ ((ApiEvents2) => { | ||
ApiEvents2["ProviderChanged"] = "providerChanged"; | ||
return ApiEvents2; | ||
})(ApiEvents || {}); | ||
var StandardResolutionReasons = { | ||
@@ -115,2 +101,3 @@ TARGETING_MATCH: "TARGETING_MATCH", | ||
UNKNOWN: "UNKNOWN", | ||
STATIC: "STATIC", | ||
CACHED: "CACHED", | ||
@@ -136,3 +123,2 @@ ERROR: "ERROR" | ||
this._hooks = []; | ||
this._handlerWrappers = []; | ||
this.metadata = { | ||
@@ -143,11 +129,3 @@ name: options.name, | ||
this._context = context; | ||
this.attachListeners(); | ||
OpenFeatureAPI.getInstance().events.on("providerChanged" /* ProviderChanged */, () => this.attachListeners()); | ||
} | ||
addHandler(eventType, handler) { | ||
this._handlerWrappers.push({ eventType, handler }); | ||
if (eventType === "PROVIDER_READY" /* Ready */ && this.providerAccessor().ready) { | ||
handler(); | ||
} | ||
} | ||
setLogger(logger) { | ||
@@ -327,10 +305,2 @@ this._clientLogger = new SafeLogger(logger); | ||
} | ||
attachListeners() { | ||
Object.values(ProviderEvents).forEach((e) => { | ||
var _a; | ||
return (_a = this.providerAccessor().events) == null ? void 0 : _a.on(e, () => { | ||
this._handlerWrappers.filter((wrapper) => wrapper.eventType === e).forEach((wrapper) => wrapper.handler()); | ||
}); | ||
}); | ||
} | ||
}; | ||
@@ -383,3 +353,2 @@ | ||
constructor() { | ||
this.events = new EventEmitter(); | ||
this._provider = NOOP_PROVIDER; | ||
@@ -427,6 +396,3 @@ this._transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR; | ||
setProvider(provider) { | ||
if (this._provider !== provider) { | ||
this.events.emit("providerChanged" /* ProviderChanged */); | ||
this._provider = provider; | ||
} | ||
this._provider = provider; | ||
return this; | ||
@@ -537,3 +503,2 @@ } | ||
export { | ||
ApiEvents, | ||
ErrorCode, | ||
@@ -546,3 +511,2 @@ FlagNotFoundError, | ||
ParseError, | ||
ProviderEvents, | ||
StandardResolutionReasons, | ||
@@ -549,0 +513,0 @@ TargetingKeyMissingError, |
@@ -1,3 +0,3 @@ | ||
import { Client, ClientMetadata, EvaluationContext, EvaluationDetails, EventProvider, FlagEvaluationOptions, FlagValue, Handler, Hook, JsonValue, Logger, Provider, ProviderEvents } from './types'; | ||
declare type OpenFeatureClientOptions = { | ||
import { Client, ClientMetadata, EvaluationContext, EvaluationDetails, FlagEvaluationOptions, FlagValue, Hook, JsonValue, Logger, Provider } from './types'; | ||
type OpenFeatureClientOptions = { | ||
name?: string; | ||
@@ -13,5 +13,3 @@ version?: string; | ||
private _clientLogger?; | ||
private _handlerWrappers; | ||
constructor(providerAccessor: () => Provider & Partial<EventProvider>, globalLogger: () => Logger, options: OpenFeatureClientOptions, context?: EvaluationContext); | ||
addHandler(eventType: ProviderEvents, handler: Handler): void; | ||
constructor(providerAccessor: () => Provider, globalLogger: () => Logger, options: OpenFeatureClientOptions, context?: EvaluationContext); | ||
setLogger(logger: Logger): OpenFeatureClient; | ||
@@ -38,4 +36,3 @@ setContext(context: EvaluationContext): OpenFeatureClient; | ||
private get _logger(); | ||
private attachListeners; | ||
} | ||
export {}; |
@@ -1,6 +0,3 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
import { Client, EvaluationContext, FlagValue, GlobalApi, Hook, Logger, Provider, ProviderMetadata, TransactionContext, TransactionContextPropagator } from './types'; | ||
export declare class OpenFeatureAPI implements GlobalApi { | ||
events: EventEmitter; | ||
private _provider; | ||
@@ -7,0 +4,0 @@ private _transactionContextPropagator; |
@@ -1,38 +0,14 @@ | ||
/// <reference types="node" /> | ||
import EventEmitter from 'events'; | ||
export declare type PrimitiveValue = null | boolean | string | number; | ||
export interface EventProvider { | ||
readonly events: EventEmitter; | ||
readonly ready: boolean; | ||
} | ||
export declare enum ProviderEvents { | ||
Ready = "PROVIDER_READY", | ||
Error = "PROVIDER_ERROR", | ||
ConfigurationChanged = "PROVIDER_CONFIGURATION_CHANGED", | ||
Shutdown = "PROVIDER_SHUTDOWN" | ||
} | ||
export declare enum ApiEvents { | ||
ProviderChanged = "providerChanged" | ||
} | ||
export interface Eventing { | ||
addHandler(notificationType: string, handler: Handler): void; | ||
} | ||
export declare type EventContext = { | ||
notificationType: string; | ||
[key: string]: unknown; | ||
}; | ||
export declare type Handler = (eventContext?: EventContext) => void; | ||
export declare type EventCallbackMessage = (eventContext: EventContext) => void; | ||
export declare type JsonObject = { | ||
export type PrimitiveValue = null | boolean | string | number; | ||
export type JsonObject = { | ||
[key: string]: JsonValue; | ||
}; | ||
export declare type JsonArray = JsonValue[]; | ||
export type JsonArray = JsonValue[]; | ||
/** | ||
* Represents a JSON node value. | ||
*/ | ||
export declare type JsonValue = PrimitiveValue | JsonObject | JsonArray; | ||
export type JsonValue = PrimitiveValue | JsonObject | JsonArray; | ||
/** | ||
* Represents a JSON node value, or Date. | ||
*/ | ||
export declare type EvaluationContextValue = PrimitiveValue | Date | { | ||
export type EvaluationContextValue = PrimitiveValue | Date | { | ||
[key: string]: EvaluationContextValue; | ||
@@ -43,3 +19,3 @@ } | EvaluationContextValue[]; | ||
*/ | ||
export declare type EvaluationContext = { | ||
export type EvaluationContext = { | ||
/** | ||
@@ -52,4 +28,4 @@ * A string uniquely identifying the subject (end-user, or client service) of a flag evaluation. | ||
} & Record<string, EvaluationContextValue>; | ||
export declare type FlagValue = boolean | string | number | JsonValue; | ||
export declare type FlagValueType = 'boolean' | 'string' | 'number' | 'object'; | ||
export type FlagValue = boolean | string | number | JsonValue; | ||
export type FlagValueType = 'boolean' | 'string' | 'number' | 'object'; | ||
export interface FlagEvaluationOptions { | ||
@@ -213,4 +189,8 @@ hooks?: Hook[]; | ||
/** | ||
* A cached value was resolved. | ||
* The resolved value is static (no dynamic evaluation). | ||
*/ | ||
readonly STATIC: "STATIC"; | ||
/** | ||
* The resolved value was retrieved from cache. | ||
*/ | ||
readonly CACHED: "CACHED"; | ||
@@ -254,4 +234,4 @@ /** | ||
} | ||
export declare type ResolutionReason = keyof typeof StandardResolutionReasons | (string & Record<never, never>); | ||
export declare type ResolutionDetails<U> = { | ||
export type ResolutionReason = keyof typeof StandardResolutionReasons | (string & Record<never, never>); | ||
export type ResolutionDetails<U> = { | ||
value: U; | ||
@@ -263,6 +243,6 @@ variant?: string; | ||
}; | ||
export declare type EvaluationDetails<T extends FlagValue> = { | ||
export type EvaluationDetails<T extends FlagValue> = { | ||
flagKey: string; | ||
} & ResolutionDetails<T>; | ||
export interface Client extends EvaluationLifeCycle<Client>, Features, ManageContext<Client>, ManageLogger<Client>, Eventing { | ||
export interface Client extends EvaluationLifeCycle<Client>, Features, ManageContext<Client>, ManageLogger<Client> { | ||
readonly metadata: ClientMetadata; | ||
@@ -349,3 +329,3 @@ } | ||
} | ||
export declare type HookHints = Readonly<Record<string, unknown>>; | ||
export type HookHints = Readonly<Record<string, unknown>>; | ||
interface Metadata { | ||
@@ -411,3 +391,3 @@ } | ||
*/ | ||
export declare type TransactionContext = EvaluationContext; | ||
export type TransactionContext = EvaluationContext; | ||
interface ManageTransactionContextPropagator<T> extends TransactionContextPropagator { | ||
@@ -414,0 +394,0 @@ /** |
{ | ||
"name": "@openfeature/js-sdk", | ||
"version": "1.1.0-experimental-9d746fab8c970534ef33d8da3fa80a5e44601b1e", | ||
"version": "1.1.0", | ||
"description": "OpenFeature SDK for JavaScript", | ||
@@ -41,2 +41,3 @@ "main": "./dist/cjs/index.js", | ||
"exports": { | ||
"types": "./dist/types/index.d.ts", | ||
"import": "./dist/esm/index.js", | ||
@@ -48,7 +49,7 @@ "require": "./dist/cjs/index.js", | ||
"@openfeature/flagd-provider": "~0.7.0", | ||
"@types/jest": "^28.1.4", | ||
"@types/jest": "^29.0.0", | ||
"@types/node": "^18.0.3", | ||
"@typescript-eslint/eslint-plugin": "^5.23.0", | ||
"@typescript-eslint/parser": "^5.23.0", | ||
"esbuild": "^0.15.1", | ||
"esbuild": "^0.16.0", | ||
"eslint": "^8.14.0", | ||
@@ -61,7 +62,7 @@ "eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-jsdoc": "^39.3.6", | ||
"jest": "^28.1.3", | ||
"jest": "^29.0.0", | ||
"jest-cucumber": "^3.0.1", | ||
"jest-junit": "^14.0.0", | ||
"jest-junit": "^15.0.0", | ||
"prettier": "^2.6.2", | ||
"ts-jest": "^28.0.8", | ||
"ts-jest": "^29.0.0", | ||
"ts-node": "^10.8.2", | ||
@@ -68,0 +69,0 @@ "typedoc": "^0.23.16", |
@@ -10,7 +10,17 @@ # OpenFeature SDK for JavaScript | ||
This is the JavaScript implementation of [OpenFeature](https://openfeature.dev), a vendor-agnostic abstraction library for evaluating feature flags. | ||
<p align="center"> | ||
<strong> | ||
<a href="https://docs.openfeature.dev/docs/tutorials/getting-started/node">Getting Started<a/> | ||
• | ||
<a href="https://open-feature.github.io/js-sdk">API Documentation<a/> | ||
</strong> | ||
</p> | ||
--- | ||
This is the JavaScript implementation of [OpenFeature][openfeature-website], a vendor-agnostic abstraction library for evaluating feature flags. | ||
We support multiple data types for flags (numbers, strings, booleans, objects) as well as hooks, which can alter the lifecycle of a flag evaluation. | ||
**This library is intended to be used in server-side contexts and has only experimental support for web usage.** | ||
> This library is intended to be used in server-side contexts and has only **experimental support** for web usage. Client-side support can be tracked [here][client-side-github-issue]. | ||
@@ -31,2 +41,4 @@ ## Installation | ||
To configure the SDK you'll need to add a provider to the `OpenFeature` global signleton. From there, you can generate a `client` which is usable by your code. While you'll likely want a provider for your specific backend, we've provided a `NoopProvider`, which simply returns the default value. | ||
```typescript | ||
@@ -60,4 +72,44 @@ import { OpenFeature } from '@openfeature/js-sdk'; | ||
A list of available providers can be found [here][server-side-artifacts]. | ||
For complete documentation, visit: https://docs.openfeature.dev/docs/category/concepts | ||
## Hooks | ||
Implement your own hook by conforming to the [Hook interface][hook-interface]. | ||
All of the hook stages (before, after, error, and finally) are optional. | ||
```typescript | ||
import { OpenFeature, Hook, HookContext } from '@openfeature/js-sdk'; | ||
// Example hook that logs if an error occurs during flag evaluation | ||
export class GlobalDebugHook implements Hook { | ||
after(hookContext: HookContext, err: Error) { | ||
console.log('hook context', hookContext); | ||
console.error(err); | ||
} | ||
} | ||
``` | ||
Register the hook at global, client, or invocation level. | ||
```typescript | ||
import { OpenFeature } from '@openfeature/js-sdk'; | ||
// This hook used is used for example purposes | ||
import { GlobalDebugHook, ClientDebugHook, InvocationDebugHook } from './debug-hook'; | ||
// A global hook will run on every flag evaluation | ||
OpenFeature.addHooks(new GlobalDebugHook()); | ||
const client = OpenFeature.getClient('my-app'); | ||
// A client hook will run on every flag evaluation executed by this client | ||
client.addHooks(new ClientDebugHook()); | ||
// An invocation hook will only run on the registred flag evaluation method | ||
const boolValue = await client.getBooleanValue('boolFlag', false, {}, { hooks: [new InvocationDebugHook()] }); | ||
``` | ||
A list of available hooks can be found [here][server-side-artifacts]. | ||
## Contributing | ||
@@ -67,5 +119,5 @@ | ||
Our community meetings are held regularly and open to everyone. Check the [OpenFeature community calendar](https://calendar.google.com/calendar/u/0?cid=MHVhN2kxaGl2NWRoMThiMjd0b2FoNjM2NDRAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ) for specific dates and for the Zoom meeting links. | ||
Our community meetings are held regularly and open to everyone. Check the [OpenFeature community calendar](https://calendar.google.com/calendar/u/0?cid=MHVhN2kxaGl2NWRoMThiMjd0b2FoNjM2NDRAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ) for specific dates and the Zoom meeting links. | ||
Thanks so much to our contributors. | ||
### Thanks to everyone that has already contributed | ||
@@ -81,1 +133,6 @@ <a href="https://github.com/open-feature/js-sdk/graphs/contributors"> | ||
[Apache License 2.0](LICENSE) | ||
[openfeature-website]: https://openfeature.dev | ||
[server-side-artifacts]: https://docs.openfeature.dev/docs/reference/technologies/server/javascript | ||
[hook-interface]: https://open-feature.github.io/js-sdk/interfaces/Hook.html | ||
[client-side-github-issue]: https://github.com/open-feature/spec/issues/167 |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
134
175907
1613