@openfeature/flagd-provider 0.13.2 → 0.13.4

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/package.json CHANGED
@@ -1,18 +1,23 @@
1
1
  {
2
2
  "name": "@openfeature/flagd-provider",
3
- "version": "0.13.2",
3
+ "version": "0.13.4",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/open-feature/js-sdk-contrib.git",
7
+ "directory": "libs/providers/flagd"
8
+ },
4
9
  "license": "Apache-2.0",
5
10
  "scripts": {
6
11
  "publish-if-not-exists": "cp $NPM_CONFIG_USERCONFIG .npmrc && if [ \"$(npm show $npm_package_name@$npm_package_version version)\" = \"$(npm run current-version -s)\" ]; then echo 'already published, skipping'; else npm publish --access public; fi",
7
12
  "current-version": "echo $npm_package_version"
8
13
  },
9
14
  "peerDependencies": {
10
- "@grpc/grpc-js": "~1.8.0 || ~1.9.0 || ~1.10.0 || ~1.11.0 || ~1.12.0",
15
+ "@grpc/grpc-js": "~1.8.0 || ~1.9.0 || ~1.10.0 || ~1.11.0 || ~1.12.0 || ~1.13.0 || ~1.14.0",
11
16
  "@openfeature/server-sdk": "^1.17.0"
12
17
  },
13
18
  "dependencies": {
14
19
  "lru-cache": "^11.0.0",
15
- "@openfeature/flagd-core": "^1.0.0"
20
+ "@openfeature/flagd-core": "^1.2.0"
16
21
  },
17
22
  "exports": {
18
23
  "./package.json": "./package.json",
@@ -0,0 +1,6 @@
1
+ import type { Hook, EvaluationContext, BeforeHookContext, HookHints } from '@openfeature/server-sdk';
2
+ export declare class SyncMetadataHook implements Hook {
3
+ enrichedContext: () => EvaluationContext;
4
+ constructor(enrichedContext: () => EvaluationContext);
5
+ before(hookContext: BeforeHookContext, hookHints?: HookHints): EvaluationContext;
6
+ }
@@ -1,3 +1,4 @@
1
+ import type { EvaluationContext } from '@openfeature/server-sdk';
1
2
  export type CacheOption = 'lru' | 'disabled';
2
3
  export type ResolverType = 'rpc' | 'in-process';
3
4
  export interface Config {
@@ -13,6 +14,12 @@ export interface Config {
13
14
  * @default 8013
14
15
  */
15
16
  port: number;
17
+ /**
18
+ * The deadline for connections.
19
+ *
20
+ * @default 500
21
+ */
22
+ deadlineMs: number;
16
23
  /**
17
24
  * Determines if TLS should be used.
18
25
  *
@@ -25,6 +32,12 @@ export interface Config {
25
32
  * @example "/tmp/flagd.socks"
26
33
  */
27
34
  socketPath?: string;
35
+ /**
36
+ * TLS certificate path to use when TLS connectivity is enabled.
37
+ *
38
+ * @example "/etc/cert/ca.crt"
39
+ */
40
+ certPath?: string;
28
41
  /**
29
42
  * Resolver type to use by the provider.
30
43
  *
@@ -57,16 +70,60 @@ export interface Config {
57
70
  * @default 1000
58
71
  */
59
72
  maxCacheSize?: number;
73
+ /**
74
+ * The target host (authority) when routing requests through a proxy (e.g. Envoy)
75
+ *
76
+ */
77
+ defaultAuthority?: string;
78
+ /**
79
+ * Initial retry backoff in milliseconds.
80
+ */
81
+ retryBackoffMs?: number;
82
+ /**
83
+ * Maximum retry backoff in milliseconds.
84
+ */
85
+ retryBackoffMaxMs?: number;
86
+ /**
87
+ * gRPC client KeepAlive in milliseconds. Disabled with 0.
88
+ * Only applies to RPC and in-process resolvers.
89
+ *
90
+ * @default 0
91
+ */
92
+ keepAliveTime?: number;
93
+ /**
94
+ * List of gRPC fatal status codes that should cause the provider to fail without retrying.
95
+ * @default []
96
+ */
97
+ fatalStatusCodes?: string[];
98
+ /**
99
+ * Grace period in seconds before provider moves from STALE to ERROR.
100
+ * When the provider disconnects, it emits STALE. If disconnected for longer
101
+ * than retryGracePeriod, it emits ERROR.
102
+ *
103
+ * @default 5
104
+ */
105
+ retryGracePeriod?: number;
60
106
  }
61
- export type FlagdProviderOptions = Partial<Config>;
62
- export declare function getConfig(options?: FlagdProviderOptions): {
63
- host: string;
64
- port: number;
65
- tls: boolean;
66
- socketPath?: string;
67
- resolverType?: ResolverType;
68
- offlineFlagSourcePath?: string;
69
- selector?: string;
70
- cache?: CacheOption;
71
- maxCacheSize?: number;
72
- };
107
+ interface FlagdConfig extends Config {
108
+ /**
109
+ * Function providing an EvaluationContext to mix into every evaluation.
110
+ * The syncContext from the SyncFlagsResponse
111
+ * (https://buf.build/open-feature/flagd/docs/main:flagd.sync.v1#flagd.sync.v1.SyncFlagsResponse),
112
+ * represented as a {@link dev.openfeature.sdk.Structure}, is passed as an argument.
113
+ *
114
+ * This function runs every time the provider (re)connects, and its result is cached and used in every evaluation.
115
+ * By default, the entire sync response (as a JSON Object) is used.
116
+ */
117
+ contextEnricher: (syncContext: EvaluationContext | null) => EvaluationContext;
118
+ }
119
+ export interface FlagdGrpcConfig extends Config {
120
+ /**
121
+ * The deadline for streaming connections.
122
+ *
123
+ * @default 600000
124
+ */
125
+ streamDeadlineMs: number;
126
+ }
127
+ export type FlagdProviderOptions = Partial<FlagdConfig & FlagdGrpcConfig>;
128
+ export declare function getConfig(options?: FlagdProviderOptions): FlagdConfig & FlagdGrpcConfig;
129
+ export {};
@@ -3,3 +3,6 @@ export declare const DEFAULT_MAX_EVENT_STREAM_RETRIES: number;
3
3
  export declare const EVENT_CONFIGURATION_CHANGE = "configuration_change";
4
4
  export declare const EVENT_PROVIDER_READY = "provider_ready";
5
5
  export declare const DEFAULT_MAX_CACHE_SIZE = 1000;
6
+ export declare const DEFAULT_RETRY_GRACE_PERIOD = 5;
7
+ export declare const DEFAULT_MAX_BACKOFF_MS = 12000;
8
+ export declare const FLAGD_SELECTOR_HEADER = "flagd-selector";
@@ -1,14 +1,21 @@
1
- import { EvaluationContext, JsonValue, Logger, OpenFeatureEventEmitter, Provider, ResolutionDetails } from '@openfeature/server-sdk';
2
- import { FlagdProviderOptions } from './configuration';
3
- import { Service } from './service/service';
1
+ import type { EvaluationContext, JsonValue, Logger, Provider, ResolutionDetails } from '@openfeature/server-sdk';
2
+ import { OpenFeatureEventEmitter } from '@openfeature/server-sdk';
3
+ import type { FlagdProviderOptions } from './configuration';
4
+ import type { Service } from './service/service';
5
+ import type { Hook } from '@openfeature/server-sdk';
4
6
  export declare class FlagdProvider implements Provider {
5
7
  private readonly logger?;
6
8
  metadata: {
7
9
  name: string;
8
10
  };
11
+ readonly hooks?: Hook[];
9
12
  readonly runsOn = "server";
10
13
  readonly events: OpenFeatureEventEmitter;
14
+ private syncContext;
11
15
  private readonly _service;
16
+ private readonly _retryGracePeriod;
17
+ private _errorTimer?;
18
+ private _isErrorState;
12
19
  /**
13
20
  * Construct a new flagd provider.
14
21
  *
@@ -17,6 +24,8 @@ export declare class FlagdProvider implements Provider {
17
24
  * @param service optional internal service implementation, should not be needed for production
18
25
  */
19
26
  constructor(options?: FlagdProviderOptions, logger?: Logger | undefined, service?: Service);
27
+ setSyncContext(context: EvaluationContext): void;
28
+ getSyncContext(): EvaluationContext | null;
20
29
  initialize(): Promise<void>;
21
30
  onClose(): Promise<void>;
22
31
  resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, transformedContext: EvaluationContext, logger: Logger): Promise<ResolutionDetails<boolean>>;
@@ -26,4 +35,5 @@ export declare class FlagdProvider implements Provider {
26
35
  private handleReconnect;
27
36
  private handleError;
28
37
  private handleChanged;
38
+ private clearErrorTimer;
29
39
  }
@@ -1,2 +1,48 @@
1
- import { ClientReadableStream } from '@grpc/grpc-js';
1
+ import type { ClientReadableStream, ChannelCredentials, ClientOptions } from '@grpc/grpc-js';
2
+ import type { Config } from '../../configuration';
3
+ import type { Logger } from '@openfeature/server-sdk';
2
4
  export declare const closeStreamIfDefined: (stream: ClientReadableStream<unknown> | undefined) => void;
5
+ /**
6
+ * Creates gRPC channel credentials based on TLS and certificate path configuration.
7
+ * @returns Channel credentials for gRPC connection
8
+ */
9
+ export declare const createChannelCredentials: (tls: boolean, certPath?: string) => ChannelCredentials;
10
+ /**
11
+ * Builds gRPC client options from config.
12
+ */
13
+ export declare function buildClientOptions(config: Config): ClientOptions;
14
+ /**
15
+ * Builds RetryPolicy for gRPC client options.
16
+ * @param serviceNames Array of service names to configure retry policy for
17
+ * @param retryBackoffMs Initial backoff duration in milliseconds
18
+ * @param retryBackoffMaxMs Maximum backoff duration in milliseconds
19
+ * @returns gRPC client options with retry policy
20
+ */
21
+ export declare const buildRetryPolicy: (serviceNames: string[], retryBackoffMs?: number, retryBackoffMaxMs?: number) => string;
22
+ /**
23
+ * Converts an array of gRPC status code strings to a Set of numeric codes.
24
+ * @param fatalStatusCodes Array of status code strings.
25
+ * @param logger Optional logger for warning about unknown codes
26
+ * @returns Set of numeric status codes
27
+ */
28
+ export declare const createFatalStatusCodesSet: (fatalStatusCodes?: string[], logger?: Logger) => Set<number>;
29
+ /**
30
+ * Checks if an error is a fatal gRPC status code that should not be retried.
31
+ * This should only be checked on the first connection attempt.
32
+ *
33
+ * @param err The error to check
34
+ * @param initialized Whether the connection has been successfully initialized
35
+ * @param fatalStatusCodes Set of numeric status codes considered fatal
36
+ * @returns True if the error is fatal and should not be retried
37
+ */
38
+ export declare const isFatalStatusCodeError: (err: Error, initialized: boolean, fatalStatusCodes: Set<number>) => boolean;
39
+ /**
40
+ * Handles a fatal gRPC status code error by logging it.
41
+ * Should only be called when isFatalStatusCodeError returns true.
42
+ *
43
+ * @param err The error to handle
44
+ * @param logger Optional logger for error logging
45
+ * @param disconnectCallback Callback to invoke with the error message
46
+ * @param rejectConnect Optional callback to reject the connection promise
47
+ */
48
+ export declare const handleFatalStatusCodeError: (err: Error, logger: Logger | undefined, disconnectCallback: (message: string) => void, rejectConnect?: (reason: Error) => void) => void;
@@ -1,7 +1,7 @@
1
- import { EvaluationContext, JsonValue, Logger, ResolutionDetails } from '@openfeature/server-sdk';
1
+ import type { EvaluationContext, JsonValue, Logger, ResolutionDetails } from '@openfeature/server-sdk';
2
2
  import { ServiceClient } from '../../../proto/ts/flagd/evaluation/v1/evaluation';
3
- import { Config } from '../../configuration';
4
- import { Service } from '../service';
3
+ import type { FlagdGrpcConfig } from '../../configuration';
4
+ import type { Service } from '../service';
5
5
  interface FlagChange {
6
6
  type: 'delete' | 'write' | 'update';
7
7
  source: string;
@@ -24,8 +24,16 @@ export declare class GRPCService implements Service {
24
24
  private _cache;
25
25
  private _cacheEnabled;
26
26
  private _eventStream;
27
+ private _deadline;
28
+ private readonly _fatalStatusCodes;
29
+ private _initialized;
30
+ private _streamDeadline;
31
+ private _maxBackoffMs;
32
+ private _errorThrottled;
33
+ private readonly _metadata;
27
34
  private get _cacheActive();
28
- constructor(config: Config, client?: ServiceClient, logger?: Logger | undefined);
35
+ constructor(config: FlagdGrpcConfig, client?: ServiceClient, logger?: Logger | undefined);
36
+ clearCache(): void;
29
37
  connect(reconnectCallback: () => void, changedCallback: (flagsChanged: string[]) => void, disconnectCallback: (message: string) => void): Promise<void>;
30
38
  disconnect(): Promise<void>;
31
39
  resolveBoolean(flagKey: string, _: boolean, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<boolean>>;
@@ -1,5 +1,5 @@
1
- import { Logger } from '@openfeature/server-sdk';
2
- import { DataFetch } from '../data-fetch';
1
+ import type { Logger } from '@openfeature/server-sdk';
2
+ import type { DataFetch } from '../data-fetch';
3
3
  export declare class FileFetch implements DataFetch {
4
4
  private _filename;
5
5
  private _logger;
@@ -1,15 +1,22 @@
1
- import { Logger } from '@openfeature/server-sdk';
1
+ import type { EvaluationContext, Logger } from '@openfeature/server-sdk';
2
2
  import { FlagSyncServiceClient } from '../../../../proto/ts/flagd/sync/v1/sync';
3
- import { Config } from '../../../configuration';
4
- import { DataFetch } from '../data-fetch';
3
+ import type { FlagdGrpcConfig } from '../../../configuration';
4
+ import type { DataFetch } from '../data-fetch';
5
5
  /**
6
6
  * Implements the gRPC sync contract to fetch flag data.
7
7
  */
8
8
  export declare class GrpcFetch implements DataFetch {
9
9
  private readonly _syncClient;
10
10
  private readonly _request;
11
+ private readonly _deadlineMs;
12
+ private readonly _maxBackoffMs;
13
+ private readonly _streamDeadlineMs;
14
+ private readonly _metadata;
11
15
  private _syncStream;
16
+ private readonly _setSyncContext;
12
17
  private _logger;
18
+ private readonly _fatalStatusCodes;
19
+ private _errorThrottled;
13
20
  /**
14
21
  * Initialized will be set to true once the initial connection is successful
15
22
  * and the first payload has been received. Subsequent reconnects will not
@@ -22,7 +29,7 @@ export declare class GrpcFetch implements DataFetch {
22
29
  * false if the connection is lost.
23
30
  */
24
31
  private _isConnected;
25
- constructor(config: Config, syncServiceClient?: FlagSyncServiceClient, logger?: Logger);
32
+ constructor(config: FlagdGrpcConfig, setSyncContext: (syncContext: EvaluationContext) => void, syncServiceClient?: FlagSyncServiceClient, logger?: Logger);
26
33
  connect(dataCallback: (flags: string) => string[], reconnectCallback: () => void, changedCallback: (flagsChanged: string[]) => void, disconnectCallback: (message: string) => void): Promise<void>;
27
34
  disconnect(): Promise<void>;
28
35
  private listen;
@@ -1,12 +1,13 @@
1
1
  import type { EvaluationContext, JsonValue, Logger, ResolutionDetails } from '@openfeature/server-sdk';
2
- import { Config } from '../../configuration';
3
- import { Service } from '../service';
4
- import { DataFetch } from './data-fetch';
2
+ import type { FlagdGrpcConfig } from '../../configuration';
3
+ import type { Service } from '../service';
4
+ import type { DataFetch } from './data-fetch';
5
5
  export declare class InProcessService implements Service {
6
6
  private readonly config;
7
7
  private _flagdCore;
8
8
  private _dataFetcher;
9
- constructor(config: Config, dataFetcher?: DataFetch, logger?: Logger);
9
+ constructor(config: FlagdGrpcConfig, setSyncContext: (syncContext: EvaluationContext) => void, dataFetcher?: DataFetch, logger?: Logger);
10
+ clearCache(): void;
10
11
  connect(reconnectCallback: () => void, changedCallback: (flagsChanged: string[]) => void, disconnectCallback: (message: string) => void): Promise<void>;
11
12
  disconnect(): Promise<void>;
12
13
  resolveBoolean(flagKey: string, defaultValue: boolean, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<boolean>>;
@@ -1,4 +1,4 @@
1
- import { EvaluationContext, JsonValue, Logger, ResolutionDetails } from '@openfeature/server-sdk';
1
+ import type { EvaluationContext, JsonValue, Logger, ResolutionDetails } from '@openfeature/server-sdk';
2
2
  export interface Service {
3
3
  connect(reconnectCallback: () => void, changedCallback: (flagsChanged: string[]) => void, disconnectCallback: (message: string) => void): Promise<void>;
4
4
  disconnect(): Promise<void>;
@@ -6,4 +6,5 @@ export interface Service {
6
6
  resolveString(flagKey: string, defaultValue: string, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<string>>;
7
7
  resolveNumber(flagKey: string, defaultValue: number, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<number>>;
8
8
  resolveObject<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<T>>;
9
+ clearCache(): void;
9
10
  }
@@ -21,6 +21,10 @@ export interface ResolveAllResponse {
21
21
  flags: {
22
22
  [key: string]: AnyFlag;
23
23
  };
24
+ /** Metadata for the bulk evaluation */
25
+ metadata: {
26
+ [key: string]: any;
27
+ } | undefined;
24
28
  }
25
29
  export interface ResolveAllResponse_FlagsEntry {
26
30
  key: string;
@@ -38,7 +42,7 @@ export interface AnyFlag {
38
42
  objectValue?: {
39
43
  [key: string]: any;
40
44
  } | undefined;
41
- /** Metadata about this flag, see https://openfeature.dev/specification/types/#flag-metadata */
45
+ /** Metadata for this evaluation */
42
46
  metadata: {
43
47
  [key: string]: any;
44
48
  } | undefined;
@@ -30,8 +30,12 @@ export interface SyncFlagsRequest {
30
30
  }
31
31
  /** SyncFlagsResponse is the server response containing feature flag configurations and the state */
32
32
  export interface SyncFlagsResponse {
33
- /** flagd feature flag configuration. Must be validated to schema - https://raw.githubusercontent.com/open-feature/schemas/main/json/flagd-definitions.json */
33
+ /** flagd feature flag configuration. Must be validated to schema - https://raw.githubusercontent.com/open-feature/flagd-schemas/main/json/flags.json */
34
34
  flagConfiguration: string;
35
+ /** Static context to be included in in-process evaluations (optional). */
36
+ syncContext?: {
37
+ [key: string]: any;
38
+ } | undefined;
35
39
  }
36
40
  /** FetchAllFlagsRequest is the request to fetch all flags. Clients send this request as the client in order to resync their internal state */
37
41
  export interface FetchAllFlagsRequest {
@@ -53,13 +57,22 @@ export interface FetchAllFlagsRequest {
53
57
  }
54
58
  /** FetchAllFlagsResponse is the server response containing feature flag configurations */
55
59
  export interface FetchAllFlagsResponse {
56
- /** flagd feature flag configuration. Must be validated to schema - https://raw.githubusercontent.com/open-feature/schemas/main/json/flagd-definitions.json */
60
+ /** flagd feature flag configuration. Must be validated to schema - https://raw.githubusercontent.com/open-feature/flagd-schemas/main/json/flags.json */
57
61
  flagConfiguration: string;
58
62
  }
59
- /** GetMetadataRequest is the request for retrieving metadata from the sync service */
63
+ /**
64
+ * GetMetadataRequest is the request for retrieving metadata from the sync service
65
+ *
66
+ * @deprecated
67
+ */
60
68
  export interface GetMetadataRequest {
61
69
  }
62
- /** GetMetadataResponse contains metadata from the sync service */
70
+ /**
71
+ * GetMetadataResponse contains metadata from the sync service
72
+ * DEPRECATED; use flagd.sync.v1.SyncFlagsResponse.sync_context
73
+ *
74
+ * @deprecated
75
+ */
63
76
  export interface GetMetadataResponse {
64
77
  metadata: {
65
78
  [key: string]: any;
@@ -134,6 +147,7 @@ export declare const FlagSyncServiceService: {
134
147
  readonly responseSerialize: (value: FetchAllFlagsResponse) => Buffer<ArrayBuffer>;
135
148
  readonly responseDeserialize: (value: Buffer) => FetchAllFlagsResponse;
136
149
  };
150
+ /** @deprecated */
137
151
  readonly getMetadata: {
138
152
  readonly path: "/flagd.sync.v1.FlagSyncService/GetMetadata";
139
153
  readonly requestStream: false;
@@ -147,6 +161,7 @@ export declare const FlagSyncServiceService: {
147
161
  export interface FlagSyncServiceServer extends UntypedServiceImplementation {
148
162
  syncFlags: handleServerStreamingCall<SyncFlagsRequest, SyncFlagsResponse>;
149
163
  fetchAllFlags: handleUnaryCall<FetchAllFlagsRequest, FetchAllFlagsResponse>;
164
+ /** @deprecated */
150
165
  getMetadata: handleUnaryCall<GetMetadataRequest, GetMetadataResponse>;
151
166
  }
152
167
  export interface FlagSyncServiceClient extends Client {
@@ -155,6 +170,7 @@ export interface FlagSyncServiceClient extends Client {
155
170
  fetchAllFlags(request: FetchAllFlagsRequest, callback: (error: ServiceError | null, response: FetchAllFlagsResponse) => void): ClientUnaryCall;
156
171
  fetchAllFlags(request: FetchAllFlagsRequest, metadata: Metadata, callback: (error: ServiceError | null, response: FetchAllFlagsResponse) => void): ClientUnaryCall;
157
172
  fetchAllFlags(request: FetchAllFlagsRequest, metadata: Metadata, options: Partial<CallOptions>, callback: (error: ServiceError | null, response: FetchAllFlagsResponse) => void): ClientUnaryCall;
173
+ /** @deprecated */
158
174
  getMetadata(request: GetMetadataRequest, callback: (error: ServiceError | null, response: GetMetadataResponse) => void): ClientUnaryCall;
159
175
  getMetadata(request: GetMetadataRequest, metadata: Metadata, callback: (error: ServiceError | null, response: GetMetadataResponse) => void): ClientUnaryCall;
160
176
  getMetadata(request: GetMetadataRequest, metadata: Metadata, options: Partial<CallOptions>, callback: (error: ServiceError | null, response: GetMetadataResponse) => void): ClientUnaryCall;
@@ -57,7 +57,7 @@ export interface SyncFlagsRequest {
57
57
  }
58
58
  /** SyncFlagsResponse is the server response containing feature flag configurations and the state */
59
59
  export interface SyncFlagsResponse {
60
- /** flagd feature flag configuration. Must be validated to schema - https://raw.githubusercontent.com/open-feature/schemas/main/json/flagd-definitions.json */
60
+ /** flagd feature flag configuration. Must be validated to schema - https://raw.githubusercontent.com/open-feature/flagd-schemas/main/json/flags.json */
61
61
  flagConfiguration: string;
62
62
  /**
63
63
  * State conveying the operation to be performed by flagd. See the descriptions of SyncState for an explanation of
@@ -85,7 +85,7 @@ export interface FetchAllFlagsRequest {
85
85
  }
86
86
  /** FetchAllFlagsResponse is the server response containing feature flag configurations */
87
87
  export interface FetchAllFlagsResponse {
88
- /** flagd feature flag configuration. Must be validated to schema - https://raw.githubusercontent.com/open-feature/schemas/main/json/flagd-definitions.json */
88
+ /** flagd feature flag configuration. Must be validated to schema - https://raw.githubusercontent.com/open-feature/flagd-schemas/main/json/flags.json */
89
89
  flagConfiguration: string;
90
90
  }
91
91
  export declare const SyncFlagsRequest: {