@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/global/index.js
CHANGED
|
@@ -235,12 +235,18 @@ var OpenFeature = (() => {
|
|
|
235
235
|
// src/index.ts
|
|
236
236
|
var index_exports = {};
|
|
237
237
|
__export(index_exports, {
|
|
238
|
+
AggregateError: () => AggregateError,
|
|
238
239
|
AllProviderEvents: () => ClientProviderEvents,
|
|
239
240
|
AllProviderStatus: () => ClientProviderStatus,
|
|
241
|
+
BaseEvaluationStrategy: () => BaseEvaluationStrategy,
|
|
240
242
|
ClientProviderEvents: () => ClientProviderEvents,
|
|
241
243
|
ClientProviderStatus: () => ClientProviderStatus,
|
|
244
|
+
ComparisonStrategy: () => ComparisonStrategy,
|
|
242
245
|
DefaultLogger: () => DefaultLogger,
|
|
243
246
|
ErrorCode: () => ErrorCode,
|
|
247
|
+
ErrorWithCode: () => ErrorWithCode,
|
|
248
|
+
FirstMatchStrategy: () => FirstMatchStrategy,
|
|
249
|
+
FirstSuccessfulStrategy: () => FirstSuccessfulStrategy,
|
|
244
250
|
FlagNotFoundError: () => FlagNotFoundError,
|
|
245
251
|
GeneralError: () => GeneralError,
|
|
246
252
|
GenericEventEmitter: () => GenericEventEmitter,
|
|
@@ -248,6 +254,7 @@ var OpenFeature = (() => {
|
|
|
248
254
|
InvalidContextError: () => InvalidContextError,
|
|
249
255
|
LOG_LEVELS: () => LOG_LEVELS,
|
|
250
256
|
MapHookData: () => MapHookData,
|
|
257
|
+
MultiProvider: () => MultiProvider,
|
|
251
258
|
NOOP_PROVIDER: () => NOOP_PROVIDER,
|
|
252
259
|
OpenFeature: () => OpenFeature,
|
|
253
260
|
OpenFeatureAPI: () => OpenFeatureAPI,
|
|
@@ -268,13 +275,15 @@ var OpenFeature = (() => {
|
|
|
268
275
|
TelemetryAttribute: () => TelemetryAttribute,
|
|
269
276
|
TelemetryFlagMetadata: () => TelemetryFlagMetadata,
|
|
270
277
|
TypeMismatchError: () => TypeMismatchError,
|
|
278
|
+
constructAggregateError: () => constructAggregateError,
|
|
271
279
|
createEvaluationEvent: () => createEvaluationEvent,
|
|
272
280
|
instantiateErrorByErrorCode: () => instantiateErrorByErrorCode,
|
|
273
281
|
isObject: () => isObject,
|
|
274
282
|
isString: () => isString,
|
|
275
283
|
objectOrUndefined: () => objectOrUndefined,
|
|
276
284
|
statusMatchesEvent: () => statusMatchesEvent,
|
|
277
|
-
stringOrUndefined: () => stringOrUndefined
|
|
285
|
+
stringOrUndefined: () => stringOrUndefined,
|
|
286
|
+
throwAggregateErrorFromPromiseResults: () => throwAggregateErrorFromPromiseResults
|
|
278
287
|
});
|
|
279
288
|
|
|
280
289
|
// ../shared/src/hooks/hook-data.ts
|
|
@@ -1259,6 +1268,509 @@ var OpenFeature = (() => {
|
|
|
1259
1268
|
}
|
|
1260
1269
|
};
|
|
1261
1270
|
|
|
1271
|
+
// src/provider/multi-provider/hook-executor.ts
|
|
1272
|
+
var HookExecutor = class {
|
|
1273
|
+
constructor(logger) {
|
|
1274
|
+
this.logger = logger;
|
|
1275
|
+
}
|
|
1276
|
+
beforeHooks(hooks, hookContext, hints) {
|
|
1277
|
+
var _a;
|
|
1278
|
+
for (const hook of hooks != null ? hooks : []) {
|
|
1279
|
+
(_a = hook == null ? void 0 : hook.before) == null ? void 0 : _a.call(hook, hookContext, Object.freeze(hints));
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
afterHooks(hooks, hookContext, evaluationDetails, hints) {
|
|
1283
|
+
var _a;
|
|
1284
|
+
for (const hook of hooks != null ? hooks : []) {
|
|
1285
|
+
(_a = hook == null ? void 0 : hook.after) == null ? void 0 : _a.call(hook, hookContext, evaluationDetails, hints);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
errorHooks(hooks, hookContext, err, hints) {
|
|
1289
|
+
var _a;
|
|
1290
|
+
for (const hook of hooks != null ? hooks : []) {
|
|
1291
|
+
try {
|
|
1292
|
+
(_a = hook == null ? void 0 : hook.error) == null ? void 0 : _a.call(hook, hookContext, err, hints);
|
|
1293
|
+
} catch (err2) {
|
|
1294
|
+
this.logger.error(`Unhandled error during 'error' hook: ${err2}`);
|
|
1295
|
+
if (err2 instanceof Error) {
|
|
1296
|
+
this.logger.error(err2.stack);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
finallyHooks(hooks, hookContext, evaluationDetails, hints) {
|
|
1302
|
+
var _a;
|
|
1303
|
+
for (const hook of hooks != null ? hooks : []) {
|
|
1304
|
+
try {
|
|
1305
|
+
(_a = hook == null ? void 0 : hook.finally) == null ? void 0 : _a.call(hook, hookContext, evaluationDetails, hints);
|
|
1306
|
+
} catch (err) {
|
|
1307
|
+
this.logger.error(`Unhandled error during 'finally' hook: ${err}`);
|
|
1308
|
+
if (err instanceof Error) {
|
|
1309
|
+
this.logger.error(err.stack);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1316
|
+
// src/provider/multi-provider/errors.ts
|
|
1317
|
+
var ErrorWithCode = class extends OpenFeatureError {
|
|
1318
|
+
constructor(code, message) {
|
|
1319
|
+
super(message);
|
|
1320
|
+
this.code = code;
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
var AggregateError = class extends GeneralError {
|
|
1324
|
+
constructor(message, originalErrors) {
|
|
1325
|
+
super(message);
|
|
1326
|
+
this.originalErrors = originalErrors;
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
var constructAggregateError = (providerErrors) => {
|
|
1330
|
+
const errorsWithSource = providerErrors.map(({ providerName, error }) => {
|
|
1331
|
+
return { source: providerName, error };
|
|
1332
|
+
}).flat();
|
|
1333
|
+
return new AggregateError(
|
|
1334
|
+
`Provider errors occurred: ${errorsWithSource[0].source}: ${errorsWithSource[0].error}`,
|
|
1335
|
+
errorsWithSource
|
|
1336
|
+
);
|
|
1337
|
+
};
|
|
1338
|
+
var throwAggregateErrorFromPromiseResults = (result, providerEntries) => {
|
|
1339
|
+
const errors = result.map((r, i) => {
|
|
1340
|
+
if (r.status === "rejected") {
|
|
1341
|
+
return { error: r.reason, providerName: providerEntries[i].name };
|
|
1342
|
+
}
|
|
1343
|
+
return null;
|
|
1344
|
+
}).filter((val) => Boolean(val));
|
|
1345
|
+
if (errors.length) {
|
|
1346
|
+
throw constructAggregateError(errors);
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1350
|
+
// src/provider/multi-provider/strategies/base-evaluation-strategy.ts
|
|
1351
|
+
var BaseEvaluationStrategy = class {
|
|
1352
|
+
shouldEvaluateThisProvider(strategyContext, _evalContext) {
|
|
1353
|
+
if (strategyContext.providerStatus === "NOT_READY" /* NOT_READY */ || strategyContext.providerStatus === "FATAL" /* FATAL */) {
|
|
1354
|
+
return false;
|
|
1355
|
+
}
|
|
1356
|
+
return true;
|
|
1357
|
+
}
|
|
1358
|
+
shouldEvaluateNextProvider(_strategyContext, _context, _result) {
|
|
1359
|
+
return true;
|
|
1360
|
+
}
|
|
1361
|
+
shouldTrackWithThisProvider(strategyContext, _context, _trackingEventName, _trackingEventDetails) {
|
|
1362
|
+
if (strategyContext.providerStatus === "NOT_READY" /* NOT_READY */ || strategyContext.providerStatus === "FATAL" /* FATAL */) {
|
|
1363
|
+
return false;
|
|
1364
|
+
}
|
|
1365
|
+
return true;
|
|
1366
|
+
}
|
|
1367
|
+
hasError(resolution) {
|
|
1368
|
+
return "thrownError" in resolution || !!resolution.details.errorCode;
|
|
1369
|
+
}
|
|
1370
|
+
hasErrorWithCode(resolution, code) {
|
|
1371
|
+
var _a;
|
|
1372
|
+
return "thrownError" in resolution ? ((_a = resolution.thrownError) == null ? void 0 : _a.code) === code : resolution.details.errorCode === code;
|
|
1373
|
+
}
|
|
1374
|
+
collectProviderErrors(resolutions) {
|
|
1375
|
+
var _a;
|
|
1376
|
+
const errors = [];
|
|
1377
|
+
for (const resolution of resolutions) {
|
|
1378
|
+
if ("thrownError" in resolution) {
|
|
1379
|
+
errors.push({ providerName: resolution.providerName, error: resolution.thrownError });
|
|
1380
|
+
} else if (resolution.details.errorCode) {
|
|
1381
|
+
errors.push({
|
|
1382
|
+
providerName: resolution.providerName,
|
|
1383
|
+
error: new ErrorWithCode(resolution.details.errorCode, (_a = resolution.details.errorMessage) != null ? _a : "unknown error")
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
return { errors };
|
|
1388
|
+
}
|
|
1389
|
+
resolutionToFinalResult(resolution) {
|
|
1390
|
+
return { details: resolution.details, provider: resolution.provider, providerName: resolution.providerName };
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
|
|
1394
|
+
// src/provider/multi-provider/strategies/first-match-strategy.ts
|
|
1395
|
+
var FirstMatchStrategy = class extends BaseEvaluationStrategy {
|
|
1396
|
+
shouldEvaluateNextProvider(strategyContext, context, result) {
|
|
1397
|
+
if (this.hasErrorWithCode(result, "FLAG_NOT_FOUND" /* FLAG_NOT_FOUND */)) {
|
|
1398
|
+
return true;
|
|
1399
|
+
}
|
|
1400
|
+
if (this.hasError(result)) {
|
|
1401
|
+
return false;
|
|
1402
|
+
}
|
|
1403
|
+
return false;
|
|
1404
|
+
}
|
|
1405
|
+
determineFinalResult(strategyContext, context, resolutions) {
|
|
1406
|
+
const finalResolution = resolutions[resolutions.length - 1];
|
|
1407
|
+
if (this.hasError(finalResolution)) {
|
|
1408
|
+
return this.collectProviderErrors(resolutions);
|
|
1409
|
+
}
|
|
1410
|
+
return this.resolutionToFinalResult(finalResolution);
|
|
1411
|
+
}
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1414
|
+
// src/provider/multi-provider/strategies/first-successful-strategy.ts
|
|
1415
|
+
var FirstSuccessfulStrategy = class extends BaseEvaluationStrategy {
|
|
1416
|
+
shouldEvaluateNextProvider(strategyContext, context, result) {
|
|
1417
|
+
return this.hasError(result);
|
|
1418
|
+
}
|
|
1419
|
+
determineFinalResult(strategyContext, context, resolutions) {
|
|
1420
|
+
const finalResolution = resolutions[resolutions.length - 1];
|
|
1421
|
+
if (this.hasError(finalResolution)) {
|
|
1422
|
+
return this.collectProviderErrors(resolutions);
|
|
1423
|
+
}
|
|
1424
|
+
return this.resolutionToFinalResult(finalResolution);
|
|
1425
|
+
}
|
|
1426
|
+
};
|
|
1427
|
+
|
|
1428
|
+
// src/provider/multi-provider/strategies/comparison-strategy.ts
|
|
1429
|
+
var ComparisonStrategy = class extends BaseEvaluationStrategy {
|
|
1430
|
+
constructor(fallbackProvider, onMismatch) {
|
|
1431
|
+
super();
|
|
1432
|
+
this.fallbackProvider = fallbackProvider;
|
|
1433
|
+
this.onMismatch = onMismatch;
|
|
1434
|
+
}
|
|
1435
|
+
determineFinalResult(strategyContext, context, resolutions) {
|
|
1436
|
+
var _a;
|
|
1437
|
+
let value;
|
|
1438
|
+
let fallbackResolution;
|
|
1439
|
+
let finalResolution;
|
|
1440
|
+
let mismatch = false;
|
|
1441
|
+
for (const [i, resolution] of resolutions.entries()) {
|
|
1442
|
+
if (this.hasError(resolution)) {
|
|
1443
|
+
return this.collectProviderErrors(resolutions);
|
|
1444
|
+
}
|
|
1445
|
+
if (resolution.provider === this.fallbackProvider) {
|
|
1446
|
+
fallbackResolution = resolution;
|
|
1447
|
+
}
|
|
1448
|
+
if (i === 0) {
|
|
1449
|
+
finalResolution = resolution;
|
|
1450
|
+
}
|
|
1451
|
+
if (typeof value !== "undefined" && value !== resolution.details.value) {
|
|
1452
|
+
mismatch = true;
|
|
1453
|
+
} else {
|
|
1454
|
+
value = resolution.details.value;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
if (!fallbackResolution) {
|
|
1458
|
+
throw new GeneralError("Fallback provider not found in resolution results");
|
|
1459
|
+
}
|
|
1460
|
+
if (!finalResolution) {
|
|
1461
|
+
throw new GeneralError("Final resolution not found in resolution results");
|
|
1462
|
+
}
|
|
1463
|
+
if (mismatch) {
|
|
1464
|
+
(_a = this.onMismatch) == null ? void 0 : _a.call(this, resolutions);
|
|
1465
|
+
return {
|
|
1466
|
+
details: fallbackResolution.details,
|
|
1467
|
+
provider: fallbackResolution.provider
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
return this.resolutionToFinalResult(finalResolution);
|
|
1471
|
+
}
|
|
1472
|
+
};
|
|
1473
|
+
|
|
1474
|
+
// src/provider/multi-provider/status-tracker.ts
|
|
1475
|
+
var StatusTracker = class {
|
|
1476
|
+
constructor(events) {
|
|
1477
|
+
this.events = events;
|
|
1478
|
+
this.providerStatuses = {};
|
|
1479
|
+
}
|
|
1480
|
+
wrapEventHandler(providerEntry) {
|
|
1481
|
+
var _a, _b, _c, _d, _e;
|
|
1482
|
+
const provider = providerEntry.provider;
|
|
1483
|
+
(_a = provider.events) == null ? void 0 : _a.addHandler("PROVIDER_ERROR" /* Error */, (details) => {
|
|
1484
|
+
this.changeProviderStatus(providerEntry.name, "ERROR" /* ERROR */, details);
|
|
1485
|
+
});
|
|
1486
|
+
(_b = provider.events) == null ? void 0 : _b.addHandler("PROVIDER_STALE" /* Stale */, (details) => {
|
|
1487
|
+
this.changeProviderStatus(providerEntry.name, "STALE" /* STALE */, details);
|
|
1488
|
+
});
|
|
1489
|
+
(_c = provider.events) == null ? void 0 : _c.addHandler("PROVIDER_CONFIGURATION_CHANGED" /* ConfigurationChanged */, (details) => {
|
|
1490
|
+
this.events.emit("PROVIDER_CONFIGURATION_CHANGED" /* ConfigurationChanged */, details);
|
|
1491
|
+
});
|
|
1492
|
+
(_d = provider.events) == null ? void 0 : _d.addHandler("PROVIDER_READY" /* Ready */, (details) => {
|
|
1493
|
+
this.changeProviderStatus(providerEntry.name, "READY" /* READY */, details);
|
|
1494
|
+
});
|
|
1495
|
+
(_e = provider.events) == null ? void 0 : _e.addHandler("PROVIDER_RECONCILING" /* Reconciling */, (details) => {
|
|
1496
|
+
this.changeProviderStatus(providerEntry.name, "RECONCILING" /* RECONCILING */, details);
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
providerStatus(name) {
|
|
1500
|
+
return this.providerStatuses[name];
|
|
1501
|
+
}
|
|
1502
|
+
getStatusFromProviderStatuses() {
|
|
1503
|
+
const statuses = Object.values(this.providerStatuses);
|
|
1504
|
+
if (statuses.includes("FATAL" /* FATAL */)) {
|
|
1505
|
+
return "FATAL" /* FATAL */;
|
|
1506
|
+
} else if (statuses.includes("NOT_READY" /* NOT_READY */)) {
|
|
1507
|
+
return "NOT_READY" /* NOT_READY */;
|
|
1508
|
+
} else if (statuses.includes("ERROR" /* ERROR */)) {
|
|
1509
|
+
return "ERROR" /* ERROR */;
|
|
1510
|
+
} else if (statuses.includes("STALE" /* STALE */)) {
|
|
1511
|
+
return "STALE" /* STALE */;
|
|
1512
|
+
} else if (statuses.includes("RECONCILING" /* RECONCILING */)) {
|
|
1513
|
+
return "RECONCILING" /* RECONCILING */;
|
|
1514
|
+
}
|
|
1515
|
+
return "READY" /* READY */;
|
|
1516
|
+
}
|
|
1517
|
+
changeProviderStatus(name, status, details) {
|
|
1518
|
+
const currentStatus = this.getStatusFromProviderStatuses();
|
|
1519
|
+
this.providerStatuses[name] = status;
|
|
1520
|
+
const newStatus = this.getStatusFromProviderStatuses();
|
|
1521
|
+
if (currentStatus !== newStatus) {
|
|
1522
|
+
if (newStatus === "FATAL" /* FATAL */ || newStatus === "ERROR" /* ERROR */) {
|
|
1523
|
+
this.events.emit("PROVIDER_ERROR" /* Error */, details);
|
|
1524
|
+
} else if (newStatus === "STALE" /* STALE */) {
|
|
1525
|
+
this.events.emit("PROVIDER_STALE" /* Stale */, details);
|
|
1526
|
+
} else if (newStatus === "READY" /* READY */) {
|
|
1527
|
+
this.events.emit("PROVIDER_READY" /* Ready */, details);
|
|
1528
|
+
} else if (newStatus === "RECONCILING" /* RECONCILING */) {
|
|
1529
|
+
this.events.emit("PROVIDER_RECONCILING" /* Reconciling */, details);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
// src/provider/multi-provider/multi-provider-web.ts
|
|
1536
|
+
var MultiProvider = class _MultiProvider {
|
|
1537
|
+
constructor(constructorProviders, evaluationStrategy = new FirstMatchStrategy(), logger = new DefaultLogger()) {
|
|
1538
|
+
this.constructorProviders = constructorProviders;
|
|
1539
|
+
this.evaluationStrategy = evaluationStrategy;
|
|
1540
|
+
this.logger = logger;
|
|
1541
|
+
this.runsOn = "client";
|
|
1542
|
+
this.events = new OpenFeatureEventEmitter();
|
|
1543
|
+
this.hookContexts = /* @__PURE__ */ new WeakMap();
|
|
1544
|
+
this.hookHints = /* @__PURE__ */ new WeakMap();
|
|
1545
|
+
this.providerEntries = [];
|
|
1546
|
+
this.providerEntriesByName = {};
|
|
1547
|
+
this.statusTracker = new StatusTracker(this.events);
|
|
1548
|
+
this.hookExecutor = new HookExecutor(this.logger);
|
|
1549
|
+
this.registerProviders(constructorProviders);
|
|
1550
|
+
const aggregateMetadata = Object.keys(this.providerEntriesByName).reduce((acc, name) => {
|
|
1551
|
+
return __spreadProps(__spreadValues({}, acc), { [name]: this.providerEntriesByName[name].provider.metadata });
|
|
1552
|
+
}, {});
|
|
1553
|
+
this.metadata = __spreadProps(__spreadValues({}, aggregateMetadata), {
|
|
1554
|
+
name: _MultiProvider.name
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
registerProviders(constructorProviders) {
|
|
1558
|
+
var _a, _b;
|
|
1559
|
+
const providersByName = {};
|
|
1560
|
+
for (const constructorProvider of constructorProviders) {
|
|
1561
|
+
const providerName = constructorProvider.provider.metadata.name;
|
|
1562
|
+
const candidateName = (_a = constructorProvider.name) != null ? _a : providerName;
|
|
1563
|
+
if (constructorProvider.name && providersByName[constructorProvider.name]) {
|
|
1564
|
+
throw new Error("Provider names must be unique");
|
|
1565
|
+
}
|
|
1566
|
+
(_b = providersByName[candidateName]) != null ? _b : providersByName[candidateName] = [];
|
|
1567
|
+
providersByName[candidateName].push(constructorProvider.provider);
|
|
1568
|
+
}
|
|
1569
|
+
for (const name of Object.keys(providersByName)) {
|
|
1570
|
+
const useIndexedNames = providersByName[name].length > 1;
|
|
1571
|
+
for (let i = 0; i < providersByName[name].length; i++) {
|
|
1572
|
+
const indexedName = useIndexedNames ? `${name}-${i + 1}` : name;
|
|
1573
|
+
this.providerEntriesByName[indexedName] = { provider: providersByName[name][i], name: indexedName };
|
|
1574
|
+
this.providerEntries.push(this.providerEntriesByName[indexedName]);
|
|
1575
|
+
this.statusTracker.wrapEventHandler(this.providerEntriesByName[indexedName]);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
Object.freeze(this.providerEntries);
|
|
1579
|
+
Object.freeze(this.providerEntriesByName);
|
|
1580
|
+
}
|
|
1581
|
+
initialize(context) {
|
|
1582
|
+
return __async(this, null, function* () {
|
|
1583
|
+
const result = yield Promise.allSettled(
|
|
1584
|
+
this.providerEntries.map((provider) => {
|
|
1585
|
+
var _a, _b;
|
|
1586
|
+
return (_b = (_a = provider.provider).initialize) == null ? void 0 : _b.call(_a, context);
|
|
1587
|
+
})
|
|
1588
|
+
);
|
|
1589
|
+
throwAggregateErrorFromPromiseResults(result, this.providerEntries);
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
onClose() {
|
|
1593
|
+
return __async(this, null, function* () {
|
|
1594
|
+
const result = yield Promise.allSettled(this.providerEntries.map((provider) => {
|
|
1595
|
+
var _a, _b;
|
|
1596
|
+
return (_b = (_a = provider.provider).onClose) == null ? void 0 : _b.call(_a);
|
|
1597
|
+
}));
|
|
1598
|
+
throwAggregateErrorFromPromiseResults(result, this.providerEntries);
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
onContextChange(oldContext, newContext) {
|
|
1602
|
+
return __async(this, null, function* () {
|
|
1603
|
+
var _a, _b;
|
|
1604
|
+
for (const providerEntry of this.providerEntries) {
|
|
1605
|
+
yield (_b = (_a = providerEntry.provider).onContextChange) == null ? void 0 : _b.call(_a, oldContext, newContext);
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
resolveBooleanEvaluation(flagKey, defaultValue, context) {
|
|
1610
|
+
return this.flagResolutionProxy(flagKey, "boolean", defaultValue, context);
|
|
1611
|
+
}
|
|
1612
|
+
resolveStringEvaluation(flagKey, defaultValue, context) {
|
|
1613
|
+
return this.flagResolutionProxy(flagKey, "string", defaultValue, context);
|
|
1614
|
+
}
|
|
1615
|
+
resolveNumberEvaluation(flagKey, defaultValue, context) {
|
|
1616
|
+
return this.flagResolutionProxy(flagKey, "number", defaultValue, context);
|
|
1617
|
+
}
|
|
1618
|
+
resolveObjectEvaluation(flagKey, defaultValue, context) {
|
|
1619
|
+
return this.flagResolutionProxy(flagKey, "object", defaultValue, context);
|
|
1620
|
+
}
|
|
1621
|
+
track(trackingEventName, context, trackingEventDetails) {
|
|
1622
|
+
var _a, _b;
|
|
1623
|
+
for (const providerEntry of this.providerEntries) {
|
|
1624
|
+
if (!providerEntry.provider.track) {
|
|
1625
|
+
continue;
|
|
1626
|
+
}
|
|
1627
|
+
const strategyContext = {
|
|
1628
|
+
provider: providerEntry.provider,
|
|
1629
|
+
providerName: providerEntry.name,
|
|
1630
|
+
providerStatus: this.statusTracker.providerStatus(providerEntry.name)
|
|
1631
|
+
};
|
|
1632
|
+
if (this.evaluationStrategy.shouldTrackWithThisProvider(
|
|
1633
|
+
strategyContext,
|
|
1634
|
+
context,
|
|
1635
|
+
trackingEventName,
|
|
1636
|
+
trackingEventDetails
|
|
1637
|
+
)) {
|
|
1638
|
+
try {
|
|
1639
|
+
(_b = (_a = providerEntry.provider).track) == null ? void 0 : _b.call(_a, trackingEventName, context, trackingEventDetails);
|
|
1640
|
+
} catch (error) {
|
|
1641
|
+
this.logger.error(
|
|
1642
|
+
`Error tracking event "${trackingEventName}" with provider "${providerEntry.name}":`,
|
|
1643
|
+
error
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
flagResolutionProxy(flagKey, flagType, defaultValue, context) {
|
|
1650
|
+
var _a;
|
|
1651
|
+
const hookContext = this.hookContexts.get(context);
|
|
1652
|
+
const hookHints = this.hookHints.get(context);
|
|
1653
|
+
if (!hookContext || !hookHints) {
|
|
1654
|
+
throw new GeneralError("Hook context not available for evaluation");
|
|
1655
|
+
}
|
|
1656
|
+
const results = [];
|
|
1657
|
+
for (const providerEntry of this.providerEntries) {
|
|
1658
|
+
const [shouldEvaluateNext, result] = this.evaluateProviderEntry(
|
|
1659
|
+
flagKey,
|
|
1660
|
+
flagType,
|
|
1661
|
+
defaultValue,
|
|
1662
|
+
providerEntry,
|
|
1663
|
+
hookContext,
|
|
1664
|
+
hookHints,
|
|
1665
|
+
context
|
|
1666
|
+
);
|
|
1667
|
+
results.push(result);
|
|
1668
|
+
if (!shouldEvaluateNext) {
|
|
1669
|
+
break;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
const resolutions = results.filter((r) => Boolean(r));
|
|
1673
|
+
const finalResult = this.evaluationStrategy.determineFinalResult({ flagKey, flagType }, context, resolutions);
|
|
1674
|
+
if ((_a = finalResult.errors) == null ? void 0 : _a.length) {
|
|
1675
|
+
throw constructAggregateError(finalResult.errors);
|
|
1676
|
+
}
|
|
1677
|
+
if (!finalResult.details) {
|
|
1678
|
+
throw new GeneralError("No result was returned from any provider");
|
|
1679
|
+
}
|
|
1680
|
+
return finalResult.details;
|
|
1681
|
+
}
|
|
1682
|
+
evaluateProviderEntry(flagKey, flagType, defaultValue, providerEntry, hookContext, hookHints, context) {
|
|
1683
|
+
let evaluationResult = void 0;
|
|
1684
|
+
const provider = providerEntry.provider;
|
|
1685
|
+
const strategyContext = {
|
|
1686
|
+
flagKey,
|
|
1687
|
+
flagType,
|
|
1688
|
+
provider,
|
|
1689
|
+
providerName: providerEntry.name,
|
|
1690
|
+
providerStatus: this.statusTracker.providerStatus(providerEntry.name)
|
|
1691
|
+
};
|
|
1692
|
+
if (!this.evaluationStrategy.shouldEvaluateThisProvider(strategyContext, context)) {
|
|
1693
|
+
return [true, null];
|
|
1694
|
+
}
|
|
1695
|
+
let resolution;
|
|
1696
|
+
try {
|
|
1697
|
+
evaluationResult = this.evaluateProviderAndHooks(flagKey, defaultValue, provider, hookContext, hookHints);
|
|
1698
|
+
resolution = {
|
|
1699
|
+
details: evaluationResult,
|
|
1700
|
+
provider,
|
|
1701
|
+
providerName: providerEntry.name
|
|
1702
|
+
};
|
|
1703
|
+
} catch (error) {
|
|
1704
|
+
resolution = {
|
|
1705
|
+
thrownError: error,
|
|
1706
|
+
provider,
|
|
1707
|
+
providerName: providerEntry.name
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
return [this.evaluationStrategy.shouldEvaluateNextProvider(strategyContext, context, resolution), resolution];
|
|
1711
|
+
}
|
|
1712
|
+
evaluateProviderAndHooks(flagKey, defaultValue, provider, hookContext, hookHints) {
|
|
1713
|
+
var _a;
|
|
1714
|
+
let evaluationDetails;
|
|
1715
|
+
try {
|
|
1716
|
+
this.hookExecutor.beforeHooks(provider.hooks, hookContext, hookHints);
|
|
1717
|
+
const resolutionDetails = this.callProviderResolve(
|
|
1718
|
+
provider,
|
|
1719
|
+
flagKey,
|
|
1720
|
+
defaultValue,
|
|
1721
|
+
hookContext.context
|
|
1722
|
+
);
|
|
1723
|
+
evaluationDetails = __spreadProps(__spreadValues({}, resolutionDetails), {
|
|
1724
|
+
flagMetadata: Object.freeze((_a = resolutionDetails.flagMetadata) != null ? _a : {}),
|
|
1725
|
+
flagKey
|
|
1726
|
+
});
|
|
1727
|
+
this.hookExecutor.afterHooks(provider.hooks, hookContext, evaluationDetails, hookHints);
|
|
1728
|
+
} catch (error) {
|
|
1729
|
+
this.hookExecutor.errorHooks(provider.hooks, hookContext, error, hookHints);
|
|
1730
|
+
evaluationDetails = this.getErrorEvaluationDetails(flagKey, defaultValue, error);
|
|
1731
|
+
}
|
|
1732
|
+
this.hookExecutor.finallyHooks(provider.hooks, hookContext, evaluationDetails, hookHints);
|
|
1733
|
+
return evaluationDetails;
|
|
1734
|
+
}
|
|
1735
|
+
callProviderResolve(provider, flagKey, defaultValue, context) {
|
|
1736
|
+
switch (typeof defaultValue) {
|
|
1737
|
+
case "string":
|
|
1738
|
+
return provider.resolveStringEvaluation(flagKey, defaultValue, context, this.logger);
|
|
1739
|
+
case "number":
|
|
1740
|
+
return provider.resolveNumberEvaluation(flagKey, defaultValue, context, this.logger);
|
|
1741
|
+
case "object":
|
|
1742
|
+
return provider.resolveObjectEvaluation(flagKey, defaultValue, context, this.logger);
|
|
1743
|
+
case "boolean":
|
|
1744
|
+
return provider.resolveBooleanEvaluation(flagKey, defaultValue, context, this.logger);
|
|
1745
|
+
default:
|
|
1746
|
+
throw new GeneralError("Invalid flag evaluation type");
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
get hooks() {
|
|
1750
|
+
return [
|
|
1751
|
+
{
|
|
1752
|
+
before: (hookContext, hints) => {
|
|
1753
|
+
this.hookContexts.set(hookContext.context, hookContext);
|
|
1754
|
+
this.hookHints.set(hookContext.context, hints != null ? hints : {});
|
|
1755
|
+
return hookContext.context;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
];
|
|
1759
|
+
}
|
|
1760
|
+
getErrorEvaluationDetails(flagKey, defaultValue, err, flagMetadata = {}) {
|
|
1761
|
+
const errorMessage = err == null ? void 0 : err.message;
|
|
1762
|
+
const errorCode = (err == null ? void 0 : err.code) || "GENERAL" /* GENERAL */;
|
|
1763
|
+
return {
|
|
1764
|
+
errorCode,
|
|
1765
|
+
errorMessage,
|
|
1766
|
+
value: defaultValue,
|
|
1767
|
+
reason: StandardResolutionReasons.ERROR,
|
|
1768
|
+
flagMetadata: Object.freeze(flagMetadata),
|
|
1769
|
+
flagKey
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
|
|
1262
1774
|
// src/client/internal/open-feature-client.ts
|
|
1263
1775
|
var OpenFeatureClient = class {
|
|
1264
1776
|
constructor(providerAccessor, providerStatusAccessor, emitterAccessor, apiContextAccessor, apiHooksAccessor, globalLogger, options) {
|