@openfeature/web-sdk 1.6.2 → 1.7.1
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 +60 -2
- package/dist/cjs/index.js +541 -23
- package/dist/cjs/index.js.map +4 -4
- package/dist/esm/index.js +523 -5
- package/dist/esm/index.js.map +4 -4
- package/dist/global/index.js +513 -1
- package/dist/global/index.js.map +4 -4
- package/dist/global/index.min.js +1 -1
- package/dist/global/index.min.js.map +4 -4
- package/dist/types.d.ts +145 -3
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -235,13 +235,22 @@ var require_eventemitter3 = __commonJS({
|
|
|
235
235
|
// src/index.ts
|
|
236
236
|
var index_exports = {};
|
|
237
237
|
__export(index_exports, {
|
|
238
|
+
AggregateError: () => AggregateError,
|
|
239
|
+
BaseEvaluationStrategy: () => BaseEvaluationStrategy,
|
|
240
|
+
ComparisonStrategy: () => ComparisonStrategy,
|
|
241
|
+
ErrorWithCode: () => ErrorWithCode,
|
|
242
|
+
FirstMatchStrategy: () => FirstMatchStrategy,
|
|
243
|
+
FirstSuccessfulStrategy: () => FirstSuccessfulStrategy,
|
|
238
244
|
InMemoryProvider: () => InMemoryProvider,
|
|
245
|
+
MultiProvider: () => MultiProvider,
|
|
239
246
|
NOOP_PROVIDER: () => NOOP_PROVIDER,
|
|
240
247
|
OpenFeature: () => OpenFeature,
|
|
241
248
|
OpenFeatureAPI: () => OpenFeatureAPI,
|
|
242
249
|
OpenFeatureEventEmitter: () => OpenFeatureEventEmitter,
|
|
243
250
|
ProviderEvents: () => import_core3.ClientProviderEvents,
|
|
244
|
-
ProviderStatus: () => import_core.ClientProviderStatus
|
|
251
|
+
ProviderStatus: () => import_core.ClientProviderStatus,
|
|
252
|
+
constructAggregateError: () => constructAggregateError,
|
|
253
|
+
throwAggregateErrorFromPromiseResults: () => throwAggregateErrorFromPromiseResults
|
|
245
254
|
});
|
|
246
255
|
module.exports = __toCommonJS(index_exports);
|
|
247
256
|
|
|
@@ -392,11 +401,520 @@ var InMemoryProvider = class {
|
|
|
392
401
|
}
|
|
393
402
|
};
|
|
394
403
|
|
|
395
|
-
// src/
|
|
404
|
+
// src/provider/multi-provider/multi-provider-web.ts
|
|
405
|
+
var import_core9 = require("@openfeature/core");
|
|
406
|
+
|
|
407
|
+
// src/provider/multi-provider/hook-executor.ts
|
|
408
|
+
var HookExecutor = class {
|
|
409
|
+
constructor(logger) {
|
|
410
|
+
this.logger = logger;
|
|
411
|
+
}
|
|
412
|
+
beforeHooks(hooks, hookContext, hints) {
|
|
413
|
+
var _a;
|
|
414
|
+
for (const hook of hooks != null ? hooks : []) {
|
|
415
|
+
(_a = hook == null ? void 0 : hook.before) == null ? void 0 : _a.call(hook, hookContext, Object.freeze(hints));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
afterHooks(hooks, hookContext, evaluationDetails, hints) {
|
|
419
|
+
var _a;
|
|
420
|
+
for (const hook of hooks != null ? hooks : []) {
|
|
421
|
+
(_a = hook == null ? void 0 : hook.after) == null ? void 0 : _a.call(hook, hookContext, evaluationDetails, hints);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
errorHooks(hooks, hookContext, err, hints) {
|
|
425
|
+
var _a;
|
|
426
|
+
for (const hook of hooks != null ? hooks : []) {
|
|
427
|
+
try {
|
|
428
|
+
(_a = hook == null ? void 0 : hook.error) == null ? void 0 : _a.call(hook, hookContext, err, hints);
|
|
429
|
+
} catch (err2) {
|
|
430
|
+
this.logger.error(`Unhandled error during 'error' hook: ${err2}`);
|
|
431
|
+
if (err2 instanceof Error) {
|
|
432
|
+
this.logger.error(err2.stack);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
finallyHooks(hooks, hookContext, evaluationDetails, hints) {
|
|
438
|
+
var _a;
|
|
439
|
+
for (const hook of hooks != null ? hooks : []) {
|
|
440
|
+
try {
|
|
441
|
+
(_a = hook == null ? void 0 : hook.finally) == null ? void 0 : _a.call(hook, hookContext, evaluationDetails, hints);
|
|
442
|
+
} catch (err) {
|
|
443
|
+
this.logger.error(`Unhandled error during 'finally' hook: ${err}`);
|
|
444
|
+
if (err instanceof Error) {
|
|
445
|
+
this.logger.error(err.stack);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// src/provider/multi-provider/errors.ts
|
|
453
|
+
var import_core6 = require("@openfeature/core");
|
|
454
|
+
var ErrorWithCode = class extends import_core6.OpenFeatureError {
|
|
455
|
+
constructor(code, message) {
|
|
456
|
+
super(message);
|
|
457
|
+
this.code = code;
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
var AggregateError = class extends import_core6.GeneralError {
|
|
461
|
+
constructor(message, originalErrors) {
|
|
462
|
+
super(message);
|
|
463
|
+
this.originalErrors = originalErrors;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
var constructAggregateError = (providerErrors) => {
|
|
467
|
+
const errorsWithSource = providerErrors.map(({ providerName, error }) => {
|
|
468
|
+
return { source: providerName, error };
|
|
469
|
+
}).flat();
|
|
470
|
+
return new AggregateError(
|
|
471
|
+
`Provider errors occurred: ${errorsWithSource[0].source}: ${errorsWithSource[0].error}`,
|
|
472
|
+
errorsWithSource
|
|
473
|
+
);
|
|
474
|
+
};
|
|
475
|
+
var throwAggregateErrorFromPromiseResults = (result, providerEntries) => {
|
|
476
|
+
const errors = result.map((r, i) => {
|
|
477
|
+
if (r.status === "rejected") {
|
|
478
|
+
return { error: r.reason, providerName: providerEntries[i].name };
|
|
479
|
+
}
|
|
480
|
+
return null;
|
|
481
|
+
}).filter((val) => Boolean(val));
|
|
482
|
+
if (errors.length) {
|
|
483
|
+
throw constructAggregateError(errors);
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// src/provider/multi-provider/strategies/base-evaluation-strategy.ts
|
|
488
|
+
var BaseEvaluationStrategy = class {
|
|
489
|
+
shouldEvaluateThisProvider(strategyContext, _evalContext) {
|
|
490
|
+
if (strategyContext.providerStatus === import_core.ClientProviderStatus.NOT_READY || strategyContext.providerStatus === import_core.ClientProviderStatus.FATAL) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
shouldEvaluateNextProvider(_strategyContext, _context, _result) {
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
shouldTrackWithThisProvider(strategyContext, _context, _trackingEventName, _trackingEventDetails) {
|
|
499
|
+
if (strategyContext.providerStatus === import_core.ClientProviderStatus.NOT_READY || strategyContext.providerStatus === import_core.ClientProviderStatus.FATAL) {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
return true;
|
|
503
|
+
}
|
|
504
|
+
hasError(resolution) {
|
|
505
|
+
return "thrownError" in resolution || !!resolution.details.errorCode;
|
|
506
|
+
}
|
|
507
|
+
hasErrorWithCode(resolution, code) {
|
|
508
|
+
var _a;
|
|
509
|
+
return "thrownError" in resolution ? ((_a = resolution.thrownError) == null ? void 0 : _a.code) === code : resolution.details.errorCode === code;
|
|
510
|
+
}
|
|
511
|
+
collectProviderErrors(resolutions) {
|
|
512
|
+
var _a;
|
|
513
|
+
const errors = [];
|
|
514
|
+
for (const resolution of resolutions) {
|
|
515
|
+
if ("thrownError" in resolution) {
|
|
516
|
+
errors.push({ providerName: resolution.providerName, error: resolution.thrownError });
|
|
517
|
+
} else if (resolution.details.errorCode) {
|
|
518
|
+
errors.push({
|
|
519
|
+
providerName: resolution.providerName,
|
|
520
|
+
error: new ErrorWithCode(resolution.details.errorCode, (_a = resolution.details.errorMessage) != null ? _a : "unknown error")
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return { errors };
|
|
525
|
+
}
|
|
526
|
+
resolutionToFinalResult(resolution) {
|
|
527
|
+
return { details: resolution.details, provider: resolution.provider, providerName: resolution.providerName };
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
// src/provider/multi-provider/strategies/first-match-strategy.ts
|
|
396
532
|
var import_core7 = require("@openfeature/core");
|
|
533
|
+
var FirstMatchStrategy = class extends BaseEvaluationStrategy {
|
|
534
|
+
shouldEvaluateNextProvider(strategyContext, context, result) {
|
|
535
|
+
if (this.hasErrorWithCode(result, import_core7.ErrorCode.FLAG_NOT_FOUND)) {
|
|
536
|
+
return true;
|
|
537
|
+
}
|
|
538
|
+
if (this.hasError(result)) {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
determineFinalResult(strategyContext, context, resolutions) {
|
|
544
|
+
const finalResolution = resolutions[resolutions.length - 1];
|
|
545
|
+
if (this.hasError(finalResolution)) {
|
|
546
|
+
return this.collectProviderErrors(resolutions);
|
|
547
|
+
}
|
|
548
|
+
return this.resolutionToFinalResult(finalResolution);
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
// src/provider/multi-provider/strategies/first-successful-strategy.ts
|
|
553
|
+
var FirstSuccessfulStrategy = class extends BaseEvaluationStrategy {
|
|
554
|
+
shouldEvaluateNextProvider(strategyContext, context, result) {
|
|
555
|
+
return this.hasError(result);
|
|
556
|
+
}
|
|
557
|
+
determineFinalResult(strategyContext, context, resolutions) {
|
|
558
|
+
const finalResolution = resolutions[resolutions.length - 1];
|
|
559
|
+
if (this.hasError(finalResolution)) {
|
|
560
|
+
return this.collectProviderErrors(resolutions);
|
|
561
|
+
}
|
|
562
|
+
return this.resolutionToFinalResult(finalResolution);
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// src/provider/multi-provider/strategies/comparison-strategy.ts
|
|
567
|
+
var import_core8 = require("@openfeature/core");
|
|
568
|
+
var ComparisonStrategy = class extends BaseEvaluationStrategy {
|
|
569
|
+
constructor(fallbackProvider, onMismatch) {
|
|
570
|
+
super();
|
|
571
|
+
this.fallbackProvider = fallbackProvider;
|
|
572
|
+
this.onMismatch = onMismatch;
|
|
573
|
+
}
|
|
574
|
+
determineFinalResult(strategyContext, context, resolutions) {
|
|
575
|
+
var _a;
|
|
576
|
+
let value;
|
|
577
|
+
let fallbackResolution;
|
|
578
|
+
let finalResolution;
|
|
579
|
+
let mismatch = false;
|
|
580
|
+
for (const [i, resolution] of resolutions.entries()) {
|
|
581
|
+
if (this.hasError(resolution)) {
|
|
582
|
+
return this.collectProviderErrors(resolutions);
|
|
583
|
+
}
|
|
584
|
+
if (resolution.provider === this.fallbackProvider) {
|
|
585
|
+
fallbackResolution = resolution;
|
|
586
|
+
}
|
|
587
|
+
if (i === 0) {
|
|
588
|
+
finalResolution = resolution;
|
|
589
|
+
}
|
|
590
|
+
if (typeof value !== "undefined" && value !== resolution.details.value) {
|
|
591
|
+
mismatch = true;
|
|
592
|
+
} else {
|
|
593
|
+
value = resolution.details.value;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
if (!fallbackResolution) {
|
|
597
|
+
throw new import_core8.GeneralError("Fallback provider not found in resolution results");
|
|
598
|
+
}
|
|
599
|
+
if (!finalResolution) {
|
|
600
|
+
throw new import_core8.GeneralError("Final resolution not found in resolution results");
|
|
601
|
+
}
|
|
602
|
+
if (mismatch) {
|
|
603
|
+
(_a = this.onMismatch) == null ? void 0 : _a.call(this, resolutions);
|
|
604
|
+
return {
|
|
605
|
+
details: fallbackResolution.details,
|
|
606
|
+
provider: fallbackResolution.provider
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
return this.resolutionToFinalResult(finalResolution);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
// src/provider/multi-provider/status-tracker.ts
|
|
614
|
+
var StatusTracker = class {
|
|
615
|
+
constructor(events) {
|
|
616
|
+
this.events = events;
|
|
617
|
+
this.providerStatuses = {};
|
|
618
|
+
}
|
|
619
|
+
wrapEventHandler(providerEntry) {
|
|
620
|
+
var _a, _b, _c, _d, _e;
|
|
621
|
+
const provider = providerEntry.provider;
|
|
622
|
+
(_a = provider.events) == null ? void 0 : _a.addHandler(import_core3.ClientProviderEvents.Error, (details) => {
|
|
623
|
+
this.changeProviderStatus(providerEntry.name, import_core.ClientProviderStatus.ERROR, details);
|
|
624
|
+
});
|
|
625
|
+
(_b = provider.events) == null ? void 0 : _b.addHandler(import_core3.ClientProviderEvents.Stale, (details) => {
|
|
626
|
+
this.changeProviderStatus(providerEntry.name, import_core.ClientProviderStatus.STALE, details);
|
|
627
|
+
});
|
|
628
|
+
(_c = provider.events) == null ? void 0 : _c.addHandler(import_core3.ClientProviderEvents.ConfigurationChanged, (details) => {
|
|
629
|
+
this.events.emit(import_core3.ClientProviderEvents.ConfigurationChanged, details);
|
|
630
|
+
});
|
|
631
|
+
(_d = provider.events) == null ? void 0 : _d.addHandler(import_core3.ClientProviderEvents.Ready, (details) => {
|
|
632
|
+
this.changeProviderStatus(providerEntry.name, import_core.ClientProviderStatus.READY, details);
|
|
633
|
+
});
|
|
634
|
+
(_e = provider.events) == null ? void 0 : _e.addHandler(import_core3.ClientProviderEvents.Reconciling, (details) => {
|
|
635
|
+
this.changeProviderStatus(providerEntry.name, import_core.ClientProviderStatus.RECONCILING, details);
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
providerStatus(name) {
|
|
639
|
+
return this.providerStatuses[name];
|
|
640
|
+
}
|
|
641
|
+
getStatusFromProviderStatuses() {
|
|
642
|
+
const statuses = Object.values(this.providerStatuses);
|
|
643
|
+
if (statuses.includes(import_core.ClientProviderStatus.FATAL)) {
|
|
644
|
+
return import_core.ClientProviderStatus.FATAL;
|
|
645
|
+
} else if (statuses.includes(import_core.ClientProviderStatus.NOT_READY)) {
|
|
646
|
+
return import_core.ClientProviderStatus.NOT_READY;
|
|
647
|
+
} else if (statuses.includes(import_core.ClientProviderStatus.ERROR)) {
|
|
648
|
+
return import_core.ClientProviderStatus.ERROR;
|
|
649
|
+
} else if (statuses.includes(import_core.ClientProviderStatus.STALE)) {
|
|
650
|
+
return import_core.ClientProviderStatus.STALE;
|
|
651
|
+
} else if (statuses.includes(import_core.ClientProviderStatus.RECONCILING)) {
|
|
652
|
+
return import_core.ClientProviderStatus.RECONCILING;
|
|
653
|
+
}
|
|
654
|
+
return import_core.ClientProviderStatus.READY;
|
|
655
|
+
}
|
|
656
|
+
changeProviderStatus(name, status, details) {
|
|
657
|
+
const currentStatus = this.getStatusFromProviderStatuses();
|
|
658
|
+
this.providerStatuses[name] = status;
|
|
659
|
+
const newStatus = this.getStatusFromProviderStatuses();
|
|
660
|
+
if (currentStatus !== newStatus) {
|
|
661
|
+
if (newStatus === import_core.ClientProviderStatus.FATAL || newStatus === import_core.ClientProviderStatus.ERROR) {
|
|
662
|
+
this.events.emit(import_core3.ClientProviderEvents.Error, details);
|
|
663
|
+
} else if (newStatus === import_core.ClientProviderStatus.STALE) {
|
|
664
|
+
this.events.emit(import_core3.ClientProviderEvents.Stale, details);
|
|
665
|
+
} else if (newStatus === import_core.ClientProviderStatus.READY) {
|
|
666
|
+
this.events.emit(import_core3.ClientProviderEvents.Ready, details);
|
|
667
|
+
} else if (newStatus === import_core.ClientProviderStatus.RECONCILING) {
|
|
668
|
+
this.events.emit(import_core3.ClientProviderEvents.Reconciling, details);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
// src/provider/multi-provider/multi-provider-web.ts
|
|
675
|
+
var MultiProvider = class _MultiProvider {
|
|
676
|
+
constructor(constructorProviders, evaluationStrategy = new FirstMatchStrategy(), logger = new import_core9.DefaultLogger()) {
|
|
677
|
+
this.constructorProviders = constructorProviders;
|
|
678
|
+
this.evaluationStrategy = evaluationStrategy;
|
|
679
|
+
this.logger = logger;
|
|
680
|
+
this.runsOn = "client";
|
|
681
|
+
this.events = new OpenFeatureEventEmitter();
|
|
682
|
+
this.hookContexts = /* @__PURE__ */ new WeakMap();
|
|
683
|
+
this.hookHints = /* @__PURE__ */ new WeakMap();
|
|
684
|
+
this.providerEntries = [];
|
|
685
|
+
this.providerEntriesByName = {};
|
|
686
|
+
this.statusTracker = new StatusTracker(this.events);
|
|
687
|
+
this.hookExecutor = new HookExecutor(this.logger);
|
|
688
|
+
this.registerProviders(constructorProviders);
|
|
689
|
+
const aggregateMetadata = Object.keys(this.providerEntriesByName).reduce((acc, name) => {
|
|
690
|
+
return __spreadProps(__spreadValues({}, acc), { [name]: this.providerEntriesByName[name].provider.metadata });
|
|
691
|
+
}, {});
|
|
692
|
+
this.metadata = __spreadProps(__spreadValues({}, aggregateMetadata), {
|
|
693
|
+
name: _MultiProvider.name
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
registerProviders(constructorProviders) {
|
|
697
|
+
var _a, _b;
|
|
698
|
+
const providersByName = {};
|
|
699
|
+
for (const constructorProvider of constructorProviders) {
|
|
700
|
+
const providerName = constructorProvider.provider.metadata.name;
|
|
701
|
+
const candidateName = (_a = constructorProvider.name) != null ? _a : providerName;
|
|
702
|
+
if (constructorProvider.name && providersByName[constructorProvider.name]) {
|
|
703
|
+
throw new Error("Provider names must be unique");
|
|
704
|
+
}
|
|
705
|
+
(_b = providersByName[candidateName]) != null ? _b : providersByName[candidateName] = [];
|
|
706
|
+
providersByName[candidateName].push(constructorProvider.provider);
|
|
707
|
+
}
|
|
708
|
+
for (const name of Object.keys(providersByName)) {
|
|
709
|
+
const useIndexedNames = providersByName[name].length > 1;
|
|
710
|
+
for (let i = 0; i < providersByName[name].length; i++) {
|
|
711
|
+
const indexedName = useIndexedNames ? `${name}-${i + 1}` : name;
|
|
712
|
+
this.providerEntriesByName[indexedName] = { provider: providersByName[name][i], name: indexedName };
|
|
713
|
+
this.providerEntries.push(this.providerEntriesByName[indexedName]);
|
|
714
|
+
this.statusTracker.wrapEventHandler(this.providerEntriesByName[indexedName]);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
Object.freeze(this.providerEntries);
|
|
718
|
+
Object.freeze(this.providerEntriesByName);
|
|
719
|
+
}
|
|
720
|
+
initialize(context) {
|
|
721
|
+
return __async(this, null, function* () {
|
|
722
|
+
const result = yield Promise.allSettled(
|
|
723
|
+
this.providerEntries.map((provider) => {
|
|
724
|
+
var _a, _b;
|
|
725
|
+
return (_b = (_a = provider.provider).initialize) == null ? void 0 : _b.call(_a, context);
|
|
726
|
+
})
|
|
727
|
+
);
|
|
728
|
+
throwAggregateErrorFromPromiseResults(result, this.providerEntries);
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
onClose() {
|
|
732
|
+
return __async(this, null, function* () {
|
|
733
|
+
const result = yield Promise.allSettled(this.providerEntries.map((provider) => {
|
|
734
|
+
var _a, _b;
|
|
735
|
+
return (_b = (_a = provider.provider).onClose) == null ? void 0 : _b.call(_a);
|
|
736
|
+
}));
|
|
737
|
+
throwAggregateErrorFromPromiseResults(result, this.providerEntries);
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
onContextChange(oldContext, newContext) {
|
|
741
|
+
return __async(this, null, function* () {
|
|
742
|
+
var _a, _b;
|
|
743
|
+
for (const providerEntry of this.providerEntries) {
|
|
744
|
+
yield (_b = (_a = providerEntry.provider).onContextChange) == null ? void 0 : _b.call(_a, oldContext, newContext);
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
resolveBooleanEvaluation(flagKey, defaultValue, context) {
|
|
749
|
+
return this.flagResolutionProxy(flagKey, "boolean", defaultValue, context);
|
|
750
|
+
}
|
|
751
|
+
resolveStringEvaluation(flagKey, defaultValue, context) {
|
|
752
|
+
return this.flagResolutionProxy(flagKey, "string", defaultValue, context);
|
|
753
|
+
}
|
|
754
|
+
resolveNumberEvaluation(flagKey, defaultValue, context) {
|
|
755
|
+
return this.flagResolutionProxy(flagKey, "number", defaultValue, context);
|
|
756
|
+
}
|
|
757
|
+
resolveObjectEvaluation(flagKey, defaultValue, context) {
|
|
758
|
+
return this.flagResolutionProxy(flagKey, "object", defaultValue, context);
|
|
759
|
+
}
|
|
760
|
+
track(trackingEventName, context, trackingEventDetails) {
|
|
761
|
+
var _a, _b;
|
|
762
|
+
for (const providerEntry of this.providerEntries) {
|
|
763
|
+
if (!providerEntry.provider.track) {
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
const strategyContext = {
|
|
767
|
+
provider: providerEntry.provider,
|
|
768
|
+
providerName: providerEntry.name,
|
|
769
|
+
providerStatus: this.statusTracker.providerStatus(providerEntry.name)
|
|
770
|
+
};
|
|
771
|
+
if (this.evaluationStrategy.shouldTrackWithThisProvider(
|
|
772
|
+
strategyContext,
|
|
773
|
+
context,
|
|
774
|
+
trackingEventName,
|
|
775
|
+
trackingEventDetails
|
|
776
|
+
)) {
|
|
777
|
+
try {
|
|
778
|
+
(_b = (_a = providerEntry.provider).track) == null ? void 0 : _b.call(_a, trackingEventName, context, trackingEventDetails);
|
|
779
|
+
} catch (error) {
|
|
780
|
+
this.logger.error(
|
|
781
|
+
`Error tracking event "${trackingEventName}" with provider "${providerEntry.name}":`,
|
|
782
|
+
error
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
flagResolutionProxy(flagKey, flagType, defaultValue, context) {
|
|
789
|
+
var _a;
|
|
790
|
+
const hookContext = this.hookContexts.get(context);
|
|
791
|
+
const hookHints = this.hookHints.get(context);
|
|
792
|
+
if (!hookContext || !hookHints) {
|
|
793
|
+
throw new import_core9.GeneralError("Hook context not available for evaluation");
|
|
794
|
+
}
|
|
795
|
+
const results = [];
|
|
796
|
+
for (const providerEntry of this.providerEntries) {
|
|
797
|
+
const [shouldEvaluateNext, result] = this.evaluateProviderEntry(
|
|
798
|
+
flagKey,
|
|
799
|
+
flagType,
|
|
800
|
+
defaultValue,
|
|
801
|
+
providerEntry,
|
|
802
|
+
hookContext,
|
|
803
|
+
hookHints,
|
|
804
|
+
context
|
|
805
|
+
);
|
|
806
|
+
results.push(result);
|
|
807
|
+
if (!shouldEvaluateNext) {
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
const resolutions = results.filter((r) => Boolean(r));
|
|
812
|
+
const finalResult = this.evaluationStrategy.determineFinalResult({ flagKey, flagType }, context, resolutions);
|
|
813
|
+
if ((_a = finalResult.errors) == null ? void 0 : _a.length) {
|
|
814
|
+
throw constructAggregateError(finalResult.errors);
|
|
815
|
+
}
|
|
816
|
+
if (!finalResult.details) {
|
|
817
|
+
throw new import_core9.GeneralError("No result was returned from any provider");
|
|
818
|
+
}
|
|
819
|
+
return finalResult.details;
|
|
820
|
+
}
|
|
821
|
+
evaluateProviderEntry(flagKey, flagType, defaultValue, providerEntry, hookContext, hookHints, context) {
|
|
822
|
+
let evaluationResult = void 0;
|
|
823
|
+
const provider = providerEntry.provider;
|
|
824
|
+
const strategyContext = {
|
|
825
|
+
flagKey,
|
|
826
|
+
flagType,
|
|
827
|
+
provider,
|
|
828
|
+
providerName: providerEntry.name,
|
|
829
|
+
providerStatus: this.statusTracker.providerStatus(providerEntry.name)
|
|
830
|
+
};
|
|
831
|
+
if (!this.evaluationStrategy.shouldEvaluateThisProvider(strategyContext, context)) {
|
|
832
|
+
return [true, null];
|
|
833
|
+
}
|
|
834
|
+
let resolution;
|
|
835
|
+
try {
|
|
836
|
+
evaluationResult = this.evaluateProviderAndHooks(flagKey, defaultValue, provider, hookContext, hookHints);
|
|
837
|
+
resolution = {
|
|
838
|
+
details: evaluationResult,
|
|
839
|
+
provider,
|
|
840
|
+
providerName: providerEntry.name
|
|
841
|
+
};
|
|
842
|
+
} catch (error) {
|
|
843
|
+
resolution = {
|
|
844
|
+
thrownError: error,
|
|
845
|
+
provider,
|
|
846
|
+
providerName: providerEntry.name
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
return [this.evaluationStrategy.shouldEvaluateNextProvider(strategyContext, context, resolution), resolution];
|
|
850
|
+
}
|
|
851
|
+
evaluateProviderAndHooks(flagKey, defaultValue, provider, hookContext, hookHints) {
|
|
852
|
+
var _a;
|
|
853
|
+
let evaluationDetails;
|
|
854
|
+
try {
|
|
855
|
+
this.hookExecutor.beforeHooks(provider.hooks, hookContext, hookHints);
|
|
856
|
+
const resolutionDetails = this.callProviderResolve(
|
|
857
|
+
provider,
|
|
858
|
+
flagKey,
|
|
859
|
+
defaultValue,
|
|
860
|
+
hookContext.context
|
|
861
|
+
);
|
|
862
|
+
evaluationDetails = __spreadProps(__spreadValues({}, resolutionDetails), {
|
|
863
|
+
flagMetadata: Object.freeze((_a = resolutionDetails.flagMetadata) != null ? _a : {}),
|
|
864
|
+
flagKey
|
|
865
|
+
});
|
|
866
|
+
this.hookExecutor.afterHooks(provider.hooks, hookContext, evaluationDetails, hookHints);
|
|
867
|
+
} catch (error) {
|
|
868
|
+
this.hookExecutor.errorHooks(provider.hooks, hookContext, error, hookHints);
|
|
869
|
+
evaluationDetails = this.getErrorEvaluationDetails(flagKey, defaultValue, error);
|
|
870
|
+
}
|
|
871
|
+
this.hookExecutor.finallyHooks(provider.hooks, hookContext, evaluationDetails, hookHints);
|
|
872
|
+
return evaluationDetails;
|
|
873
|
+
}
|
|
874
|
+
callProviderResolve(provider, flagKey, defaultValue, context) {
|
|
875
|
+
switch (typeof defaultValue) {
|
|
876
|
+
case "string":
|
|
877
|
+
return provider.resolveStringEvaluation(flagKey, defaultValue, context, this.logger);
|
|
878
|
+
case "number":
|
|
879
|
+
return provider.resolveNumberEvaluation(flagKey, defaultValue, context, this.logger);
|
|
880
|
+
case "object":
|
|
881
|
+
return provider.resolveObjectEvaluation(flagKey, defaultValue, context, this.logger);
|
|
882
|
+
case "boolean":
|
|
883
|
+
return provider.resolveBooleanEvaluation(flagKey, defaultValue, context, this.logger);
|
|
884
|
+
default:
|
|
885
|
+
throw new import_core9.GeneralError("Invalid flag evaluation type");
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
get hooks() {
|
|
889
|
+
return [
|
|
890
|
+
{
|
|
891
|
+
before: (hookContext, hints) => {
|
|
892
|
+
this.hookContexts.set(hookContext.context, hookContext);
|
|
893
|
+
this.hookHints.set(hookContext.context, hints != null ? hints : {});
|
|
894
|
+
return hookContext.context;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
];
|
|
898
|
+
}
|
|
899
|
+
getErrorEvaluationDetails(flagKey, defaultValue, err, flagMetadata = {}) {
|
|
900
|
+
const errorMessage = err == null ? void 0 : err.message;
|
|
901
|
+
const errorCode = (err == null ? void 0 : err.code) || import_core9.ErrorCode.GENERAL;
|
|
902
|
+
return {
|
|
903
|
+
errorCode,
|
|
904
|
+
errorMessage,
|
|
905
|
+
value: defaultValue,
|
|
906
|
+
reason: import_core9.StandardResolutionReasons.ERROR,
|
|
907
|
+
flagMetadata: Object.freeze(flagMetadata),
|
|
908
|
+
flagKey
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
// src/open-feature.ts
|
|
914
|
+
var import_core11 = require("@openfeature/core");
|
|
397
915
|
|
|
398
916
|
// src/client/internal/open-feature-client.ts
|
|
399
|
-
var
|
|
917
|
+
var import_core10 = require("@openfeature/core");
|
|
400
918
|
var OpenFeatureClient = class {
|
|
401
919
|
constructor(providerAccessor, providerStatusAccessor, emitterAccessor, apiContextAccessor, apiHooksAccessor, globalLogger, options) {
|
|
402
920
|
this.providerAccessor = providerAccessor;
|
|
@@ -424,7 +942,7 @@ var OpenFeatureClient = class {
|
|
|
424
942
|
addHandler(eventType, handler, options) {
|
|
425
943
|
var _a;
|
|
426
944
|
this.emitterAccessor().addHandler(eventType, handler);
|
|
427
|
-
const shouldRunNow = (0,
|
|
945
|
+
const shouldRunNow = (0, import_core10.statusMatchesEvent)(eventType, this.providerStatus);
|
|
428
946
|
if (shouldRunNow) {
|
|
429
947
|
try {
|
|
430
948
|
handler({
|
|
@@ -449,7 +967,7 @@ var OpenFeatureClient = class {
|
|
|
449
967
|
return this.emitterAccessor().getHandlers(eventType);
|
|
450
968
|
}
|
|
451
969
|
setLogger(logger) {
|
|
452
|
-
this._clientLogger = new
|
|
970
|
+
this._clientLogger = new import_core10.SafeLogger(logger);
|
|
453
971
|
return this;
|
|
454
972
|
}
|
|
455
973
|
addHooks(...hooks) {
|
|
@@ -534,7 +1052,7 @@ var OpenFeatureClient = class {
|
|
|
534
1052
|
providerMetadata: this._provider.metadata,
|
|
535
1053
|
context,
|
|
536
1054
|
logger: this._logger,
|
|
537
|
-
hookData: new
|
|
1055
|
+
hookData: new import_core10.MapHookData()
|
|
538
1056
|
})
|
|
539
1057
|
);
|
|
540
1058
|
let evaluationDetails;
|
|
@@ -547,7 +1065,7 @@ var OpenFeatureClient = class {
|
|
|
547
1065
|
flagKey
|
|
548
1066
|
});
|
|
549
1067
|
if (resolutionDetails.errorCode) {
|
|
550
|
-
const err = (0,
|
|
1068
|
+
const err = (0, import_core10.instantiateErrorByErrorCode)(resolutionDetails.errorCode, resolutionDetails.errorMessage);
|
|
551
1069
|
this.errorHooks(allHooksReversed, hookContexts, err, options);
|
|
552
1070
|
evaluationDetails = this.getErrorEvaluationDetails(flagKey, defaultValue, err, resolutionDetails.flagMetadata);
|
|
553
1071
|
} else {
|
|
@@ -616,19 +1134,19 @@ var OpenFeatureClient = class {
|
|
|
616
1134
|
}
|
|
617
1135
|
shortCircuitIfNotReady() {
|
|
618
1136
|
if (this.providerStatus === import_core.ClientProviderStatus.NOT_READY) {
|
|
619
|
-
throw new
|
|
1137
|
+
throw new import_core10.ProviderNotReadyError("provider has not yet initialized");
|
|
620
1138
|
} else if (this.providerStatus === import_core.ClientProviderStatus.FATAL) {
|
|
621
|
-
throw new
|
|
1139
|
+
throw new import_core10.ProviderFatalError("provider is in an irrecoverable error state");
|
|
622
1140
|
}
|
|
623
1141
|
}
|
|
624
1142
|
getErrorEvaluationDetails(flagKey, defaultValue, err, flagMetadata = {}) {
|
|
625
1143
|
const errorMessage = err == null ? void 0 : err.message;
|
|
626
|
-
const errorCode = (err == null ? void 0 : err.code) ||
|
|
1144
|
+
const errorCode = (err == null ? void 0 : err.code) || import_core10.ErrorCode.GENERAL;
|
|
627
1145
|
return {
|
|
628
1146
|
errorCode,
|
|
629
1147
|
errorMessage,
|
|
630
1148
|
value: defaultValue,
|
|
631
|
-
reason:
|
|
1149
|
+
reason: import_core10.StandardResolutionReasons.ERROR,
|
|
632
1150
|
flagMetadata: Object.freeze(flagMetadata),
|
|
633
1151
|
flagKey
|
|
634
1152
|
};
|
|
@@ -638,12 +1156,12 @@ var OpenFeatureClient = class {
|
|
|
638
1156
|
// src/open-feature.ts
|
|
639
1157
|
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/web-sdk/api");
|
|
640
1158
|
var _globalThis = globalThis;
|
|
641
|
-
var OpenFeatureAPI = class _OpenFeatureAPI extends
|
|
1159
|
+
var OpenFeatureAPI = class _OpenFeatureAPI extends import_core11.OpenFeatureCommonAPI {
|
|
642
1160
|
constructor() {
|
|
643
1161
|
super("client");
|
|
644
1162
|
this._statusEnumType = import_core.ClientProviderStatus;
|
|
645
1163
|
this._apiEmitter = new OpenFeatureEventEmitter();
|
|
646
|
-
this._defaultProvider = new
|
|
1164
|
+
this._defaultProvider = new import_core11.ProviderWrapper(
|
|
647
1165
|
NOOP_PROVIDER,
|
|
648
1166
|
import_core.ClientProviderStatus.NOT_READY,
|
|
649
1167
|
this._statusEnumType
|
|
@@ -674,9 +1192,9 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends import_core7.OpenFeatureCommo
|
|
|
674
1192
|
}
|
|
675
1193
|
setProviderAndWait(clientOrProvider, providerContextOrUndefined, contextOrUndefined) {
|
|
676
1194
|
return __async(this, null, function* () {
|
|
677
|
-
const domain = (0,
|
|
678
|
-
const provider = domain ? (0,
|
|
679
|
-
const context = domain ? (0,
|
|
1195
|
+
const domain = (0, import_core11.stringOrUndefined)(clientOrProvider);
|
|
1196
|
+
const provider = domain ? (0, import_core11.objectOrUndefined)(providerContextOrUndefined) : (0, import_core11.objectOrUndefined)(clientOrProvider);
|
|
1197
|
+
const context = domain ? (0, import_core11.objectOrUndefined)(contextOrUndefined) : (0, import_core11.objectOrUndefined)(providerContextOrUndefined);
|
|
680
1198
|
if (context) {
|
|
681
1199
|
if (domain) {
|
|
682
1200
|
this._domainScopedContext.set(domain, context);
|
|
@@ -688,9 +1206,9 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends import_core7.OpenFeatureCommo
|
|
|
688
1206
|
});
|
|
689
1207
|
}
|
|
690
1208
|
setProvider(domainOrProvider, providerContextOrUndefined, contextOrUndefined) {
|
|
691
|
-
const domain = (0,
|
|
692
|
-
const provider = domain ? (0,
|
|
693
|
-
const context = domain ? (0,
|
|
1209
|
+
const domain = (0, import_core11.stringOrUndefined)(domainOrProvider);
|
|
1210
|
+
const provider = domain ? (0, import_core11.objectOrUndefined)(providerContextOrUndefined) : (0, import_core11.objectOrUndefined)(domainOrProvider);
|
|
1211
|
+
const context = domain ? (0, import_core11.objectOrUndefined)(contextOrUndefined) : (0, import_core11.objectOrUndefined)(providerContextOrUndefined);
|
|
694
1212
|
if (context) {
|
|
695
1213
|
if (domain) {
|
|
696
1214
|
this._domainScopedContext.set(domain, context);
|
|
@@ -710,8 +1228,8 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends import_core7.OpenFeatureCommo
|
|
|
710
1228
|
setContext(domainOrContext, contextOrUndefined) {
|
|
711
1229
|
return __async(this, null, function* () {
|
|
712
1230
|
var _a, _b;
|
|
713
|
-
const domain = (0,
|
|
714
|
-
const context = (_b = (_a = (0,
|
|
1231
|
+
const domain = (0, import_core11.stringOrUndefined)(domainOrContext);
|
|
1232
|
+
const context = (_b = (_a = (0, import_core11.objectOrUndefined)(domainOrContext)) != null ? _a : (0, import_core11.objectOrUndefined)(contextOrUndefined)) != null ? _b : {};
|
|
715
1233
|
if (domain) {
|
|
716
1234
|
const wrapper = this._domainScopedProviders.get(domain);
|
|
717
1235
|
if (wrapper) {
|
|
@@ -740,7 +1258,7 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends import_core7.OpenFeatureCommo
|
|
|
740
1258
|
});
|
|
741
1259
|
}
|
|
742
1260
|
getContext(domainOrUndefined) {
|
|
743
|
-
const domain = (0,
|
|
1261
|
+
const domain = (0, import_core11.stringOrUndefined)(domainOrUndefined);
|
|
744
1262
|
if (domain) {
|
|
745
1263
|
const context = this._domainScopedContext.get(domain);
|
|
746
1264
|
if (context) {
|
|
@@ -753,7 +1271,7 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends import_core7.OpenFeatureCommo
|
|
|
753
1271
|
}
|
|
754
1272
|
clearContext(domainOrUndefined) {
|
|
755
1273
|
return __async(this, null, function* () {
|
|
756
|
-
const domain = (0,
|
|
1274
|
+
const domain = (0, import_core11.stringOrUndefined)(domainOrUndefined);
|
|
757
1275
|
if (domain) {
|
|
758
1276
|
const wrapper = this._domainScopedProviders.get(domain);
|
|
759
1277
|
if (wrapper) {
|