@openfeature/server-sdk 1.20.1 → 1.21.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.
package/dist/esm/index.js CHANGED
@@ -39,9 +39,7 @@ var __async = (__this, __arguments, generator) => {
39
39
  };
40
40
 
41
41
  // src/provider/provider.ts
42
- import {
43
- ServerProviderStatus
44
- } from "@openfeature/core";
42
+ import { ServerProviderStatus } from "@openfeature/core";
45
43
 
46
44
  // src/provider/no-op-provider.ts
47
45
  var REASON_NO_OP = "No-op";
@@ -169,9 +167,72 @@ var InMemoryProvider = class {
169
167
  });
170
168
  }
171
169
  };
170
+ var TypedInMemoryProvider = class extends InMemoryProvider {
171
+ constructor(flagConfiguration = {}) {
172
+ super(flagConfiguration);
173
+ }
174
+ /**
175
+ * Overwrites the configured flags.
176
+ * @param { FlagConfiguration } flagConfiguration new flag configuration
177
+ * @example
178
+ * ```
179
+ * provider.putConfiguration({
180
+ * 'my-flag': {
181
+ * variants: { on: true, off: false },
182
+ * defaultVariant: 'on',
183
+ * contextEvaluator: (ctx) => ctx?.user?.id === '123' ? 'on' : 'off',
184
+ * disabled: false,
185
+ * },
186
+ * });
187
+ *
188
+ * const flags = {
189
+ * 'my-flag': {
190
+ * variants: { on: true, off: false },
191
+ * defaultVariant: 'on',
192
+ * contextEvaluator: (ctx) => ctx?.user?.id === '123' ? 'on' : 'off',
193
+ * disabled: false,
194
+ * },
195
+ * } as const; // 'as const' needed to preserve the `defaultVariant` narrow literal type rather than `string`
196
+ * provider.putConfiguration(flags);
197
+ * ```
198
+ */
199
+ putConfiguration(flagConfiguration) {
200
+ super.putConfiguration(flagConfiguration);
201
+ }
202
+ };
172
203
 
173
204
  // src/provider/multi-provider/multi-provider.ts
174
- import { DefaultLogger, ErrorCode as ErrorCode3, GeneralError as GeneralError4, StandardResolutionReasons as StandardResolutionReasons2 } from "@openfeature/core";
205
+ import {
206
+ DefaultLogger,
207
+ ErrorCode as ErrorCode2,
208
+ GeneralError as GeneralError2,
209
+ StandardResolutionReasons as StandardResolutionReasons2,
210
+ constructAggregateError,
211
+ throwAggregateErrorFromPromiseResults,
212
+ StatusTracker
213
+ } from "@openfeature/core";
214
+
215
+ // src/provider/multi-provider/strategies.ts
216
+ import {
217
+ BaseFirstMatchStrategy,
218
+ BaseFirstSuccessfulStrategy,
219
+ BaseComparisonStrategy
220
+ } from "@openfeature/core";
221
+ var FirstMatchStrategy = class extends BaseFirstMatchStrategy {
222
+ constructor() {
223
+ super(ServerProviderStatus);
224
+ }
225
+ };
226
+ var FirstSuccessfulStrategy = class extends BaseFirstSuccessfulStrategy {
227
+ constructor() {
228
+ super(ServerProviderStatus);
229
+ }
230
+ };
231
+ var ComparisonStrategy = class extends BaseComparisonStrategy {
232
+ constructor(fallbackProvider, onMismatch) {
233
+ super(ServerProviderStatus, fallbackProvider, onMismatch);
234
+ }
235
+ };
175
236
 
176
237
  // src/events/open-feature-event-emitter.ts
177
238
  import { GenericEventEmitter } from "@openfeature/core";
@@ -187,40 +248,8 @@ var OpenFeatureEventEmitter = class extends GenericEventEmitter {
187
248
  }
188
249
  };
189
250
 
190
- // src/provider/multi-provider/errors.ts
191
- import { GeneralError as GeneralError2, OpenFeatureError as OpenFeatureError3 } from "@openfeature/core";
192
- var ErrorWithCode = class extends OpenFeatureError3 {
193
- constructor(code, message) {
194
- super(message);
195
- this.code = code;
196
- }
197
- };
198
- var AggregateError = class extends GeneralError2 {
199
- constructor(message, originalErrors) {
200
- super(message);
201
- this.originalErrors = originalErrors;
202
- }
203
- };
204
- var constructAggregateError = (providerErrors) => {
205
- const errorsWithSource = providerErrors.map(({ providerName, error }) => {
206
- return { source: providerName, error };
207
- }).flat();
208
- return new AggregateError(
209
- `Provider errors occurred: ${errorsWithSource[0].source}: ${errorsWithSource[0].error}`,
210
- errorsWithSource
211
- );
212
- };
213
- var throwAggregateErrorFromPromiseResults = (result, providerEntries) => {
214
- const errors = result.map((r, i) => {
215
- if (r.status === "rejected") {
216
- return { error: r.reason, providerName: providerEntries[i].name };
217
- }
218
- return null;
219
- }).filter((val) => Boolean(val));
220
- if (errors.length) {
221
- throw constructAggregateError(errors);
222
- }
223
- };
251
+ // src/events/events.ts
252
+ import { ServerProviderEvents } from "@openfeature/core";
224
253
 
225
254
  // src/provider/multi-provider/hook-executor.ts
226
255
  var HookExecutor = class {
@@ -279,193 +308,6 @@ var HookExecutor = class {
279
308
  }
280
309
  };
281
310
 
282
- // src/events/events.ts
283
- import { ServerProviderEvents } from "@openfeature/core";
284
-
285
- // src/provider/multi-provider/status-tracker.ts
286
- var StatusTracker = class {
287
- constructor(events) {
288
- this.events = events;
289
- this.providerStatuses = {};
290
- }
291
- wrapEventHandler(providerEntry) {
292
- var _a, _b, _c, _d;
293
- const provider = providerEntry.provider;
294
- (_a = provider.events) == null ? void 0 : _a.addHandler(ServerProviderEvents.Error, (details) => {
295
- this.changeProviderStatus(providerEntry.name, ServerProviderStatus.ERROR, details);
296
- });
297
- (_b = provider.events) == null ? void 0 : _b.addHandler(ServerProviderEvents.Stale, (details) => {
298
- this.changeProviderStatus(providerEntry.name, ServerProviderStatus.STALE, details);
299
- });
300
- (_c = provider.events) == null ? void 0 : _c.addHandler(ServerProviderEvents.ConfigurationChanged, (details) => {
301
- this.events.emit(ServerProviderEvents.ConfigurationChanged, details);
302
- });
303
- (_d = provider.events) == null ? void 0 : _d.addHandler(ServerProviderEvents.Ready, (details) => {
304
- this.changeProviderStatus(providerEntry.name, ServerProviderStatus.READY, details);
305
- });
306
- }
307
- providerStatus(name) {
308
- return this.providerStatuses[name];
309
- }
310
- getStatusFromProviderStatuses() {
311
- const statuses = Object.values(this.providerStatuses);
312
- if (statuses.includes(ServerProviderStatus.FATAL)) {
313
- return ServerProviderStatus.FATAL;
314
- } else if (statuses.includes(ServerProviderStatus.NOT_READY)) {
315
- return ServerProviderStatus.NOT_READY;
316
- } else if (statuses.includes(ServerProviderStatus.ERROR)) {
317
- return ServerProviderStatus.ERROR;
318
- } else if (statuses.includes(ServerProviderStatus.STALE)) {
319
- return ServerProviderStatus.STALE;
320
- }
321
- return ServerProviderStatus.READY;
322
- }
323
- changeProviderStatus(name, status, details) {
324
- const currentStatus = this.getStatusFromProviderStatuses();
325
- this.providerStatuses[name] = status;
326
- const newStatus = this.getStatusFromProviderStatuses();
327
- if (currentStatus !== newStatus) {
328
- if (newStatus === ServerProviderStatus.FATAL || newStatus === ServerProviderStatus.ERROR) {
329
- this.events.emit(ServerProviderEvents.Error, details);
330
- } else if (newStatus === ServerProviderStatus.STALE) {
331
- this.events.emit(ServerProviderEvents.Stale, details);
332
- } else if (newStatus === ServerProviderStatus.READY) {
333
- this.events.emit(ServerProviderEvents.Ready, details);
334
- }
335
- }
336
- }
337
- };
338
-
339
- // src/provider/multi-provider/strategies/base-evaluation-strategy.ts
340
- var BaseEvaluationStrategy = class {
341
- constructor() {
342
- this.runMode = "sequential";
343
- }
344
- shouldEvaluateThisProvider(strategyContext, _evalContext) {
345
- if (strategyContext.providerStatus === ServerProviderStatus.NOT_READY || strategyContext.providerStatus === ServerProviderStatus.FATAL) {
346
- return false;
347
- }
348
- return true;
349
- }
350
- shouldEvaluateNextProvider(_strategyContext, _context, _result) {
351
- return true;
352
- }
353
- shouldTrackWithThisProvider(strategyContext, _context, _trackingEventName, _trackingEventDetails) {
354
- if (strategyContext.providerStatus === ServerProviderStatus.NOT_READY || strategyContext.providerStatus === ServerProviderStatus.FATAL) {
355
- return false;
356
- }
357
- return true;
358
- }
359
- hasError(resolution) {
360
- return "thrownError" in resolution || !!resolution.details.errorCode;
361
- }
362
- hasErrorWithCode(resolution, code) {
363
- var _a;
364
- return "thrownError" in resolution ? ((_a = resolution.thrownError) == null ? void 0 : _a.code) === code : resolution.details.errorCode === code;
365
- }
366
- collectProviderErrors(resolutions) {
367
- var _a;
368
- const errors = [];
369
- for (const resolution of resolutions) {
370
- if ("thrownError" in resolution) {
371
- errors.push({ providerName: resolution.providerName, error: resolution.thrownError });
372
- } else if (resolution.details.errorCode) {
373
- errors.push({
374
- providerName: resolution.providerName,
375
- error: new ErrorWithCode(resolution.details.errorCode, (_a = resolution.details.errorMessage) != null ? _a : "unknown error")
376
- });
377
- }
378
- }
379
- return { errors };
380
- }
381
- resolutionToFinalResult(resolution) {
382
- return { details: resolution.details, provider: resolution.provider, providerName: resolution.providerName };
383
- }
384
- };
385
-
386
- // src/provider/multi-provider/strategies/first-match-strategy.ts
387
- import { ErrorCode as ErrorCode2 } from "@openfeature/core";
388
- var FirstMatchStrategy = class extends BaseEvaluationStrategy {
389
- shouldEvaluateNextProvider(strategyContext, context, result) {
390
- if (this.hasErrorWithCode(result, ErrorCode2.FLAG_NOT_FOUND)) {
391
- return true;
392
- }
393
- if (this.hasError(result)) {
394
- return false;
395
- }
396
- return false;
397
- }
398
- determineFinalResult(strategyContext, context, resolutions) {
399
- const finalResolution = resolutions[resolutions.length - 1];
400
- if (this.hasError(finalResolution)) {
401
- return this.collectProviderErrors(resolutions);
402
- }
403
- return this.resolutionToFinalResult(finalResolution);
404
- }
405
- };
406
-
407
- // src/provider/multi-provider/strategies/first-successful-strategy.ts
408
- var FirstSuccessfulStrategy = class extends BaseEvaluationStrategy {
409
- shouldEvaluateNextProvider(strategyContext, context, result) {
410
- return this.hasError(result);
411
- }
412
- determineFinalResult(strategyContext, context, resolutions) {
413
- const finalResolution = resolutions[resolutions.length - 1];
414
- if (this.hasError(finalResolution)) {
415
- return this.collectProviderErrors(resolutions);
416
- }
417
- return this.resolutionToFinalResult(finalResolution);
418
- }
419
- };
420
-
421
- // src/provider/multi-provider/strategies/comparison-strategy.ts
422
- import { GeneralError as GeneralError3 } from "@openfeature/core";
423
- var ComparisonStrategy = class extends BaseEvaluationStrategy {
424
- constructor(fallbackProvider, onMismatch) {
425
- super();
426
- this.fallbackProvider = fallbackProvider;
427
- this.onMismatch = onMismatch;
428
- this.runMode = "parallel";
429
- }
430
- determineFinalResult(strategyContext, context, resolutions) {
431
- var _a;
432
- let value;
433
- let fallbackResolution;
434
- let finalResolution;
435
- let mismatch = false;
436
- for (const [i, resolution] of resolutions.entries()) {
437
- if (this.hasError(resolution)) {
438
- return this.collectProviderErrors(resolutions);
439
- }
440
- if (resolution.provider === this.fallbackProvider) {
441
- fallbackResolution = resolution;
442
- }
443
- if (i === 0) {
444
- finalResolution = resolution;
445
- }
446
- if (typeof value !== "undefined" && value !== resolution.details.value) {
447
- mismatch = true;
448
- } else {
449
- value = resolution.details.value;
450
- }
451
- }
452
- if (!fallbackResolution) {
453
- throw new GeneralError3("Fallback provider not found in resolution results");
454
- }
455
- if (!finalResolution) {
456
- throw new GeneralError3("Final resolution not found in resolution results");
457
- }
458
- if (mismatch) {
459
- (_a = this.onMismatch) == null ? void 0 : _a.call(this, resolutions);
460
- return {
461
- details: fallbackResolution.details,
462
- provider: fallbackResolution.provider
463
- };
464
- }
465
- return this.resolutionToFinalResult(finalResolution);
466
- }
467
- };
468
-
469
311
  // src/provider/multi-provider/multi-provider.ts
470
312
  var MultiProvider = class _MultiProvider {
471
313
  constructor(constructorProviders, evaluationStrategy = new FirstMatchStrategy(), logger = new DefaultLogger()) {
@@ -478,7 +320,7 @@ var MultiProvider = class _MultiProvider {
478
320
  this.hookHints = /* @__PURE__ */ new WeakMap();
479
321
  this.providerEntries = [];
480
322
  this.providerEntriesByName = {};
481
- this.statusTracker = new StatusTracker(this.events);
323
+ this.statusTracker = new StatusTracker(this.events, ServerProviderStatus, ServerProviderEvents);
482
324
  this.hookExecutor = new HookExecutor(this.logger);
483
325
  this.registerProviders(constructorProviders);
484
326
  const aggregateMetadata = Object.keys(this.providerEntriesByName).reduce((acc, name) => {
@@ -550,7 +392,7 @@ var MultiProvider = class _MultiProvider {
550
392
  const hookContext = this.hookContexts.get(context);
551
393
  const hookHints = this.hookHints.get(context);
552
394
  if (!hookContext || !hookHints) {
553
- throw new GeneralError4("Hook context not available for evaluation");
395
+ throw new GeneralError2("Hook context not available for evaluation");
554
396
  }
555
397
  const tasks = [];
556
398
  for (const providerEntry of this.providerEntries) {
@@ -578,7 +420,7 @@ var MultiProvider = class _MultiProvider {
578
420
  throw constructAggregateError(finalResult.errors);
579
421
  }
580
422
  if (!finalResult.details) {
581
- throw new GeneralError4("No result was returned from any provider");
423
+ throw new GeneralError2("No result was returned from any provider");
582
424
  }
583
425
  return finalResult.details;
584
426
  });
@@ -657,7 +499,7 @@ var MultiProvider = class _MultiProvider {
657
499
  case "boolean":
658
500
  return yield provider.resolveBooleanEvaluation(flagKey, defaultValue, context, this.logger);
659
501
  default:
660
- throw new GeneralError4("Invalid flag evaluation type");
502
+ throw new GeneralError2("Invalid flag evaluation type");
661
503
  }
662
504
  });
663
505
  }
@@ -702,7 +544,7 @@ var MultiProvider = class _MultiProvider {
702
544
  }
703
545
  getErrorEvaluationDetails(flagKey, defaultValue, err, flagMetadata = {}) {
704
546
  const errorMessage = err == null ? void 0 : err.message;
705
- const errorCode = (err == null ? void 0 : err.code) || ErrorCode3.GENERAL;
547
+ const errorCode = (err == null ? void 0 : err.code) || ErrorCode2.GENERAL;
706
548
  return {
707
549
  errorCode,
708
550
  errorMessage,
@@ -715,16 +557,11 @@ var MultiProvider = class _MultiProvider {
715
557
  };
716
558
 
717
559
  // src/open-feature.ts
718
- import {
719
- OpenFeatureCommonAPI,
720
- ProviderWrapper,
721
- objectOrUndefined,
722
- stringOrUndefined
723
- } from "@openfeature/core";
560
+ import { OpenFeatureCommonAPI, ProviderWrapper, objectOrUndefined, stringOrUndefined } from "@openfeature/core";
724
561
 
725
562
  // src/client/internal/open-feature-client.ts
726
563
  import {
727
- ErrorCode as ErrorCode4,
564
+ ErrorCode as ErrorCode3,
728
565
  ProviderFatalError,
729
566
  ProviderNotReadyError,
730
567
  SafeLogger,
@@ -936,9 +773,7 @@ var OpenFeatureClient = class {
936
773
  const hookResult = yield (_a = hook == null ? void 0 : hook.before) == null ? void 0 : _a.call(hook, hookContext, Object.freeze(options.hookHints));
937
774
  if (hookResult) {
938
775
  Object.assign(accumulatedContext, hookResult);
939
- for (let i = 0; i < hooks.length; i++) {
940
- Object.assign(hookContexts[hookContextIndex].context, accumulatedContext);
941
- }
776
+ Object.assign(hookContext.context, accumulatedContext);
942
777
  }
943
778
  }
944
779
  return Object.freeze(accumulatedContext);
@@ -1008,7 +843,7 @@ var OpenFeatureClient = class {
1008
843
  }
1009
844
  getErrorEvaluationDetails(flagKey, defaultValue, err, flagMetadata = {}) {
1010
845
  const errorMessage = err == null ? void 0 : err.message;
1011
- const errorCode = (err == null ? void 0 : err.code) || ErrorCode4.GENERAL;
846
+ const errorCode = (err == null ? void 0 : err.code) || ErrorCode3.GENERAL;
1012
847
  return {
1013
848
  errorCode,
1014
849
  errorMessage,
@@ -1164,11 +999,8 @@ var OpenFeature = OpenFeatureAPI.getInstance();
1164
999
  // src/index.ts
1165
1000
  export * from "@openfeature/core";
1166
1001
  export {
1167
- AggregateError,
1168
1002
  AsyncLocalStorageTransactionContextPropagator,
1169
- BaseEvaluationStrategy,
1170
1003
  ComparisonStrategy,
1171
- ErrorWithCode,
1172
1004
  FirstMatchStrategy,
1173
1005
  FirstSuccessfulStrategy,
1174
1006
  InMemoryProvider,
@@ -1180,7 +1012,6 @@ export {
1180
1012
  OpenFeatureEventEmitter,
1181
1013
  ServerProviderEvents as ProviderEvents,
1182
1014
  ServerProviderStatus as ProviderStatus,
1183
- constructAggregateError,
1184
- throwAggregateErrorFromPromiseResults
1015
+ TypedInMemoryProvider
1185
1016
  };
1186
1017
  //# sourceMappingURL=index.js.map