@splitsoftware/openfeature-js-split-provider 1.2.0 → 1.3.0

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.
@@ -0,0 +1,23 @@
1
+ import type { EvaluationContext } from '@openfeature/server-sdk';
2
+ import type { Consumer } from './types';
3
+ import { DEFAULT_TRAFFIC_TYPE } from './types';
4
+
5
+ /**
6
+ * Transforms OpenFeature evaluation context into the consumer shape used by the Split API:
7
+ * targeting key, traffic type (with default), and remaining attributes.
8
+ */
9
+ export function transformContext(
10
+ context: EvaluationContext,
11
+ defaultTrafficType: string = DEFAULT_TRAFFIC_TYPE
12
+ ): Consumer {
13
+ const { targetingKey, trafficType: ttVal, ...attributes } = context;
14
+ const trafficType =
15
+ ttVal != null && typeof ttVal === 'string' && ttVal.trim() !== ''
16
+ ? ttVal
17
+ : defaultTrafficType;
18
+ return {
19
+ targetingKey,
20
+ trafficType,
21
+ attributes: JSON.parse(JSON.stringify(attributes)),
22
+ };
23
+ }
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  EvaluationContext,
3
+ EventDetails,
3
4
  FlagNotFoundError,
4
5
  JsonValue,
6
+ Logger,
5
7
  OpenFeatureEventEmitter,
6
8
  ParseError,
7
9
  Provider,
@@ -11,72 +13,82 @@ import {
11
13
  TargetingKeyMissingError,
12
14
  TrackingEventDetails
13
15
  } from '@openfeature/server-sdk';
14
- import { SplitFactory } from '@splitsoftware/splitio';
15
16
  import type SplitIO from '@splitsoftware/splitio/types/splitio';
16
-
17
- type SplitProviderOptions = {
18
- splitClient: SplitIO.IClient | SplitIO.IAsyncClient;
19
- }
20
-
21
- type Consumer = {
22
- targetingKey: string | undefined;
23
- trafficType: string;
24
- attributes: SplitIO.Attributes;
25
- };
26
-
27
- const CONTROL_VALUE_ERROR_MESSAGE = 'Received the "control" value from Split.';
28
- const CONTROL_TREATMENT = 'control';
17
+ import { getSplitClient } from './client-resolver';
18
+ import { transformContext } from './context';
19
+ import { parseValidJsonObject, parseValidNumber } from './parsers';
20
+ import { attachReadyEventHandlers, waitUntilReady } from './readiness';
21
+ import {
22
+ CONTROL_TREATMENT,
23
+ CONTROL_VALUE_ERROR_MESSAGE,
24
+ DEFAULT_TRAFFIC_TYPE,
25
+ PROVIDER_NAME,
26
+ SplitProviderConstructorOptions,
27
+ type Consumer
28
+ } from './types';
29
29
 
30
30
  export class OpenFeatureSplitProvider implements Provider {
31
- metadata = {
32
- name: 'split',
33
- };
31
+ readonly metadata = {
32
+ name: PROVIDER_NAME,
33
+ } as const;
34
+
35
+ readonly runsOn = 'server' as const;
34
36
 
35
37
  private client: SplitIO.IClient | SplitIO.IAsyncClient;
36
38
  private trafficType: string;
37
39
  public readonly events = new OpenFeatureEventEmitter();
38
40
 
39
- private getSplitClient(options: SplitProviderOptions | string | SplitIO.ISDK | SplitIO.IAsyncSDK) {
40
- if (typeof(options) === 'string') {
41
- const splitFactory = SplitFactory({core: { authorizationKey: options } });
42
- return splitFactory.client();
43
- }
44
-
45
- let splitClient;
46
- try {
47
- splitClient = (options as SplitIO.ISDK | SplitIO.IAsyncSDK).client();
48
- } catch {
49
- splitClient = (options as SplitProviderOptions).splitClient
50
- }
51
-
52
- return splitClient;
41
+ constructor(
42
+ options: SplitProviderConstructorOptions
43
+ ) {
44
+ this.trafficType = DEFAULT_TRAFFIC_TYPE;
45
+ this.client = getSplitClient(options);
46
+
47
+ attachReadyEventHandlers(this.client, this.events, this.metadata.name);
48
+
49
+ this.client.on(
50
+ this.client.Event.SDK_UPDATE,
51
+ (updateMetadata: SplitIO.SdkUpdateMetadata) => {
52
+ const eventDetails: EventDetails = {
53
+ providerName: this.metadata.name,
54
+ ...(updateMetadata
55
+ ? {
56
+ metadata: { type: updateMetadata.type },
57
+ flagsChanged: updateMetadata.names || [],
58
+ }
59
+ : {}),
60
+ };
61
+ this.events.emit(ProviderEvents.ConfigurationChanged, eventDetails);
62
+ }
63
+ );
53
64
  }
54
-
55
- constructor(options: SplitProviderOptions | string | SplitIO.ISDK | SplitIO.IAsyncSDK) {
56
- // Asume 'user' as default traffic type'
57
- this.trafficType = 'user';
58
- this.client = this.getSplitClient(options);
59
- this.client.on(this.client.Event.SDK_UPDATE, () => {
60
- this.events.emit(ProviderEvents.ConfigurationChanged);
61
- });
65
+
66
+ /**
67
+ * Called by the SDK after the provider is set. Waits for the Split client to be ready.
68
+ * When this promise resolves, the SDK emits ProviderEvents.Ready.
69
+ */
70
+ async initialize(_context?: EvaluationContext): Promise<void> {
71
+ void _context;
72
+ await waitUntilReady(this.client, this.events, this.metadata.name);
62
73
  }
63
74
 
64
75
  public async resolveBooleanEvaluation(
65
76
  flagKey: string,
66
77
  _: boolean,
67
- context: EvaluationContext
78
+ context: EvaluationContext,
79
+ logger: Logger
68
80
  ): Promise<ResolutionDetails<boolean>> {
81
+ void logger;
69
82
  const details = await this.evaluateTreatment(
70
83
  flagKey,
71
- this.transformContext(context)
84
+ transformContext(context, this.trafficType)
72
85
  );
73
86
  const treatment = details.value.toLowerCase();
74
87
 
75
- if ( treatment === 'on' || treatment === 'true' ) {
88
+ if (treatment === 'on' || treatment === 'true') {
76
89
  return { ...details, value: true };
77
90
  }
78
-
79
- if ( treatment === 'off' || treatment === 'false' ) {
91
+ if (treatment === 'off' || treatment === 'false') {
80
92
  return { ...details, value: false };
81
93
  }
82
94
 
@@ -86,37 +98,42 @@ export class OpenFeatureSplitProvider implements Provider {
86
98
  public async resolveStringEvaluation(
87
99
  flagKey: string,
88
100
  _: string,
89
- context: EvaluationContext
101
+ context: EvaluationContext,
102
+ logger: Logger
90
103
  ): Promise<ResolutionDetails<string>> {
91
- const details = await this.evaluateTreatment(
104
+ void logger;
105
+ return this.evaluateTreatment(
92
106
  flagKey,
93
- this.transformContext(context)
107
+ transformContext(context, this.trafficType)
94
108
  );
95
- return details;
96
109
  }
97
110
 
98
111
  public async resolveNumberEvaluation(
99
112
  flagKey: string,
100
113
  _: number,
101
- context: EvaluationContext
114
+ context: EvaluationContext,
115
+ logger: Logger
102
116
  ): Promise<ResolutionDetails<number>> {
117
+ void logger;
103
118
  const details = await this.evaluateTreatment(
104
119
  flagKey,
105
- this.transformContext(context)
120
+ transformContext(context, this.trafficType)
106
121
  );
107
- return { ...details, value: this.parseValidNumber(details.value) };
122
+ return { ...details, value: parseValidNumber(details.value) };
108
123
  }
109
124
 
110
125
  public async resolveObjectEvaluation<U extends JsonValue>(
111
126
  flagKey: string,
112
127
  _: U,
113
- context: EvaluationContext
128
+ context: EvaluationContext,
129
+ logger: Logger
114
130
  ): Promise<ResolutionDetails<U>> {
131
+ void logger;
115
132
  const details = await this.evaluateTreatment(
116
133
  flagKey,
117
- this.transformContext(context)
134
+ transformContext(context, this.trafficType)
118
135
  );
119
- return { ...details, value: this.parseValidJsonObject(details.value) };
136
+ return { ...details, value: parseValidJsonObject<U>(details.value) };
120
137
  }
121
138
 
122
139
  private async evaluateTreatment(
@@ -129,31 +146,26 @@ export class OpenFeatureSplitProvider implements Provider {
129
146
  );
130
147
  }
131
148
  if (flagKey == null || flagKey === '') {
132
- throw new FlagNotFoundError(
133
- 'flagKey must be a non-empty string'
134
- );
149
+ throw new FlagNotFoundError('flagKey must be a non-empty string');
135
150
  }
136
151
 
137
- await new Promise((resolve, reject) => {
138
- this.readinessHandler(resolve, reject);
139
- });
140
-
141
- const { treatment: value, config }: SplitIO.TreatmentWithConfig = await this.client.getTreatmentWithConfig(
142
- consumer.targetingKey,
143
- flagKey,
144
- consumer.attributes
145
- );
152
+ await waitUntilReady(this.client, this.events, this.metadata.name);
153
+ const { treatment: value, config }: SplitIO.TreatmentWithConfig =
154
+ await this.client.getTreatmentWithConfig(
155
+ consumer.targetingKey,
156
+ flagKey,
157
+ consumer.attributes
158
+ );
146
159
  if (value === CONTROL_TREATMENT) {
147
160
  throw new FlagNotFoundError(CONTROL_VALUE_ERROR_MESSAGE);
148
161
  }
149
- const flagMetadata = { config: config ? config : '' };
150
- const details: ResolutionDetails<string> = {
151
- value: value,
162
+ const flagMetadata = Object.freeze({ config: config ?? '' });
163
+ return {
164
+ value,
152
165
  variant: value,
153
- flagMetadata: flagMetadata,
166
+ flagMetadata,
154
167
  reason: StandardResolutionReasons.TARGETING_MATCH,
155
168
  };
156
- return details;
157
169
  }
158
170
 
159
171
  async track(
@@ -161,17 +173,21 @@ export class OpenFeatureSplitProvider implements Provider {
161
173
  context: EvaluationContext,
162
174
  details: TrackingEventDetails
163
175
  ): Promise<void> {
164
-
165
- // eventName is always required
166
- if (trackingEventName == null || trackingEventName === '')
176
+ if (trackingEventName == null || trackingEventName === '') {
167
177
  throw new ParseError('Missing eventName, required to track');
178
+ }
168
179
 
169
- // targetingKey is always required
170
- const { targetingKey, trafficType } = this.transformContext(context);
171
- if (targetingKey == null || targetingKey === '')
172
- throw new TargetingKeyMissingError('Missing targetingKey, required to track');
180
+ const { targetingKey, trafficType } = transformContext(
181
+ context,
182
+ this.trafficType
183
+ );
184
+ if (targetingKey == null || targetingKey === '') {
185
+ throw new TargetingKeyMissingError(
186
+ 'Missing targetingKey, required to track'
187
+ );
188
+ }
173
189
 
174
- let value;
190
+ let value: number | undefined;
175
191
  let properties: SplitIO.Properties = {};
176
192
  if (details != null) {
177
193
  if (details.value != null) {
@@ -180,73 +196,18 @@ export class OpenFeatureSplitProvider implements Provider {
180
196
  if (details.properties != null) {
181
197
  properties = details.properties as SplitIO.Properties;
182
198
  }
183
- }
184
-
185
- this.client.track(targetingKey, trafficType, trackingEventName, value, properties);
186
- }
187
-
188
- public async onClose?(): Promise<void> {
189
- return this.client.destroy();
190
- }
199
+ }
191
200
 
192
- //Transform the context into an object useful for the Split API, an key string with arbitrary Split 'Attributes'.
193
- private transformContext(context: EvaluationContext): Consumer {
194
- const { targetingKey, trafficType: ttVal, ...attributes } = context;
195
- const trafficType =
196
- ttVal != null && typeof ttVal === 'string' && ttVal.trim() !== ''
197
- ? ttVal
198
- : this.trafficType;
199
- return {
201
+ this.client.track(
200
202
  targetingKey,
201
203
  trafficType,
202
- // Stringify context objects include date.
203
- attributes: JSON.parse(JSON.stringify(attributes)),
204
- };
205
- }
206
-
207
- private parseValidNumber(stringValue: string | undefined) {
208
- if (stringValue === undefined) {
209
- throw new ParseError(`Invalid 'undefined' value.`);
210
- }
211
- const result = Number.parseFloat(stringValue);
212
- if (Number.isNaN(result)) {
213
- throw new ParseError(`Invalid numeric value ${stringValue}`);
214
- }
215
- return result;
216
- }
217
-
218
- private parseValidJsonObject<T extends JsonValue>(
219
- stringValue: string | undefined
220
- ): T {
221
- if (stringValue === undefined) {
222
- throw new ParseError(`Invalid 'undefined' JSON value.`);
223
- }
224
- // we may want to allow the parsing to be customized.
225
- try {
226
- const value = JSON.parse(stringValue);
227
- if (typeof value !== 'object') {
228
- throw new ParseError(
229
- `Flag value ${stringValue} had unexpected type ${typeof value}, expected "object"`
230
- );
231
- }
232
- return value;
233
- } catch (err) {
234
- throw new ParseError(`Error parsing ${stringValue} as JSON, ${err}`);
235
- }
204
+ trackingEventName,
205
+ value,
206
+ properties
207
+ );
236
208
  }
237
209
 
238
- private async readinessHandler(onSdkReady: (params?: unknown) => void, onSdkTimedOut: () => void): Promise<void> {
239
-
240
- const clientStatus = this.client.getStatus();
241
- if (clientStatus.isReady) {
242
- onSdkReady();
243
- } else {
244
- if (clientStatus.hasTimedout) {
245
- onSdkTimedOut();
246
- } else {
247
- this.client.on(this.client.Event.SDK_READY_TIMED_OUT, onSdkTimedOut);
248
- }
249
- this.client.on(this.client.Event.SDK_READY, onSdkReady);
250
- }
210
+ public async onClose?(): Promise<void> {
211
+ return this.client.destroy();
251
212
  }
252
213
  }
@@ -0,0 +1,32 @@
1
+ import { ParseError } from '@openfeature/server-sdk';
2
+ import type { JsonValue } from '@openfeature/server-sdk';
3
+
4
+ export function parseValidNumber(stringValue: string | undefined): number {
5
+ if (stringValue === undefined) {
6
+ throw new ParseError(`Invalid 'undefined' value.`);
7
+ }
8
+ const result = Number.parseFloat(stringValue);
9
+ if (Number.isNaN(result)) {
10
+ throw new ParseError(`Invalid numeric value ${stringValue}`);
11
+ }
12
+ return result;
13
+ }
14
+
15
+ export function parseValidJsonObject<T extends JsonValue>(
16
+ stringValue: string | undefined
17
+ ): T {
18
+ if (stringValue === undefined) {
19
+ throw new ParseError(`Invalid 'undefined' JSON value.`);
20
+ }
21
+ try {
22
+ const value = JSON.parse(stringValue);
23
+ if (typeof value !== 'object') {
24
+ throw new ParseError(
25
+ `Flag value ${stringValue} had unexpected type ${typeof value}, expected "object"`
26
+ );
27
+ }
28
+ return value;
29
+ } catch (err) {
30
+ throw new ParseError(`Error parsing ${stringValue} as JSON, ${err}`);
31
+ }
32
+ }
@@ -0,0 +1,103 @@
1
+ import type { OpenFeatureEventEmitter } from '@openfeature/server-sdk';
2
+ import { ProviderEvents } from '@openfeature/server-sdk';
3
+ import type SplitIO from '@splitsoftware/splitio/types/splitio';
4
+ import { PROVIDER_NAME } from './types';
5
+
6
+ /**
7
+ * Builds OpenFeature Ready event details including Split SDK ready metadata.
8
+ * Handles Split SDK not passing metadata (e.g. in consumer/Redis mode).
9
+ */
10
+ function buildReadyEventDetails(
11
+ providerName: string,
12
+ splitMetadata: SplitIO.SdkReadyMetadata | undefined,
13
+ readyFromCache: boolean
14
+ ) {
15
+ const metadata: Record<string, string | boolean | number> = {
16
+ readyFromCache,
17
+ initialCacheLoad: splitMetadata?.initialCacheLoad ?? false,
18
+ };
19
+ if (splitMetadata?.lastUpdateTimestamp != null) {
20
+ metadata.lastUpdateTimestamp = splitMetadata.lastUpdateTimestamp;
21
+ }
22
+ return {
23
+ providerName: providerName || PROVIDER_NAME,
24
+ metadata,
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Registers Split SDK_READY and SDK_READY_FROM_CACHE listeners and forwards them
30
+ * as OpenFeature ProviderEvents.Ready with event metadata (initialCacheLoad, lastUpdateTimestamp, readyFromCache).
31
+ * If the client is already ready when attaching (e.g. localhost or reused client), emits Ready once
32
+ * with best-effort metadata so handlers always receive at least one Ready when the client is ready.
33
+ */
34
+ export function attachReadyEventHandlers(
35
+ client: SplitIO.IClient | SplitIO.IAsyncClient,
36
+ events: OpenFeatureEventEmitter,
37
+ providerName: string = PROVIDER_NAME
38
+ ): void {
39
+ client.on(
40
+ client.Event.SDK_READY_FROM_CACHE,
41
+ (splitMetadata: SplitIO.SdkReadyMetadata) => {
42
+ events.emit(
43
+ ProviderEvents.Ready,
44
+ buildReadyEventDetails(providerName, splitMetadata, true)
45
+ );
46
+ }
47
+ );
48
+ client.on(client.Event.SDK_READY, (splitMetadata: SplitIO.SdkReadyMetadata) => {
49
+ events.emit(
50
+ ProviderEvents.Ready,
51
+ buildReadyEventDetails(providerName, splitMetadata, false)
52
+ );
53
+ });
54
+
55
+ const status = client.getStatus();
56
+ if (status.isReady) {
57
+ events.emit(
58
+ ProviderEvents.Ready,
59
+ buildReadyEventDetails(providerName, undefined, false)
60
+ );
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Returns a promise that resolves when the Split client is ready (SDK_READY),
66
+ * or rejects if the client has timed out (SDK_READY_TIMED_OUT).
67
+ * Used to gate evaluations until the SDK has synchronized with the backend.
68
+ */
69
+ export function waitUntilReady(
70
+ client: SplitIO.IClient | SplitIO.IAsyncClient,
71
+ events: OpenFeatureEventEmitter,
72
+ providerName: string = PROVIDER_NAME
73
+ ): Promise<void> {
74
+ return new Promise((resolve, reject) => {
75
+ const status = client.getStatus();
76
+ if (status.isReady) {
77
+ emitReadyEvent(client, events, providerName);
78
+ resolve();
79
+ return;
80
+ }
81
+ if (status.hasTimedout) {
82
+ reject();
83
+ return;
84
+ }
85
+ client.on(client.Event.SDK_READY_TIMED_OUT, reject);
86
+ client.on(client.Event.SDK_READY, () => {
87
+ emitReadyEvent(client, events, providerName);
88
+ resolve();
89
+ });
90
+ });
91
+ }
92
+
93
+ export function emitReadyEvent(
94
+ client: SplitIO.IClient | SplitIO.IAsyncClient,
95
+ events: OpenFeatureEventEmitter,
96
+ providerName: string = PROVIDER_NAME
97
+ ): void {
98
+ events.emit(
99
+ ProviderEvents.Ready,
100
+ buildReadyEventDetails(providerName, undefined, false)
101
+ );
102
+ }
103
+
@@ -0,0 +1,32 @@
1
+ import type SplitIO from '@splitsoftware/splitio/types/splitio';
2
+
3
+ /**
4
+ * Options when providing an existing Split client to the provider.
5
+ */
6
+ export type SplitProviderOptions = {
7
+ splitClient: SplitIO.IClient | SplitIO.IAsyncClient;
8
+ };
9
+
10
+ /**
11
+ * Consumer representation used for Split API calls:
12
+ * targeting key, traffic type, and attributes.
13
+ */
14
+ export type Consumer = {
15
+ targetingKey: string | undefined;
16
+ trafficType: string;
17
+ attributes: SplitIO.Attributes;
18
+ };
19
+
20
+ /**
21
+ * Union of all constructor argument types for the Split OpenFeature provider.
22
+ */
23
+ export type SplitProviderConstructorOptions =
24
+ | SplitProviderOptions
25
+ | string
26
+ | SplitIO.ISDK
27
+ | SplitIO.IAsyncSDK;
28
+
29
+ export const CONTROL_TREATMENT = 'control';
30
+ export const CONTROL_VALUE_ERROR_MESSAGE = 'Received the "control" value from Split.';
31
+ export const DEFAULT_TRAFFIC_TYPE = 'user';
32
+ export const PROVIDER_NAME = 'split';
@@ -0,0 +1,7 @@
1
+ import type SplitIO from '@splitsoftware/splitio/types/splitio';
2
+ import type { SplitProviderConstructorOptions } from './types';
3
+ /**
4
+ * Resolves the Split client from the various supported constructor option shapes.
5
+ * Supports: API key (string), Split SDK/AsyncSDK (factory), or pre-built splitClient.
6
+ */
7
+ export declare function getSplitClient(options: SplitProviderConstructorOptions): SplitIO.IClient | SplitIO.IAsyncClient;
@@ -0,0 +1,7 @@
1
+ import type { EvaluationContext } from '@openfeature/server-sdk';
2
+ import type { Consumer } from './types';
3
+ /**
4
+ * Transforms OpenFeature evaluation context into the consumer shape used by the Split API:
5
+ * targeting key, traffic type (with default), and remaining attributes.
6
+ */
7
+ export declare function transformContext(context: EvaluationContext, defaultTrafficType?: string): Consumer;
@@ -1,27 +1,24 @@
1
- import { EvaluationContext, JsonValue, OpenFeatureEventEmitter, Provider, ResolutionDetails, TrackingEventDetails } from '@openfeature/server-sdk';
2
- import type SplitIO from '@splitsoftware/splitio/types/splitio';
3
- type SplitProviderOptions = {
4
- splitClient: SplitIO.IClient | SplitIO.IAsyncClient;
5
- };
1
+ import { EvaluationContext, JsonValue, Logger, OpenFeatureEventEmitter, Provider, ResolutionDetails, TrackingEventDetails } from '@openfeature/server-sdk';
2
+ import { SplitProviderConstructorOptions } from './types';
6
3
  export declare class OpenFeatureSplitProvider implements Provider {
7
- metadata: {
8
- name: string;
4
+ readonly metadata: {
5
+ readonly name: "split";
9
6
  };
7
+ readonly runsOn: "server";
10
8
  private client;
11
9
  private trafficType;
12
10
  readonly events: OpenFeatureEventEmitter;
13
- private getSplitClient;
14
- constructor(options: SplitProviderOptions | string | SplitIO.ISDK | SplitIO.IAsyncSDK);
15
- resolveBooleanEvaluation(flagKey: string, _: boolean, context: EvaluationContext): Promise<ResolutionDetails<boolean>>;
16
- resolveStringEvaluation(flagKey: string, _: string, context: EvaluationContext): Promise<ResolutionDetails<string>>;
17
- resolveNumberEvaluation(flagKey: string, _: number, context: EvaluationContext): Promise<ResolutionDetails<number>>;
18
- resolveObjectEvaluation<U extends JsonValue>(flagKey: string, _: U, context: EvaluationContext): Promise<ResolutionDetails<U>>;
11
+ constructor(options: SplitProviderConstructorOptions);
12
+ /**
13
+ * Called by the SDK after the provider is set. Waits for the Split client to be ready.
14
+ * When this promise resolves, the SDK emits ProviderEvents.Ready.
15
+ */
16
+ initialize(_context?: EvaluationContext): Promise<void>;
17
+ resolveBooleanEvaluation(flagKey: string, _: boolean, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<boolean>>;
18
+ resolveStringEvaluation(flagKey: string, _: string, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<string>>;
19
+ resolveNumberEvaluation(flagKey: string, _: number, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<number>>;
20
+ resolveObjectEvaluation<U extends JsonValue>(flagKey: string, _: U, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<U>>;
19
21
  private evaluateTreatment;
20
22
  track(trackingEventName: string, context: EvaluationContext, details: TrackingEventDetails): Promise<void>;
21
23
  onClose?(): Promise<void>;
22
- private transformContext;
23
- private parseValidNumber;
24
- private parseValidJsonObject;
25
- private readinessHandler;
26
24
  }
27
- export {};
@@ -0,0 +1,3 @@
1
+ import type { JsonValue } from '@openfeature/server-sdk';
2
+ export declare function parseValidNumber(stringValue: string | undefined): number;
3
+ export declare function parseValidJsonObject<T extends JsonValue>(stringValue: string | undefined): T;
@@ -0,0 +1,16 @@
1
+ import type { OpenFeatureEventEmitter } from '@openfeature/server-sdk';
2
+ import type SplitIO from '@splitsoftware/splitio/types/splitio';
3
+ /**
4
+ * Registers Split SDK_READY and SDK_READY_FROM_CACHE listeners and forwards them
5
+ * as OpenFeature ProviderEvents.Ready with event metadata (initialCacheLoad, lastUpdateTimestamp, readyFromCache).
6
+ * If the client is already ready when attaching (e.g. localhost or reused client), emits Ready once
7
+ * with best-effort metadata so handlers always receive at least one Ready when the client is ready.
8
+ */
9
+ export declare function attachReadyEventHandlers(client: SplitIO.IClient | SplitIO.IAsyncClient, events: OpenFeatureEventEmitter, providerName?: string): void;
10
+ /**
11
+ * Returns a promise that resolves when the Split client is ready (SDK_READY),
12
+ * or rejects if the client has timed out (SDK_READY_TIMED_OUT).
13
+ * Used to gate evaluations until the SDK has synchronized with the backend.
14
+ */
15
+ export declare function waitUntilReady(client: SplitIO.IClient | SplitIO.IAsyncClient, events: OpenFeatureEventEmitter, providerName?: string): Promise<void>;
16
+ export declare function emitReadyEvent(client: SplitIO.IClient | SplitIO.IAsyncClient, events: OpenFeatureEventEmitter, providerName?: string): void;
@@ -0,0 +1,24 @@
1
+ import type SplitIO from '@splitsoftware/splitio/types/splitio';
2
+ /**
3
+ * Options when providing an existing Split client to the provider.
4
+ */
5
+ export type SplitProviderOptions = {
6
+ splitClient: SplitIO.IClient | SplitIO.IAsyncClient;
7
+ };
8
+ /**
9
+ * Consumer representation used for Split API calls:
10
+ * targeting key, traffic type, and attributes.
11
+ */
12
+ export type Consumer = {
13
+ targetingKey: string | undefined;
14
+ trafficType: string;
15
+ attributes: SplitIO.Attributes;
16
+ };
17
+ /**
18
+ * Union of all constructor argument types for the Split OpenFeature provider.
19
+ */
20
+ export type SplitProviderConstructorOptions = SplitProviderOptions | string | SplitIO.ISDK | SplitIO.IAsyncSDK;
21
+ export declare const CONTROL_TREATMENT = "control";
22
+ export declare const CONTROL_VALUE_ERROR_MESSAGE = "Received the \"control\" value from Split.";
23
+ export declare const DEFAULT_TRAFFIC_TYPE = "user";
24
+ export declare const PROVIDER_NAME = "split";