@openfeature/web-sdk 0.4.10 → 0.4.12
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/README.md +23 -14
- package/dist/cjs/index.js +135 -194
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +135 -194
- package/dist/esm/index.js.map +1 -1
- package/dist/types.d.ts +4 -637
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.7.0&color=yellow&style=for-the-badge" />
|
|
17
17
|
</a>
|
|
18
18
|
<!-- x-release-please-start-version -->
|
|
19
|
-
<a href="https://github.com/open-feature/js-sdk/releases/tag/web-sdk-v0.4.
|
|
20
|
-
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.4.
|
|
19
|
+
<a href="https://github.com/open-feature/js-sdk/releases/tag/web-sdk-v0.4.12">
|
|
20
|
+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.4.12&color=blue&style=for-the-badge" />
|
|
21
21
|
</a>
|
|
22
22
|
<!-- x-release-please-end -->
|
|
23
23
|
<br/>
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
|
|
48
48
|
### Requirements
|
|
49
49
|
|
|
50
|
-
-
|
|
50
|
+
- ES2022-compatible web browser (Chrome, Edge, Firefox, etc)
|
|
51
51
|
|
|
52
52
|
### Install
|
|
53
53
|
|
|
@@ -267,43 +267,52 @@ This can be a new repository or included in [the existing contrib repository](ht
|
|
|
267
267
|
You’ll then need to write the provider by implementing the [Provider interface](./src/provider/provider.ts) exported by the OpenFeature SDK.
|
|
268
268
|
|
|
269
269
|
```ts
|
|
270
|
-
import {
|
|
270
|
+
import {
|
|
271
|
+
AnyProviderEvent,
|
|
272
|
+
EvaluationContext,
|
|
273
|
+
Hook,
|
|
274
|
+
JsonValue,
|
|
275
|
+
Logger,
|
|
276
|
+
Provider,
|
|
277
|
+
ProviderEventEmitter,
|
|
278
|
+
ProviderStatus,
|
|
279
|
+
ResolutionDetails
|
|
280
|
+
} from '@openfeature/web-sdk';
|
|
271
281
|
|
|
272
282
|
// implement the provider interface
|
|
273
283
|
class MyProvider implements Provider {
|
|
274
284
|
// Adds runtime validation that the provider is used with the expected SDK
|
|
275
|
-
public readonly runsOn = '
|
|
276
|
-
|
|
285
|
+
public readonly runsOn = 'server';
|
|
277
286
|
readonly metadata = {
|
|
278
287
|
name: 'My Provider',
|
|
279
288
|
} as const;
|
|
280
|
-
|
|
281
289
|
// Optional provider managed hooks
|
|
282
|
-
hooks?: Hook
|
|
283
|
-
|
|
290
|
+
hooks?: Hook[];
|
|
284
291
|
resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext, logger: Logger): ResolutionDetails<boolean> {
|
|
285
292
|
// code to evaluate a boolean
|
|
286
293
|
}
|
|
287
|
-
|
|
288
294
|
resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext, logger: Logger): ResolutionDetails<string> {
|
|
289
295
|
// code to evaluate a string
|
|
290
296
|
}
|
|
291
|
-
|
|
292
297
|
resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext, logger: Logger): ResolutionDetails<number> {
|
|
293
298
|
// code to evaluate a number
|
|
294
299
|
}
|
|
295
|
-
|
|
296
300
|
resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext, logger: Logger): ResolutionDetails<T> {
|
|
297
301
|
// code to evaluate an object
|
|
298
302
|
}
|
|
299
303
|
|
|
304
|
+
onContextChange?(oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void> {
|
|
305
|
+
// reconcile the provider's cached flags, if applicable
|
|
306
|
+
}
|
|
307
|
+
|
|
300
308
|
status?: ProviderStatus | undefined;
|
|
301
|
-
|
|
309
|
+
|
|
310
|
+
// implement with "new OpenFeatureEventEmitter()", and use "emit()" to emit events
|
|
311
|
+
events?: ProviderEventEmitter<AnyProviderEvent> | undefined;
|
|
302
312
|
|
|
303
313
|
initialize?(context?: EvaluationContext | undefined): Promise<void> {
|
|
304
314
|
// code to initialize your provider
|
|
305
315
|
}
|
|
306
|
-
|
|
307
316
|
onClose?(): Promise<void> {
|
|
308
317
|
// code to shut down your provider
|
|
309
318
|
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,28 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __create = Object.create;
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
|
-
var __defProps = Object.defineProperties;
|
|
5
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
7
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
9
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
10
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
-
var __reflectGet = Reflect.get;
|
|
13
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
14
|
-
var __spreadValues = (a, b) => {
|
|
15
|
-
for (var prop in b || (b = {}))
|
|
16
|
-
if (__hasOwnProp.call(b, prop))
|
|
17
|
-
__defNormalProp(a, prop, b[prop]);
|
|
18
|
-
if (__getOwnPropSymbols)
|
|
19
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
20
|
-
if (__propIsEnum.call(b, prop))
|
|
21
|
-
__defNormalProp(a, prop, b[prop]);
|
|
22
|
-
}
|
|
23
|
-
return a;
|
|
24
|
-
};
|
|
25
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
26
8
|
var __commonJS = (cb, mod) => function __require() {
|
|
27
9
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
28
10
|
};
|
|
@@ -48,27 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
48
30
|
mod
|
|
49
31
|
));
|
|
50
32
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
51
|
-
var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
|
|
52
|
-
var __async = (__this, __arguments, generator) => {
|
|
53
|
-
return new Promise((resolve, reject) => {
|
|
54
|
-
var fulfilled = (value) => {
|
|
55
|
-
try {
|
|
56
|
-
step(generator.next(value));
|
|
57
|
-
} catch (e) {
|
|
58
|
-
reject(e);
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
var rejected = (value) => {
|
|
62
|
-
try {
|
|
63
|
-
step(generator.throw(value));
|
|
64
|
-
} catch (e) {
|
|
65
|
-
reject(e);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
69
|
-
step((generator = generator.apply(__this, __arguments)).next());
|
|
70
|
-
});
|
|
71
|
-
};
|
|
72
33
|
|
|
73
34
|
// ../../node_modules/events/events.js
|
|
74
35
|
var require_events = __commonJS({
|
|
@@ -465,12 +426,11 @@ var import_core6 = require("@openfeature/core");
|
|
|
465
426
|
var import_core = require("@openfeature/core");
|
|
466
427
|
var import_events = __toESM(require_events());
|
|
467
428
|
var OpenFeatureEventEmitter = class extends import_core.GenericEventEmitter {
|
|
429
|
+
eventEmitter = new import_events.default({ captureRejections: true });
|
|
468
430
|
constructor() {
|
|
469
431
|
super();
|
|
470
|
-
this.eventEmitter = new import_events.default({ captureRejections: true });
|
|
471
432
|
this.eventEmitter.on("error", (err) => {
|
|
472
|
-
|
|
473
|
-
(_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
|
|
433
|
+
this._logger?.error("Error running event handler:", err);
|
|
474
434
|
});
|
|
475
435
|
}
|
|
476
436
|
};
|
|
@@ -482,11 +442,9 @@ var import_core2 = require("@openfeature/core");
|
|
|
482
442
|
var import_core3 = require("@openfeature/core");
|
|
483
443
|
var REASON_NO_OP = "No-op";
|
|
484
444
|
var NoopFeatureProvider = class {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
};
|
|
489
|
-
}
|
|
445
|
+
metadata = {
|
|
446
|
+
name: "No-op Provider"
|
|
447
|
+
};
|
|
490
448
|
get status() {
|
|
491
449
|
return import_core3.ProviderStatus.NOT_READY;
|
|
492
450
|
}
|
|
@@ -517,6 +475,7 @@ var import_core5 = require("@openfeature/core");
|
|
|
517
475
|
// src/provider/in-memory-provider/variant-not-found-error.ts
|
|
518
476
|
var import_core4 = require("@openfeature/core");
|
|
519
477
|
var VariantNotFoundError = class extends import_core4.OpenFeatureError {
|
|
478
|
+
code;
|
|
520
479
|
constructor(message) {
|
|
521
480
|
super(message);
|
|
522
481
|
Object.setPrototypeOf(this, VariantNotFoundError.prototype);
|
|
@@ -527,48 +486,46 @@ var VariantNotFoundError = class extends import_core4.OpenFeatureError {
|
|
|
527
486
|
|
|
528
487
|
// src/provider/in-memory-provider/in-memory-provider.ts
|
|
529
488
|
var InMemoryProvider = class {
|
|
489
|
+
events = new OpenFeatureEventEmitter();
|
|
490
|
+
runsOn = "client";
|
|
491
|
+
status = import_core5.ProviderStatus.NOT_READY;
|
|
492
|
+
metadata = {
|
|
493
|
+
name: "in-memory"
|
|
494
|
+
};
|
|
495
|
+
_flagConfiguration;
|
|
496
|
+
_context;
|
|
530
497
|
constructor(flagConfiguration = {}) {
|
|
531
|
-
this.
|
|
532
|
-
this.runsOn = "client";
|
|
533
|
-
this.status = import_core5.ProviderStatus.NOT_READY;
|
|
534
|
-
this.metadata = {
|
|
535
|
-
name: "in-memory"
|
|
536
|
-
};
|
|
537
|
-
this._flagConfiguration = __spreadValues({}, flagConfiguration);
|
|
498
|
+
this._flagConfiguration = { ...flagConfiguration };
|
|
538
499
|
}
|
|
539
|
-
initialize(context) {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
this.resolveFlagWithReason(key, context);
|
|
544
|
-
}
|
|
545
|
-
this._context = context;
|
|
546
|
-
this.status = import_core5.ProviderStatus.READY;
|
|
547
|
-
} catch (error) {
|
|
548
|
-
this.status = import_core5.ProviderStatus.ERROR;
|
|
549
|
-
throw error;
|
|
500
|
+
async initialize(context) {
|
|
501
|
+
try {
|
|
502
|
+
for (const key in this._flagConfiguration) {
|
|
503
|
+
this.resolveFlagWithReason(key, context);
|
|
550
504
|
}
|
|
551
|
-
|
|
505
|
+
this._context = context;
|
|
506
|
+
this.status = import_core5.ProviderStatus.READY;
|
|
507
|
+
} catch (error) {
|
|
508
|
+
this.status = import_core5.ProviderStatus.ERROR;
|
|
509
|
+
throw error;
|
|
510
|
+
}
|
|
552
511
|
}
|
|
553
512
|
/**
|
|
554
513
|
* Overwrites the configured flags.
|
|
555
514
|
* @param { FlagConfiguration } flagConfiguration new flag configuration
|
|
556
515
|
*/
|
|
557
|
-
putConfiguration(flagConfiguration) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
}
|
|
571
|
-
});
|
|
516
|
+
async putConfiguration(flagConfiguration) {
|
|
517
|
+
const flagsChanged = Object.entries(flagConfiguration).filter(([key, value]) => this._flagConfiguration[key] !== value).map(([key]) => key);
|
|
518
|
+
this.status = import_core5.ProviderStatus.STALE;
|
|
519
|
+
this.events.emit(import_core2.ClientProviderEvents.Stale);
|
|
520
|
+
this._flagConfiguration = { ...flagConfiguration };
|
|
521
|
+
this.events.emit(import_core2.ClientProviderEvents.ConfigurationChanged, { flagsChanged });
|
|
522
|
+
try {
|
|
523
|
+
await this.initialize(this._context);
|
|
524
|
+
this.events.emit(import_core2.ClientProviderEvents.Ready);
|
|
525
|
+
} catch (err) {
|
|
526
|
+
this.events.emit(import_core2.ClientProviderEvents.Error);
|
|
527
|
+
throw err;
|
|
528
|
+
}
|
|
572
529
|
}
|
|
573
530
|
resolveBooleanEvaluation(flagKey, defaultValue, context, logger) {
|
|
574
531
|
return this.resolveAndCheckFlag(flagKey, defaultValue, context || this._context, logger);
|
|
@@ -585,7 +542,7 @@ var InMemoryProvider = class {
|
|
|
585
542
|
resolveAndCheckFlag(flagKey, defaultValue, context, logger) {
|
|
586
543
|
if (!(flagKey in this._flagConfiguration)) {
|
|
587
544
|
const message = `no flag found with key ${flagKey}`;
|
|
588
|
-
logger
|
|
545
|
+
logger?.debug(message);
|
|
589
546
|
throw new import_core5.FlagNotFoundError(message);
|
|
590
547
|
}
|
|
591
548
|
if (this._flagConfiguration[flagKey].disabled) {
|
|
@@ -594,7 +551,7 @@ var InMemoryProvider = class {
|
|
|
594
551
|
const resolvedFlag = this.resolveFlagWithReason(flagKey, context);
|
|
595
552
|
if (resolvedFlag.value === void 0) {
|
|
596
553
|
const message = `no value associated with variant provided for ${flagKey} found`;
|
|
597
|
-
logger
|
|
554
|
+
logger?.error(message);
|
|
598
555
|
throw new VariantNotFoundError(message);
|
|
599
556
|
}
|
|
600
557
|
if (typeof resolvedFlag.value != typeof defaultValue) {
|
|
@@ -608,24 +565,23 @@ var InMemoryProvider = class {
|
|
|
608
565
|
return resolutionResult;
|
|
609
566
|
} catch (error) {
|
|
610
567
|
if (!(error instanceof import_core5.OpenFeatureError)) {
|
|
611
|
-
throw new import_core5.GeneralError(
|
|
568
|
+
throw new import_core5.GeneralError(error?.message || "unknown error");
|
|
612
569
|
}
|
|
613
570
|
throw error;
|
|
614
571
|
}
|
|
615
572
|
}
|
|
616
573
|
lookupFlagValue(flagKey, ctx) {
|
|
617
|
-
var _a;
|
|
618
574
|
const flagSpec = this._flagConfiguration[flagKey];
|
|
619
|
-
const isContextEval = ctx &&
|
|
620
|
-
const variant = isContextEval ?
|
|
621
|
-
const value = variant &&
|
|
575
|
+
const isContextEval = ctx && flagSpec?.contextEvaluator;
|
|
576
|
+
const variant = isContextEval ? flagSpec.contextEvaluator?.(ctx) : flagSpec.defaultVariant;
|
|
577
|
+
const value = variant && flagSpec?.variants[variant];
|
|
622
578
|
const evalReason = isContextEval ? import_core5.StandardResolutionReasons.TARGETING_MATCH : import_core5.StandardResolutionReasons.STATIC;
|
|
623
579
|
const reason = this.status === import_core5.ProviderStatus.STALE ? import_core5.StandardResolutionReasons.CACHED : evalReason;
|
|
624
|
-
return
|
|
625
|
-
value
|
|
626
|
-
|
|
580
|
+
return {
|
|
581
|
+
value,
|
|
582
|
+
...variant && { variant },
|
|
627
583
|
reason
|
|
628
|
-
}
|
|
584
|
+
};
|
|
629
585
|
}
|
|
630
586
|
};
|
|
631
587
|
|
|
@@ -633,12 +589,12 @@ var InMemoryProvider = class {
|
|
|
633
589
|
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/web-sdk/api");
|
|
634
590
|
var _globalThis = globalThis;
|
|
635
591
|
var OpenFeatureAPI = class extends import_core6.OpenFeatureCommonAPI {
|
|
592
|
+
_events = new OpenFeatureEventEmitter();
|
|
593
|
+
_defaultProvider = NOOP_PROVIDER;
|
|
594
|
+
_createEventEmitter = () => new OpenFeatureEventEmitter();
|
|
595
|
+
_namedProviderContext = /* @__PURE__ */ new Map();
|
|
636
596
|
constructor() {
|
|
637
597
|
super("client");
|
|
638
|
-
this._events = new OpenFeatureEventEmitter();
|
|
639
|
-
this._defaultProvider = NOOP_PROVIDER;
|
|
640
|
-
this._createEventEmitter = () => new OpenFeatureEventEmitter();
|
|
641
|
-
this._namedProviderContext = /* @__PURE__ */ new Map();
|
|
642
598
|
}
|
|
643
599
|
/**
|
|
644
600
|
* Gets a singleton instance of the OpenFeature API.
|
|
@@ -654,39 +610,36 @@ var OpenFeatureAPI = class extends import_core6.OpenFeatureCommonAPI {
|
|
|
654
610
|
_globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;
|
|
655
611
|
return instance;
|
|
656
612
|
}
|
|
657
|
-
setContext(nameOrContext, contextOrUndefined) {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
const
|
|
662
|
-
if (
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
this._namedProviderContext.set(clientName, context);
|
|
667
|
-
yield this.runProviderContextChangeHandler(clientName, provider, oldContext, context);
|
|
668
|
-
} else {
|
|
669
|
-
this._namedProviderContext.set(clientName, context);
|
|
670
|
-
}
|
|
613
|
+
async setContext(nameOrContext, contextOrUndefined) {
|
|
614
|
+
const clientName = (0, import_core6.stringOrUndefined)(nameOrContext);
|
|
615
|
+
const context = (0, import_core6.objectOrUndefined)(nameOrContext) ?? (0, import_core6.objectOrUndefined)(contextOrUndefined) ?? {};
|
|
616
|
+
if (clientName) {
|
|
617
|
+
const provider = this._clientProviders.get(clientName);
|
|
618
|
+
if (provider) {
|
|
619
|
+
const oldContext = this.getContext(clientName);
|
|
620
|
+
this._namedProviderContext.set(clientName, context);
|
|
621
|
+
await this.runProviderContextChangeHandler(clientName, provider, oldContext, context);
|
|
671
622
|
} else {
|
|
672
|
-
|
|
673
|
-
this._context = context;
|
|
674
|
-
const defaultContextNameProviders = Array.from(this._clientProviders.entries()).filter(([name]) => !this._namedProviderContext.has(name)).reduce((acc, [name, provider]) => {
|
|
675
|
-
acc.push({ name, provider });
|
|
676
|
-
return acc;
|
|
677
|
-
}, []);
|
|
678
|
-
const allProviders = [
|
|
679
|
-
// add in the default (no name)
|
|
680
|
-
{ name: void 0, provider: this._defaultProvider },
|
|
681
|
-
...defaultContextNameProviders
|
|
682
|
-
];
|
|
683
|
-
yield Promise.all(
|
|
684
|
-
allProviders.map(
|
|
685
|
-
(tuple) => this.runProviderContextChangeHandler(tuple.name, tuple.provider, oldContext, context)
|
|
686
|
-
)
|
|
687
|
-
);
|
|
623
|
+
this._namedProviderContext.set(clientName, context);
|
|
688
624
|
}
|
|
689
|
-
}
|
|
625
|
+
} else {
|
|
626
|
+
const oldContext = this._context;
|
|
627
|
+
this._context = context;
|
|
628
|
+
const defaultContextNameProviders = Array.from(this._clientProviders.entries()).filter(([name]) => !this._namedProviderContext.has(name)).reduce((acc, [name, provider]) => {
|
|
629
|
+
acc.push({ name, provider });
|
|
630
|
+
return acc;
|
|
631
|
+
}, []);
|
|
632
|
+
const allProviders = [
|
|
633
|
+
// add in the default (no name)
|
|
634
|
+
{ name: void 0, provider: this._defaultProvider },
|
|
635
|
+
...defaultContextNameProviders
|
|
636
|
+
];
|
|
637
|
+
await Promise.all(
|
|
638
|
+
allProviders.map(
|
|
639
|
+
(tuple) => this.runProviderContextChangeHandler(tuple.name, tuple.provider, oldContext, context)
|
|
640
|
+
)
|
|
641
|
+
);
|
|
642
|
+
}
|
|
690
643
|
}
|
|
691
644
|
getContext(nameOrUndefined) {
|
|
692
645
|
const clientName = (0, import_core6.stringOrUndefined)(nameOrUndefined);
|
|
@@ -700,33 +653,29 @@ var OpenFeatureAPI = class extends import_core6.OpenFeatureCommonAPI {
|
|
|
700
653
|
}
|
|
701
654
|
return this._context;
|
|
702
655
|
}
|
|
703
|
-
clearContext(nameOrUndefined) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
yield this.runProviderContextChangeHandler(clientName, provider, oldContext, newContext);
|
|
713
|
-
} else {
|
|
714
|
-
this._namedProviderContext.delete(clientName);
|
|
715
|
-
}
|
|
656
|
+
async clearContext(nameOrUndefined) {
|
|
657
|
+
const clientName = (0, import_core6.stringOrUndefined)(nameOrUndefined);
|
|
658
|
+
if (clientName) {
|
|
659
|
+
const provider = this._clientProviders.get(clientName);
|
|
660
|
+
if (provider) {
|
|
661
|
+
const oldContext = this.getContext(clientName);
|
|
662
|
+
this._namedProviderContext.delete(clientName);
|
|
663
|
+
const newContext = this.getContext();
|
|
664
|
+
await this.runProviderContextChangeHandler(clientName, provider, oldContext, newContext);
|
|
716
665
|
} else {
|
|
717
|
-
|
|
666
|
+
this._namedProviderContext.delete(clientName);
|
|
718
667
|
}
|
|
719
|
-
}
|
|
668
|
+
} else {
|
|
669
|
+
return this.setContext({});
|
|
670
|
+
}
|
|
720
671
|
}
|
|
721
672
|
/**
|
|
722
673
|
* Resets the global evaluation context and removes the evaluation context for
|
|
723
674
|
* all named clients.
|
|
724
675
|
*/
|
|
725
|
-
clearContexts() {
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
yield Promise.allSettled(Array.from(this._clientProviders.keys()).map((name) => this.clearContext(name)));
|
|
729
|
-
});
|
|
676
|
+
async clearContexts() {
|
|
677
|
+
await this.clearContext();
|
|
678
|
+
await Promise.allSettled(Array.from(this._clientProviders.keys()).map((name) => this.clearContext(name)));
|
|
730
679
|
}
|
|
731
680
|
/**
|
|
732
681
|
* A factory function for creating new named OpenFeature clients. Clients can contain
|
|
@@ -753,32 +702,27 @@ var OpenFeatureAPI = class extends import_core6.OpenFeatureCommonAPI {
|
|
|
753
702
|
* Clears all registered providers and resets the default provider.
|
|
754
703
|
* @returns {Promise<void>}
|
|
755
704
|
*/
|
|
756
|
-
clearProviders() {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
this._namedProviderContext.clear();
|
|
760
|
-
});
|
|
705
|
+
async clearProviders() {
|
|
706
|
+
await super.clearProvidersAndSetDefault(NOOP_PROVIDER);
|
|
707
|
+
this._namedProviderContext.clear();
|
|
761
708
|
}
|
|
762
|
-
runProviderContextChangeHandler(clientName, provider, oldContext, newContext) {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
(
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
(_e = this._events) == null ? void 0 : _e.emit(import_core2.ClientProviderEvents.Error, { clientName, providerName, message });
|
|
780
|
-
}
|
|
781
|
-
});
|
|
709
|
+
async runProviderContextChangeHandler(clientName, provider, oldContext, newContext) {
|
|
710
|
+
const providerName = provider.metadata.name;
|
|
711
|
+
try {
|
|
712
|
+
await provider.onContextChange?.(oldContext, newContext);
|
|
713
|
+
this.getAssociatedEventEmitters(clientName).forEach((emitter) => {
|
|
714
|
+
emitter?.emit(import_core2.ClientProviderEvents.ContextChanged, { clientName, providerName });
|
|
715
|
+
});
|
|
716
|
+
this._events?.emit(import_core2.ClientProviderEvents.ContextChanged, { clientName, providerName });
|
|
717
|
+
} catch (err) {
|
|
718
|
+
const error = err;
|
|
719
|
+
const message = `Error running ${provider?.metadata?.name}'s context change handler: ${error?.message}`;
|
|
720
|
+
this._logger?.error(`${message}`, err);
|
|
721
|
+
this.getAssociatedEventEmitters(clientName).forEach((emitter) => {
|
|
722
|
+
emitter?.emit(import_core2.ClientProviderEvents.Error, { clientName, providerName, message });
|
|
723
|
+
});
|
|
724
|
+
this._events?.emit(import_core2.ClientProviderEvents.Error, { clientName, providerName, message });
|
|
725
|
+
}
|
|
782
726
|
}
|
|
783
727
|
};
|
|
784
728
|
var OpenFeature = OpenFeatureAPI.getInstance();
|
|
@@ -790,8 +734,9 @@ var OpenFeatureClient = class {
|
|
|
790
734
|
this.emitterAccessor = emitterAccessor;
|
|
791
735
|
this.globalLogger = globalLogger;
|
|
792
736
|
this.options = options;
|
|
793
|
-
this._hooks = [];
|
|
794
737
|
}
|
|
738
|
+
_hooks = [];
|
|
739
|
+
_clientLogger;
|
|
795
740
|
get metadata() {
|
|
796
741
|
return {
|
|
797
742
|
name: this.options.name,
|
|
@@ -800,18 +745,16 @@ var OpenFeatureClient = class {
|
|
|
800
745
|
};
|
|
801
746
|
}
|
|
802
747
|
get providerStatus() {
|
|
803
|
-
|
|
804
|
-
return ((_a = this.providerAccessor()) == null ? void 0 : _a.status) || import_core7.ProviderStatus.READY;
|
|
748
|
+
return this.providerAccessor()?.status || import_core7.ProviderStatus.READY;
|
|
805
749
|
}
|
|
806
750
|
addHandler(eventType, handler) {
|
|
807
|
-
var _a;
|
|
808
751
|
this.emitterAccessor().addHandler(eventType, handler);
|
|
809
752
|
const shouldRunNow = (0, import_core7.statusMatchesEvent)(eventType, this._provider.status);
|
|
810
753
|
if (shouldRunNow) {
|
|
811
754
|
try {
|
|
812
755
|
handler({ clientName: this.metadata.name, providerName: this._provider.metadata.name });
|
|
813
756
|
} catch (err) {
|
|
814
|
-
|
|
757
|
+
this._logger?.error("Error running event handler:", err);
|
|
815
758
|
}
|
|
816
759
|
}
|
|
817
760
|
}
|
|
@@ -875,7 +818,6 @@ var OpenFeatureClient = class {
|
|
|
875
818
|
return this.evaluate(flagKey, this._provider.resolveObjectEvaluation, defaultValue, "object", options);
|
|
876
819
|
}
|
|
877
820
|
evaluate(flagKey, resolver, defaultValue, flagType, options = {}) {
|
|
878
|
-
var _a, _b;
|
|
879
821
|
const allHooks = [
|
|
880
822
|
...OpenFeature.getHooks(),
|
|
881
823
|
...this.getHooks(),
|
|
@@ -883,7 +825,9 @@ var OpenFeatureClient = class {
|
|
|
883
825
|
...this._provider.hooks || []
|
|
884
826
|
];
|
|
885
827
|
const allHooksReversed = [...allHooks].reverse();
|
|
886
|
-
const context =
|
|
828
|
+
const context = {
|
|
829
|
+
...OpenFeature.getContext(this?.options?.name)
|
|
830
|
+
};
|
|
887
831
|
const hookContext = {
|
|
888
832
|
flagKey,
|
|
889
833
|
defaultValue,
|
|
@@ -896,15 +840,16 @@ var OpenFeatureClient = class {
|
|
|
896
840
|
try {
|
|
897
841
|
this.beforeHooks(allHooks, hookContext, options);
|
|
898
842
|
const resolution = resolver.call(this._provider, flagKey, defaultValue, context, this._logger);
|
|
899
|
-
const evaluationDetails =
|
|
900
|
-
|
|
843
|
+
const evaluationDetails = {
|
|
844
|
+
...resolution,
|
|
845
|
+
flagMetadata: Object.freeze(resolution.flagMetadata ?? {}),
|
|
901
846
|
flagKey
|
|
902
|
-
}
|
|
847
|
+
};
|
|
903
848
|
this.afterHooks(allHooksReversed, hookContext, evaluationDetails, options);
|
|
904
849
|
return evaluationDetails;
|
|
905
850
|
} catch (err) {
|
|
906
|
-
const errorMessage = err
|
|
907
|
-
const errorCode =
|
|
851
|
+
const errorMessage = err?.message;
|
|
852
|
+
const errorCode = err?.code || import_core7.ErrorCode.GENERAL;
|
|
908
853
|
this.errorHooks(allHooksReversed, hookContext, err, options);
|
|
909
854
|
return {
|
|
910
855
|
errorCode,
|
|
@@ -919,44 +864,40 @@ var OpenFeatureClient = class {
|
|
|
919
864
|
}
|
|
920
865
|
}
|
|
921
866
|
beforeHooks(hooks, hookContext, options) {
|
|
922
|
-
var _a;
|
|
923
867
|
Object.freeze(hookContext);
|
|
924
868
|
Object.freeze(hookContext.context);
|
|
925
869
|
for (const hook of hooks) {
|
|
926
|
-
|
|
870
|
+
hook?.before?.(hookContext, Object.freeze(options.hookHints));
|
|
927
871
|
}
|
|
928
872
|
}
|
|
929
873
|
afterHooks(hooks, hookContext, evaluationDetails, options) {
|
|
930
|
-
var _a;
|
|
931
874
|
for (const hook of hooks) {
|
|
932
|
-
|
|
875
|
+
hook?.after?.(hookContext, evaluationDetails, options.hookHints);
|
|
933
876
|
}
|
|
934
877
|
}
|
|
935
878
|
errorHooks(hooks, hookContext, err, options) {
|
|
936
|
-
var _a;
|
|
937
879
|
for (const hook of hooks) {
|
|
938
880
|
try {
|
|
939
|
-
|
|
881
|
+
hook?.error?.(hookContext, err, options.hookHints);
|
|
940
882
|
} catch (err2) {
|
|
941
883
|
this._logger.error(`Unhandled error during 'error' hook: ${err2}`);
|
|
942
884
|
if (err2 instanceof Error) {
|
|
943
885
|
this._logger.error(err2.stack);
|
|
944
886
|
}
|
|
945
|
-
this._logger.error(err2
|
|
887
|
+
this._logger.error(err2?.stack);
|
|
946
888
|
}
|
|
947
889
|
}
|
|
948
890
|
}
|
|
949
891
|
finallyHooks(hooks, hookContext, options) {
|
|
950
|
-
var _a;
|
|
951
892
|
for (const hook of hooks) {
|
|
952
893
|
try {
|
|
953
|
-
|
|
894
|
+
hook?.finally?.(hookContext, options.hookHints);
|
|
954
895
|
} catch (err) {
|
|
955
896
|
this._logger.error(`Unhandled error during 'finally' hook: ${err}`);
|
|
956
897
|
if (err instanceof Error) {
|
|
957
898
|
this._logger.error(err.stack);
|
|
958
899
|
}
|
|
959
|
-
this._logger.error(err
|
|
900
|
+
this._logger.error(err?.stack);
|
|
960
901
|
}
|
|
961
902
|
}
|
|
962
903
|
}
|