superposition-provider 0.104.0 → 0.106.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/configuration-client.d.ts +3 -1
- package/dist/experimentation-client.d.ts +4 -1
- package/dist/index.esm.js +145 -49
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +145 -49
- package/dist/index.js.map +1 -1
- package/dist/native-lib/libsuperposition_core-aarch64-apple-darwin.dylib +0 -0
- package/dist/native-lib/libsuperposition_core-x86_64-apple-darwin.dylib +0 -0
- package/dist/native-lib/libsuperposition_core-x86_64-pc-windows-msvc.dll +0 -0
- package/dist/native-lib/libsuperposition_core-x86_64-unknown-linux-gnu.so +0 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3183,7 +3183,7 @@ var runtimeConfig = {};
|
|
|
3183
3183
|
|
|
3184
3184
|
var name = "superposition-sdk";
|
|
3185
3185
|
var description = "superposition-sdk client";
|
|
3186
|
-
var version = "0.
|
|
3186
|
+
var version = "0.106.0";
|
|
3187
3187
|
var repository = {
|
|
3188
3188
|
type: "git",
|
|
3189
3189
|
url: "git+https://github.com/juspay/superposition.git"
|
|
@@ -16392,13 +16392,14 @@ function requireModels () {
|
|
|
16392
16392
|
} (superpositionSdk));
|
|
16393
16393
|
|
|
16394
16394
|
class ExperimentationClient {
|
|
16395
|
-
constructor(superpositionOptions, experimentOptions) {
|
|
16395
|
+
constructor(superpositionOptions, experimentOptions, onExperimentsChange) {
|
|
16396
16396
|
this.superpositionOptions = superpositionOptions;
|
|
16397
16397
|
this.cachedExperiments = null;
|
|
16398
16398
|
this.cachedExperimentGroups = null;
|
|
16399
16399
|
this.lastUpdated = null;
|
|
16400
16400
|
this.evaluationCache = new Map();
|
|
16401
16401
|
this.options = experimentOptions;
|
|
16402
|
+
this.onExperimentsChange = onExperimentsChange;
|
|
16402
16403
|
this.smithyClient = new superpositionSdk.SuperpositionClient({
|
|
16403
16404
|
endpoint: superpositionOptions.endpoint,
|
|
16404
16405
|
token: { token: superpositionOptions.token },
|
|
@@ -16412,6 +16413,7 @@ class ExperimentationClient {
|
|
|
16412
16413
|
if (experiments && experimentgroups) {
|
|
16413
16414
|
this.cachedExperiments = experiments;
|
|
16414
16415
|
this.cachedExperimentGroups = experimentgroups;
|
|
16416
|
+
this.onExperimentsChange?.();
|
|
16415
16417
|
this.lastUpdated = new Date();
|
|
16416
16418
|
console.log("Experiments and Experiment Groups fetched successfully.");
|
|
16417
16419
|
}
|
|
@@ -16423,21 +16425,28 @@ class ExperimentationClient {
|
|
|
16423
16425
|
}
|
|
16424
16426
|
}
|
|
16425
16427
|
startPolling(interval) {
|
|
16426
|
-
|
|
16428
|
+
const weakSelf = new WeakRef(this);
|
|
16429
|
+
const poll = async () => {
|
|
16430
|
+
const self = weakSelf.deref();
|
|
16431
|
+
if (!self)
|
|
16432
|
+
return;
|
|
16427
16433
|
try {
|
|
16428
|
-
const experiments = await
|
|
16429
|
-
const experimentGroups = await
|
|
16434
|
+
const experiments = await self.fetchExperiments();
|
|
16435
|
+
const experimentGroups = await self.fetchExperimentGroups();
|
|
16430
16436
|
if (experiments && experimentGroups) {
|
|
16431
|
-
|
|
16432
|
-
|
|
16433
|
-
|
|
16437
|
+
self.cachedExperiments = experiments;
|
|
16438
|
+
self.cachedExperimentGroups = experimentGroups;
|
|
16439
|
+
self.lastUpdated = new Date();
|
|
16434
16440
|
console.log("Experiments and Experiment Groups refreshed successfully.");
|
|
16441
|
+
self.onExperimentsChange?.();
|
|
16435
16442
|
}
|
|
16436
16443
|
}
|
|
16437
16444
|
catch (error) {
|
|
16438
16445
|
console.error("Polling error:", error);
|
|
16439
16446
|
}
|
|
16440
|
-
|
|
16447
|
+
self.pollingInterval = setTimeout(poll, interval);
|
|
16448
|
+
};
|
|
16449
|
+
this.pollingInterval = setTimeout(poll, interval);
|
|
16441
16450
|
}
|
|
16442
16451
|
async fetchExperiments() {
|
|
16443
16452
|
try {
|
|
@@ -16490,7 +16499,7 @@ class ExperimentationClient {
|
|
|
16490
16499
|
id: exp.id,
|
|
16491
16500
|
context: this.normalizeToStringRecord(exp.context),
|
|
16492
16501
|
variants: variants,
|
|
16493
|
-
traffic_percentage: exp.traffic_percentage
|
|
16502
|
+
traffic_percentage: exp.traffic_percentage ?? 100,
|
|
16494
16503
|
status: exp.status || superpositionSdk.ExperimentStatusType.DISCARDED,
|
|
16495
16504
|
});
|
|
16496
16505
|
}
|
|
@@ -16524,7 +16533,7 @@ class ExperimentationClient {
|
|
|
16524
16533
|
experimentGroups.push({
|
|
16525
16534
|
id: exp_group.id,
|
|
16526
16535
|
context: this.normalizeToStringRecord(exp_group.context),
|
|
16527
|
-
traffic_percentage: exp_group.traffic_percentage
|
|
16536
|
+
traffic_percentage: exp_group.traffic_percentage ?? 100,
|
|
16528
16537
|
member_experiment_ids: exp_group.member_experiment_ids || [],
|
|
16529
16538
|
group_type: exp_group.group_type ||
|
|
16530
16539
|
superpositionSdk.GroupType.USER_CREATED,
|
|
@@ -16583,6 +16592,7 @@ class ExperimentationClient {
|
|
|
16583
16592
|
if (experiments) {
|
|
16584
16593
|
this.cachedExperiments = experiments;
|
|
16585
16594
|
this.lastUpdated = new Date();
|
|
16595
|
+
this.onExperimentsChange?.();
|
|
16586
16596
|
}
|
|
16587
16597
|
}
|
|
16588
16598
|
catch (error) {
|
|
@@ -16600,6 +16610,7 @@ class ExperimentationClient {
|
|
|
16600
16610
|
const experiments = await this.fetchExperiments();
|
|
16601
16611
|
if (experiments) {
|
|
16602
16612
|
this.cachedExperiments = experiments;
|
|
16613
|
+
this.onExperimentsChange?.();
|
|
16603
16614
|
this.lastUpdated = new Date();
|
|
16604
16615
|
}
|
|
16605
16616
|
}
|
|
@@ -16620,6 +16631,7 @@ class ExperimentationClient {
|
|
|
16620
16631
|
if (experimentGroups) {
|
|
16621
16632
|
this.cachedExperimentGroups = experimentGroups;
|
|
16622
16633
|
this.lastUpdated = new Date();
|
|
16634
|
+
this.onExperimentsChange?.();
|
|
16623
16635
|
}
|
|
16624
16636
|
}
|
|
16625
16637
|
catch (error) {
|
|
@@ -16637,11 +16649,18 @@ class ExperimentationClient {
|
|
|
16637
16649
|
const experimentGroups = await this.fetchExperimentGroups();
|
|
16638
16650
|
if (experimentGroups) {
|
|
16639
16651
|
this.cachedExperimentGroups = experimentGroups;
|
|
16652
|
+
this.onExperimentsChange?.();
|
|
16640
16653
|
this.lastUpdated = new Date();
|
|
16641
16654
|
}
|
|
16642
16655
|
}
|
|
16643
16656
|
return this.cachedExperimentGroups || [];
|
|
16644
16657
|
}
|
|
16658
|
+
getCachedExperiments() {
|
|
16659
|
+
return this.cachedExperiments;
|
|
16660
|
+
}
|
|
16661
|
+
getCachedExperimentGroups() {
|
|
16662
|
+
return this.cachedExperimentGroups;
|
|
16663
|
+
}
|
|
16645
16664
|
generateCacheKey(queryData) {
|
|
16646
16665
|
return JSON.stringify(queryData, Object.keys(queryData).sort());
|
|
16647
16666
|
}
|
|
@@ -16657,11 +16676,12 @@ class ExperimentationClient {
|
|
|
16657
16676
|
async close() {
|
|
16658
16677
|
try {
|
|
16659
16678
|
if (this.pollingInterval) {
|
|
16660
|
-
|
|
16679
|
+
clearTimeout(this.pollingInterval);
|
|
16661
16680
|
console.log("Polling stopped successfully");
|
|
16662
16681
|
}
|
|
16663
16682
|
this.clearEvalCache();
|
|
16664
16683
|
this.cachedExperiments = null;
|
|
16684
|
+
this.cachedExperimentGroups = null;
|
|
16665
16685
|
this.lastUpdated = null;
|
|
16666
16686
|
console.log("ExperimentationClient closed successfully");
|
|
16667
16687
|
}
|
|
@@ -16672,30 +16692,47 @@ class ExperimentationClient {
|
|
|
16672
16692
|
}
|
|
16673
16693
|
}
|
|
16674
16694
|
|
|
16695
|
+
const _cacheRegistry = new FinalizationRegistry((freeFn) => {
|
|
16696
|
+
setImmediate(freeFn);
|
|
16697
|
+
});
|
|
16675
16698
|
class ConfigurationClient {
|
|
16676
16699
|
constructor(config, resolver, options = {}, experimentationOptions) {
|
|
16677
16700
|
this.currentConfigData = null;
|
|
16701
|
+
this.providerCache = null;
|
|
16702
|
+
this.refreshInterval = null;
|
|
16678
16703
|
this.defaults = null;
|
|
16679
16704
|
this.config = config;
|
|
16680
16705
|
this.resolver = resolver;
|
|
16681
16706
|
this.options = options;
|
|
16707
|
+
this.providerCache = resolver.createProviderCache();
|
|
16708
|
+
const cache = this.providerCache;
|
|
16709
|
+
_cacheRegistry.register(this, () => {
|
|
16710
|
+
cache.free();
|
|
16711
|
+
}, this);
|
|
16682
16712
|
if (this.options.refreshStrategy &&
|
|
16683
16713
|
"interval" in this.options.refreshStrategy) {
|
|
16684
16714
|
const strategy = this.options.refreshStrategy;
|
|
16685
|
-
|
|
16715
|
+
const weakSelf = new WeakRef(this);
|
|
16716
|
+
const poll = async () => {
|
|
16717
|
+
const self = weakSelf.deref();
|
|
16718
|
+
if (!self)
|
|
16719
|
+
return;
|
|
16686
16720
|
try {
|
|
16687
|
-
const refreshedConfig = await
|
|
16688
|
-
|
|
16721
|
+
const refreshedConfig = await self.fetchConfigData();
|
|
16722
|
+
self.currentConfigData = refreshedConfig;
|
|
16723
|
+
self.providerCache?.initConfig(refreshedConfig.default_configs, refreshedConfig.contexts, refreshedConfig.overrides, refreshedConfig.dimensions);
|
|
16689
16724
|
console.log("Configuration refreshed successfully.");
|
|
16690
16725
|
}
|
|
16691
16726
|
catch (error) {
|
|
16692
16727
|
console.error("Failed to refresh configuration. Will continue to use the last known good configuration.", error);
|
|
16693
16728
|
}
|
|
16694
|
-
|
|
16729
|
+
self.refreshInterval = setTimeout(poll, strategy.interval);
|
|
16730
|
+
};
|
|
16731
|
+
this.refreshInterval = setTimeout(poll, strategy.interval);
|
|
16695
16732
|
}
|
|
16696
16733
|
if (experimentationOptions) {
|
|
16697
16734
|
this.experimentationOptions = experimentationOptions;
|
|
16698
|
-
this.experimentationClient = new ExperimentationClient(config, experimentationOptions);
|
|
16735
|
+
this.experimentationClient = new ExperimentationClient(config, experimentationOptions, this.reinitExperimentsCache.bind(this));
|
|
16699
16736
|
}
|
|
16700
16737
|
this.smithyClient = new superpositionSdk.SuperpositionClient({
|
|
16701
16738
|
endpoint: this.config.endpoint,
|
|
@@ -16704,26 +16741,35 @@ class ConfigurationClient {
|
|
|
16704
16741
|
});
|
|
16705
16742
|
}
|
|
16706
16743
|
async initialize() {
|
|
16707
|
-
|
|
16744
|
+
const configData = await this.fetchConfigData();
|
|
16745
|
+
this.providerCache.initConfig(configData.default_configs, configData.contexts, configData.overrides, configData.dimensions);
|
|
16708
16746
|
if (this.experimentationClient) {
|
|
16709
16747
|
await this.experimentationClient.initialize();
|
|
16748
|
+
this.reinitExperimentsCache();
|
|
16749
|
+
}
|
|
16750
|
+
}
|
|
16751
|
+
reinitExperimentsCache() {
|
|
16752
|
+
if (!this.experimentationClient || !this.providerCache)
|
|
16753
|
+
return;
|
|
16754
|
+
const experiments = this.experimentationClient.getCachedExperiments();
|
|
16755
|
+
const experimentGroups = this.experimentationClient.getCachedExperimentGroups();
|
|
16756
|
+
if (experiments && experimentGroups) {
|
|
16757
|
+
this.providerCache.initExperiments(experiments, experimentGroups);
|
|
16710
16758
|
}
|
|
16711
16759
|
}
|
|
16712
16760
|
async eval(queryData, filterPrefixes, targetingKey) {
|
|
16713
16761
|
try {
|
|
16714
|
-
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
const experiments = await this.experimentationClient.getExperiments();
|
|
16718
|
-
const experiment_groups = await this.experimentationClient.getExperimentGroups();
|
|
16719
|
-
experimentationArgs = {
|
|
16720
|
-
experiments,
|
|
16721
|
-
experiment_groups,
|
|
16722
|
-
targeting_key: targetingKey,
|
|
16723
|
-
};
|
|
16762
|
+
if (!this.currentConfigData) {
|
|
16763
|
+
const configData = await this.fetchConfigData();
|
|
16764
|
+
this.providerCache.initConfig(configData.default_configs, configData.contexts, configData.overrides, configData.dimensions);
|
|
16724
16765
|
}
|
|
16725
|
-
|
|
16726
|
-
|
|
16766
|
+
if (this.experimentationClient && targetingKey &&
|
|
16767
|
+
!this.experimentationClient.getCachedExperiments()) {
|
|
16768
|
+
await this.experimentationClient.getExperiments();
|
|
16769
|
+
await this.experimentationClient.getExperimentGroups();
|
|
16770
|
+
this.reinitExperimentsCache();
|
|
16771
|
+
}
|
|
16772
|
+
return this.providerCache.evalConfig(queryData, "merge", filterPrefixes, targetingKey);
|
|
16727
16773
|
}
|
|
16728
16774
|
catch (error) {
|
|
16729
16775
|
if (this.defaults) {
|
|
@@ -16763,21 +16809,17 @@ class ConfigurationClient {
|
|
|
16763
16809
|
// TODO: Remove this function all together and use eval for getAllConfigValue as well
|
|
16764
16810
|
async getAllConfigValue(defaultValue, context, targetingKey) {
|
|
16765
16811
|
try {
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
|
|
16769
|
-
if (this.experimentationClient && targetingKey) {
|
|
16770
|
-
const experiments = await this.experimentationClient.getExperiments();
|
|
16771
|
-
const experiment_groups = await this.experimentationClient.getExperimentGroups();
|
|
16772
|
-
const identifier = this.experimentationOptions?.defaultIdentifier ||
|
|
16773
|
-
(targetingKey ? targetingKey : "default");
|
|
16774
|
-
const variantIds = await this.getApplicableVariants(experiments, experiment_groups, this.currentConfigData?.dimensions || {}, queryData, identifier);
|
|
16775
|
-
if (variantIds.length > 0) {
|
|
16776
|
-
queryData.variantIds = variantIds;
|
|
16777
|
-
}
|
|
16812
|
+
if (!this.currentConfigData) {
|
|
16813
|
+
const configData = await this.fetchConfigData();
|
|
16814
|
+
this.providerCache.initConfig(configData.default_configs, configData.contexts, configData.overrides, configData.dimensions);
|
|
16778
16815
|
}
|
|
16779
|
-
|
|
16780
|
-
|
|
16816
|
+
if (this.experimentationClient && targetingKey &&
|
|
16817
|
+
!this.experimentationClient.getCachedExperiments()) {
|
|
16818
|
+
await this.experimentationClient.getExperiments();
|
|
16819
|
+
await this.experimentationClient.getExperimentGroups();
|
|
16820
|
+
this.reinitExperimentsCache();
|
|
16821
|
+
}
|
|
16822
|
+
return this.providerCache.evalConfig(context, "merge", undefined, targetingKey);
|
|
16781
16823
|
}
|
|
16782
16824
|
catch (error) {
|
|
16783
16825
|
if (this.defaults) {
|
|
@@ -16786,16 +16828,20 @@ class ConfigurationClient {
|
|
|
16786
16828
|
throw error;
|
|
16787
16829
|
}
|
|
16788
16830
|
}
|
|
16789
|
-
// Add method to get applicable variants
|
|
16790
|
-
async getApplicableVariants(experiments, experiment_groups, dimensions, queryData, identifier, filterPrefixes) {
|
|
16791
|
-
// This would use the native resolver's getApplicableVariants method
|
|
16792
|
-
return this.resolver.getApplicableVariants(experiments, experiment_groups, dimensions, queryData, identifier, filterPrefixes || []);
|
|
16793
|
-
}
|
|
16794
16831
|
// Add method to close and cleanup
|
|
16795
16832
|
async close() {
|
|
16833
|
+
_cacheRegistry.unregister(this);
|
|
16834
|
+
if (this.refreshInterval) {
|
|
16835
|
+
clearTimeout(this.refreshInterval);
|
|
16836
|
+
this.refreshInterval = null;
|
|
16837
|
+
}
|
|
16796
16838
|
if (this.experimentationClient) {
|
|
16797
16839
|
await this.experimentationClient.close();
|
|
16798
16840
|
}
|
|
16841
|
+
if (this.providerCache) {
|
|
16842
|
+
this.providerCache.free();
|
|
16843
|
+
this.providerCache = null;
|
|
16844
|
+
}
|
|
16799
16845
|
}
|
|
16800
16846
|
}
|
|
16801
16847
|
|
|
@@ -16860,6 +16906,11 @@ class NativeResolver {
|
|
|
16860
16906
|
this.lib.core_test_connection = this.lib.func("int core_test_connection()");
|
|
16861
16907
|
this.lib.core_parse_toml_config = this.lib.func("char* core_parse_toml_config(const char*, char*)");
|
|
16862
16908
|
this.lib.core_parse_json_config = this.lib.func("char* core_parse_json_config(const char*, char*)");
|
|
16909
|
+
this.lib.core_provider_cache_new = this.lib.func("void* core_provider_cache_new()");
|
|
16910
|
+
this.lib.core_provider_cache_free = this.lib.func("void core_provider_cache_free(void*)");
|
|
16911
|
+
this.lib.core_provider_cache_init_config = this.lib.func("void core_provider_cache_init_config(void*, const char*, const char*, const char*, const char*, char*)");
|
|
16912
|
+
this.lib.core_provider_cache_init_experiments = this.lib.func("void core_provider_cache_init_experiments(void*, const char*, const char*, char*)");
|
|
16913
|
+
this.lib.core_provider_cache_eval_config = this.lib.func("char* core_provider_cache_eval_config(void*, const char*, const char*, const char*, const char*, char*)");
|
|
16863
16914
|
this.isAvailable = true;
|
|
16864
16915
|
}
|
|
16865
16916
|
catch (error) {
|
|
@@ -17188,6 +17239,51 @@ class NativeResolver {
|
|
|
17188
17239
|
return false;
|
|
17189
17240
|
}
|
|
17190
17241
|
}
|
|
17242
|
+
createProviderCache() {
|
|
17243
|
+
if (!this.isAvailable) {
|
|
17244
|
+
throw new Error("Native resolver is not available.");
|
|
17245
|
+
}
|
|
17246
|
+
const handle = this.lib.core_provider_cache_new();
|
|
17247
|
+
if (!handle) {
|
|
17248
|
+
throw new Error("core_provider_cache_new returned null");
|
|
17249
|
+
}
|
|
17250
|
+
const lib = this.lib;
|
|
17251
|
+
return {
|
|
17252
|
+
initConfig(defaultConfigs, contexts, overrides, dimensions) {
|
|
17253
|
+
const ebuf = buffer.Buffer.alloc(ERROR_BUFFER_SIZE);
|
|
17254
|
+
lib.core_provider_cache_init_config(handle, JSON.stringify(defaultConfigs || {}), JSON.stringify(contexts || []), JSON.stringify(overrides || {}), JSON.stringify(dimensions || {}), ebuf);
|
|
17255
|
+
const err = ebuf.toString('utf8').split('\0')[0];
|
|
17256
|
+
if (err.length !== 0)
|
|
17257
|
+
throw new Error("ffi: " + err);
|
|
17258
|
+
},
|
|
17259
|
+
initExperiments(experiments, experimentGroups) {
|
|
17260
|
+
const ebuf = buffer.Buffer.alloc(ERROR_BUFFER_SIZE);
|
|
17261
|
+
lib.core_provider_cache_init_experiments(handle, JSON.stringify(experiments || []), JSON.stringify(experimentGroups || []), ebuf);
|
|
17262
|
+
const err = ebuf.toString('utf8').split('\0')[0];
|
|
17263
|
+
if (err.length !== 0)
|
|
17264
|
+
throw new Error("ffi: " + err);
|
|
17265
|
+
},
|
|
17266
|
+
evalConfig(queryData, mergeStrategy = "merge", filterPrefixes, targetingKey) {
|
|
17267
|
+
const ebuf = buffer.Buffer.alloc(ERROR_BUFFER_SIZE);
|
|
17268
|
+
const filterPrefixesJson = filterPrefixes && filterPrefixes.length > 0
|
|
17269
|
+
? JSON.stringify(filterPrefixes)
|
|
17270
|
+
: null;
|
|
17271
|
+
const result = lib.core_provider_cache_eval_config(handle, JSON.stringify(queryData || {}), mergeStrategy, filterPrefixesJson, targetingKey || null, ebuf);
|
|
17272
|
+
const err = ebuf.toString('utf8').split('\0')[0];
|
|
17273
|
+
if (err.length !== 0)
|
|
17274
|
+
throw new Error("ffi: " + err);
|
|
17275
|
+
const configStr = typeof result === "string"
|
|
17276
|
+
? result
|
|
17277
|
+
: lib.decode(result, "string");
|
|
17278
|
+
if (typeof result !== "string")
|
|
17279
|
+
lib.core_free_string(result);
|
|
17280
|
+
return JSON.parse(configStr);
|
|
17281
|
+
},
|
|
17282
|
+
free() {
|
|
17283
|
+
lib.core_provider_cache_free(handle);
|
|
17284
|
+
},
|
|
17285
|
+
};
|
|
17286
|
+
}
|
|
17191
17287
|
throwFFIError(err) {
|
|
17192
17288
|
throw new Error("ffi: " + err);
|
|
17193
17289
|
}
|