superposition-provider 0.93.1 → 0.94.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/dist/experimentation-client.d.ts +5 -1
- package/dist/index.esm.js +91 -60
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +91 -60
- 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/dist/superposition-provider.d.ts +3 -3
- package/dist/types.d.ts +13 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GroupType,
|
|
1
|
+
import { GroupType, VariantType } from "superposition-sdk";
|
|
2
2
|
import { SuperpositionOptions, ExperimentationOptions } from "./types";
|
|
3
3
|
export interface Variant {
|
|
4
4
|
id: string;
|
|
@@ -13,6 +13,10 @@ export interface Experiment {
|
|
|
13
13
|
variants: Variant[];
|
|
14
14
|
traffic_percentage: number;
|
|
15
15
|
}
|
|
16
|
+
export interface Bucket {
|
|
17
|
+
variant_id: string;
|
|
18
|
+
experiment_id: string;
|
|
19
|
+
}
|
|
16
20
|
export interface ExperimentGroup {
|
|
17
21
|
id: string;
|
|
18
22
|
context: Record<string, string>;
|
package/dist/index.esm.js
CHANGED
|
@@ -9900,6 +9900,7 @@ function requireAws_restJson1 () {
|
|
|
9900
9900
|
[_v]: [, input[_v]],
|
|
9901
9901
|
[_sr]: [() => input.show_reasoning !== void 0, () => (input[_sr].toString())],
|
|
9902
9902
|
[_ci]: [, input[_ci]],
|
|
9903
|
+
[_rr]: [() => input.resolve_remote !== void 0, () => (input[_rr].toString())],
|
|
9903
9904
|
});
|
|
9904
9905
|
let body;
|
|
9905
9906
|
body = JSON.stringify((0, smithy_client_1.take)(input, {
|
|
@@ -12617,6 +12618,7 @@ function requireAws_restJson1 () {
|
|
|
12617
12618
|
};
|
|
12618
12619
|
const de_DimensionInfo = (output, context) => {
|
|
12619
12620
|
return (0, smithy_client_1.take)(output, {
|
|
12621
|
+
'autocomplete_function_name': smithy_client_1.expectString,
|
|
12620
12622
|
'dependency_graph': smithy_client_1._json,
|
|
12621
12623
|
'dimension_type': (_) => (0, smithy_client_1._json)((0, core_1.awsExpectUnion)(_)),
|
|
12622
12624
|
'position': smithy_client_1.expectInt32,
|
|
@@ -12933,6 +12935,7 @@ function requireAws_restJson1 () {
|
|
|
12933
12935
|
const _p = "prefix";
|
|
12934
12936
|
const _pa = "page";
|
|
12935
12937
|
const _pl = "plaintext";
|
|
12938
|
+
const _rr = "resolve_remote";
|
|
12936
12939
|
const _s = "status";
|
|
12937
12940
|
const _sb = "sort_by";
|
|
12938
12941
|
const _so = "sort_on";
|
|
@@ -15596,7 +15599,10 @@ class ExperimentationClient {
|
|
|
15596
15599
|
member_experiment_ids: exp_group.member_experiment_ids || [],
|
|
15597
15600
|
group_type: exp_group.group_type ||
|
|
15598
15601
|
superpositionSdk.GroupType.USER_CREATED,
|
|
15599
|
-
buckets: exp_group.buckets
|
|
15602
|
+
buckets: exp_group.buckets?.map((bucket) => ({
|
|
15603
|
+
variant_id: bucket.variant_id || "",
|
|
15604
|
+
experiment_id: bucket.experiment_id || "",
|
|
15605
|
+
})) || [],
|
|
15600
15606
|
});
|
|
15601
15607
|
}
|
|
15602
15608
|
return experimentGroups;
|
|
@@ -15741,10 +15747,10 @@ class ConfigurationClient {
|
|
|
15741
15747
|
console.error("Failed to refresh configuration. Will continue to use the last known good configuration.", error);
|
|
15742
15748
|
}
|
|
15743
15749
|
}, strategy.interval);
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15750
|
+
}
|
|
15751
|
+
if (experimentationOptions) {
|
|
15752
|
+
this.experimentationOptions = experimentationOptions;
|
|
15753
|
+
this.experimentationClient = new ExperimentationClient(config, experimentationOptions);
|
|
15748
15754
|
}
|
|
15749
15755
|
this.smithyClient = new superpositionSdk.SuperpositionClient({
|
|
15750
15756
|
endpoint: this.config.endpoint,
|
|
@@ -15763,8 +15769,10 @@ class ConfigurationClient {
|
|
|
15763
15769
|
let experimentationArgs;
|
|
15764
15770
|
if (this.experimentationClient && targetingKey) {
|
|
15765
15771
|
const experiments = await this.experimentationClient.getExperiments();
|
|
15772
|
+
const experiment_groups = await this.experimentationClient.getExperimentGroups();
|
|
15766
15773
|
experimentationArgs = {
|
|
15767
15774
|
experiments,
|
|
15775
|
+
experiment_groups,
|
|
15768
15776
|
targeting_key: targetingKey,
|
|
15769
15777
|
};
|
|
15770
15778
|
}
|
|
@@ -15806,6 +15814,7 @@ class ConfigurationClient {
|
|
|
15806
15814
|
}
|
|
15807
15815
|
}
|
|
15808
15816
|
// TODO: defaultValue is taken but not used. Should it be used as a fallback?
|
|
15817
|
+
// TODO: Remove this function all together and use eval for getAllConfigValue as well
|
|
15809
15818
|
async getAllConfigValue(defaultValue, context, targetingKey) {
|
|
15810
15819
|
try {
|
|
15811
15820
|
const configData = await this.fetchConfigData();
|
|
@@ -15897,11 +15906,9 @@ class NativeResolver {
|
|
|
15897
15906
|
try {
|
|
15898
15907
|
this.lib = koffi.load(libPath || this.getDefaultLibPath());
|
|
15899
15908
|
// Define the core resolution functions with CORRECT 8 parameters each
|
|
15900
|
-
this.lib.core_get_resolved_config = this.lib.func("char* core_get_resolved_config(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*)");
|
|
15901
|
-
this.lib.core_get_resolved_config_with_reasoning = this.lib.func("char* core_get_resolved_config_with_reasoning(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*)");
|
|
15909
|
+
this.lib.core_get_resolved_config = this.lib.func("char* core_get_resolved_config(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*)");
|
|
15910
|
+
this.lib.core_get_resolved_config_with_reasoning = this.lib.func("char* core_get_resolved_config_with_reasoning(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*)");
|
|
15902
15911
|
this.lib.core_free_string = this.lib.func("void core_free_string(char*)");
|
|
15903
|
-
this.lib.core_last_error_message = this.lib.func("char* core_last_error_message()");
|
|
15904
|
-
this.lib.core_last_error_length = this.lib.func("int core_last_error_length()");
|
|
15905
15912
|
this.lib.core_get_applicable_variants = this.lib.func("char* core_get_applicable_variants(const char*, const char*, const char*, const char*, const char*)");
|
|
15906
15913
|
this.lib.core_test_connection = this.lib.func("int core_test_connection()");
|
|
15907
15914
|
this.isAvailable = true;
|
|
@@ -15953,7 +15960,9 @@ class NativeResolver {
|
|
|
15953
15960
|
console.log(" queryData :", queryDataJson);
|
|
15954
15961
|
console.log(" mergeStrategy:", mergeStrategy);
|
|
15955
15962
|
console.log(" filterPrefixes:", filterPrefixes);
|
|
15956
|
-
console.log("
|
|
15963
|
+
console.log(" experiment:", experimentation?.experiments?.length);
|
|
15964
|
+
console.log(" experiment groups:", experimentation?.experiment_groups?.length);
|
|
15965
|
+
console.log(" targetingKey:", experimentation?.targetingKey);
|
|
15957
15966
|
if (!defaultConfigsJson ||
|
|
15958
15967
|
defaultConfigsJson === "null" ||
|
|
15959
15968
|
defaultConfigsJson === "undefined") {
|
|
@@ -15979,10 +15988,12 @@ class NativeResolver {
|
|
|
15979
15988
|
queryDataJson === "undefined") {
|
|
15980
15989
|
throw new Error("queryData serialization failed");
|
|
15981
15990
|
}
|
|
15982
|
-
const
|
|
15991
|
+
const ebuf = Buffer$1.alloc(256);
|
|
15992
|
+
const result = this.lib.core_get_resolved_config(defaultConfigsJson, contextsJson, overridesJson, dimensionsJson, queryDataJson, mergeStrategy, filterPrefixesJson, experimentationJson, ebuf);
|
|
15983
15993
|
console.log("🔧 FFI call completed, result:", result);
|
|
15984
|
-
|
|
15985
|
-
|
|
15994
|
+
const err = ebuf.toString('utf8').split('\0')[0];
|
|
15995
|
+
if (err.length !== 0) {
|
|
15996
|
+
this.throwFFIError(err);
|
|
15986
15997
|
}
|
|
15987
15998
|
const configStr = typeof result === "string"
|
|
15988
15999
|
? result
|
|
@@ -16009,9 +16020,11 @@ class NativeResolver {
|
|
|
16009
16020
|
const experimentationJson = experimentation
|
|
16010
16021
|
? JSON.stringify(experimentation)
|
|
16011
16022
|
: null;
|
|
16012
|
-
const
|
|
16013
|
-
|
|
16014
|
-
|
|
16023
|
+
const ebuf = Buffer$1.alloc(256);
|
|
16024
|
+
const result = this.lib.core_get_resolved_config_with_reasoning(JSON.stringify(defaultConfigs || {}), JSON.stringify(contexts), JSON.stringify(overrides), JSON.stringify(dimensions), JSON.stringify(queryData), mergeStrategy, filterPrefixesJson, experimentationJson, ebuf);
|
|
16025
|
+
const err = ebuf.toString('utf8').split('\0')[0];
|
|
16026
|
+
if (err.length !== 0) {
|
|
16027
|
+
this.throwFFIError(err);
|
|
16015
16028
|
}
|
|
16016
16029
|
const configStr = typeof result === "string"
|
|
16017
16030
|
? result
|
|
@@ -16049,10 +16062,12 @@ class NativeResolver {
|
|
|
16049
16062
|
console.log(" userContext:", userContext);
|
|
16050
16063
|
console.log(" identifier:", identifier);
|
|
16051
16064
|
console.log(" filterPrefixes:", filterPrefixes);
|
|
16065
|
+
const ebuf = Buffer$1.alloc(256);
|
|
16052
16066
|
const result = this.lib.core_get_applicable_variants(experimentsJson, experimentGroupsJson, dimensionsJson, userContextJson, identifier, filterPrefixesJson);
|
|
16053
16067
|
console.log("FFI getApplicableVariants call completed, result:", result);
|
|
16054
|
-
|
|
16055
|
-
|
|
16068
|
+
const err = ebuf.toString('utf8').split('\0')[0];
|
|
16069
|
+
if (err.length !== 0) {
|
|
16070
|
+
this.throwFFIError(err);
|
|
16056
16071
|
}
|
|
16057
16072
|
const resultStr = typeof result === "string"
|
|
16058
16073
|
? result
|
|
@@ -16136,22 +16151,8 @@ class NativeResolver {
|
|
|
16136
16151
|
return false;
|
|
16137
16152
|
}
|
|
16138
16153
|
}
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
throw new Error(`${prefix}: Native resolver not available`);
|
|
16142
|
-
}
|
|
16143
|
-
const errorLength = this.lib.core_last_error_length();
|
|
16144
|
-
if (errorLength > 0) {
|
|
16145
|
-
const errorPtr = this.lib.core_last_error_message();
|
|
16146
|
-
const errorMsg = typeof errorPtr === "string"
|
|
16147
|
-
? errorPtr
|
|
16148
|
-
: this.lib.decode(errorPtr, "string");
|
|
16149
|
-
if (typeof errorPtr !== "string") {
|
|
16150
|
-
this.lib.core_free_string(errorPtr);
|
|
16151
|
-
}
|
|
16152
|
-
throw new Error(`${prefix}: ${errorMsg}`);
|
|
16153
|
-
}
|
|
16154
|
-
throw new Error(`${prefix}: Unknown error`);
|
|
16154
|
+
throwFFIError(err) {
|
|
16155
|
+
throw new Error("ffi: " + err);
|
|
16155
16156
|
}
|
|
16156
16157
|
}
|
|
16157
16158
|
|
|
@@ -16165,13 +16166,14 @@ class SuperpositionProvider {
|
|
|
16165
16166
|
constructor(config) {
|
|
16166
16167
|
this.config = config;
|
|
16167
16168
|
this.metadata = {
|
|
16168
|
-
name:
|
|
16169
|
-
slug:
|
|
16169
|
+
name: "SuperpositionProvider",
|
|
16170
|
+
slug: "superposition-provider",
|
|
16170
16171
|
};
|
|
16171
16172
|
this.events = new OpenFeatureEventEmitter();
|
|
16172
16173
|
this.hooks = [];
|
|
16173
16174
|
this.status = ProviderStatus.NOT_READY;
|
|
16174
16175
|
// Cache for processed contexts
|
|
16176
|
+
// TODO: verify if this is at all needed
|
|
16175
16177
|
this.processedContextCache = new WeakMap();
|
|
16176
16178
|
this.client = new ConfigurationClient({
|
|
16177
16179
|
endpoint: config.endpoint,
|
|
@@ -16188,14 +16190,22 @@ class SuperpositionProvider {
|
|
|
16188
16190
|
this.status = ProviderStatus.NOT_READY;
|
|
16189
16191
|
try {
|
|
16190
16192
|
await this.client.initialize();
|
|
16193
|
+
// TODO: find why is this needed?
|
|
16191
16194
|
await this.client.eval(context || {});
|
|
16192
16195
|
this.status = ProviderStatus.READY;
|
|
16193
|
-
this.events.emit(ProviderEvents.Ready, {
|
|
16196
|
+
this.events.emit(ProviderEvents.Ready, {
|
|
16197
|
+
message: "Provider ready",
|
|
16198
|
+
});
|
|
16194
16199
|
}
|
|
16195
16200
|
catch (error) {
|
|
16196
16201
|
this.status = ProviderStatus.ERROR;
|
|
16197
|
-
const message = error instanceof Error
|
|
16198
|
-
|
|
16202
|
+
const message = error instanceof Error
|
|
16203
|
+
? error.message
|
|
16204
|
+
: "Initialization failed";
|
|
16205
|
+
this.events.emit(ProviderEvents.Error, {
|
|
16206
|
+
message,
|
|
16207
|
+
errorCode: ErrorCode.PROVIDER_NOT_READY,
|
|
16208
|
+
});
|
|
16199
16209
|
throw error;
|
|
16200
16210
|
}
|
|
16201
16211
|
}
|
|
@@ -16210,7 +16220,7 @@ class SuperpositionProvider {
|
|
|
16210
16220
|
processedContext = this.filterContext(context);
|
|
16211
16221
|
this.processedContextCache.set(context, processedContext);
|
|
16212
16222
|
}
|
|
16213
|
-
const config = await this.client.eval(processedContext);
|
|
16223
|
+
const config = await this.client.eval(processedContext, undefined, context.targetingKey);
|
|
16214
16224
|
const value = getNestedValue(config, flagKey);
|
|
16215
16225
|
const converter = TYPE_CONVERTERS[type];
|
|
16216
16226
|
return converter(value, defaultValue);
|
|
@@ -16218,17 +16228,24 @@ class SuperpositionProvider {
|
|
|
16218
16228
|
filterContext(context) {
|
|
16219
16229
|
const filtered = {};
|
|
16220
16230
|
for (const [key, value] of Object.entries(context)) {
|
|
16221
|
-
if (key.startsWith(
|
|
16231
|
+
if (key.startsWith("__") ||
|
|
16232
|
+
key === "targetingKey" ||
|
|
16233
|
+
key === "timestamp") {
|
|
16222
16234
|
continue;
|
|
16223
16235
|
}
|
|
16224
16236
|
// Only include simple, serializable types
|
|
16225
|
-
if (typeof value ===
|
|
16237
|
+
if (typeof value === "string" ||
|
|
16238
|
+
typeof value === "number" ||
|
|
16239
|
+
typeof value === "boolean") {
|
|
16226
16240
|
filtered[key] = value;
|
|
16227
16241
|
}
|
|
16228
|
-
else if (typeof value ===
|
|
16242
|
+
else if (typeof value === "object" &&
|
|
16243
|
+
value !== null &&
|
|
16244
|
+
!Array.isArray(value)) {
|
|
16229
16245
|
try {
|
|
16230
16246
|
const serialized = JSON.stringify(value);
|
|
16231
|
-
if (serialized.length < 1000 &&
|
|
16247
|
+
if (serialized.length < 1000 &&
|
|
16248
|
+
Object.keys(value).length < 10) {
|
|
16232
16249
|
filtered[key] = value;
|
|
16233
16250
|
}
|
|
16234
16251
|
}
|
|
@@ -16241,62 +16258,76 @@ class SuperpositionProvider {
|
|
|
16241
16258
|
}
|
|
16242
16259
|
createResolver(type) {
|
|
16243
16260
|
return async (flagKey, defaultValue, context) => {
|
|
16244
|
-
if (this.status !== ProviderStatus.READY &&
|
|
16261
|
+
if (this.status !== ProviderStatus.READY &&
|
|
16262
|
+
this.status !== ProviderStatus.STALE) {
|
|
16245
16263
|
return {
|
|
16246
16264
|
value: defaultValue,
|
|
16247
|
-
reason:
|
|
16248
|
-
errorCode: this.status === ProviderStatus.FATAL
|
|
16249
|
-
|
|
16265
|
+
reason: "ERROR",
|
|
16266
|
+
errorCode: this.status === ProviderStatus.FATAL
|
|
16267
|
+
? ErrorCode.PROVIDER_FATAL
|
|
16268
|
+
: ErrorCode.PROVIDER_NOT_READY,
|
|
16269
|
+
errorMessage: `Provider status: ${this.status}`,
|
|
16250
16270
|
};
|
|
16251
16271
|
}
|
|
16252
16272
|
try {
|
|
16253
16273
|
const value = await this.evaluateFlag(flagKey, defaultValue, context, type);
|
|
16254
16274
|
return {
|
|
16255
16275
|
value,
|
|
16256
|
-
reason: this.status === ProviderStatus.STALE
|
|
16276
|
+
reason: this.status === ProviderStatus.STALE
|
|
16277
|
+
? "STALE"
|
|
16278
|
+
: "TARGETING_MATCH",
|
|
16257
16279
|
};
|
|
16258
16280
|
}
|
|
16259
16281
|
catch (error) {
|
|
16260
16282
|
return {
|
|
16261
16283
|
value: defaultValue,
|
|
16262
|
-
reason:
|
|
16284
|
+
reason: "ERROR",
|
|
16263
16285
|
errorCode: ErrorCode.GENERAL,
|
|
16264
|
-
errorMessage: error instanceof Error
|
|
16286
|
+
errorMessage: error instanceof Error
|
|
16287
|
+
? error.message
|
|
16288
|
+
: "Evaluation failed",
|
|
16265
16289
|
};
|
|
16266
16290
|
}
|
|
16267
16291
|
};
|
|
16268
16292
|
}
|
|
16269
16293
|
async resolveBooleanEvaluation(flagKey, defaultValue, context) {
|
|
16270
|
-
return this.createResolver(
|
|
16294
|
+
return this.createResolver("boolean")(flagKey, defaultValue, context);
|
|
16271
16295
|
}
|
|
16272
16296
|
async resolveStringEvaluation(flagKey, defaultValue, context) {
|
|
16273
|
-
return this.createResolver(
|
|
16297
|
+
return this.createResolver("string")(flagKey, defaultValue, context);
|
|
16274
16298
|
}
|
|
16275
16299
|
async resolveNumberEvaluation(flagKey, defaultValue, context) {
|
|
16276
|
-
return this.createResolver(
|
|
16300
|
+
return this.createResolver("number")(flagKey, defaultValue, context);
|
|
16277
16301
|
}
|
|
16278
16302
|
async resolveObjectEvaluation(flagKey, defaultValue, context, logger) {
|
|
16279
|
-
return this.createResolver(
|
|
16303
|
+
return this.createResolver("object")(flagKey, defaultValue, context);
|
|
16280
16304
|
}
|
|
16281
16305
|
async resolveAllConfigDetails(defaultValue, context) {
|
|
16282
|
-
if (this.status !== ProviderStatus.READY &&
|
|
16306
|
+
if (this.status !== ProviderStatus.READY &&
|
|
16307
|
+
this.status !== ProviderStatus.STALE) {
|
|
16283
16308
|
return defaultValue;
|
|
16284
16309
|
}
|
|
16285
16310
|
try {
|
|
16286
|
-
const processedContext = this.processedContextCache.get(context) ||
|
|
16311
|
+
const processedContext = this.processedContextCache.get(context) ||
|
|
16312
|
+
this.filterContext(context);
|
|
16287
16313
|
if (!this.processedContextCache.has(context)) {
|
|
16288
16314
|
this.processedContextCache.set(context, processedContext);
|
|
16289
16315
|
}
|
|
16290
16316
|
const targetingKey = context.targetingKey;
|
|
16317
|
+
// TODO: remove this function and use eval for getAllConfigValue as well
|
|
16291
16318
|
return await this.client.getAllConfigValue(defaultValue, processedContext, targetingKey);
|
|
16292
16319
|
}
|
|
16293
16320
|
catch (error) {
|
|
16294
|
-
console.error(
|
|
16321
|
+
console.error("Error resolving all config details:", error);
|
|
16295
16322
|
return defaultValue;
|
|
16296
16323
|
}
|
|
16297
16324
|
}
|
|
16298
|
-
getStatus() {
|
|
16299
|
-
|
|
16325
|
+
getStatus() {
|
|
16326
|
+
return this.status;
|
|
16327
|
+
}
|
|
16328
|
+
getConfigurationClient() {
|
|
16329
|
+
return this.client;
|
|
16330
|
+
}
|
|
16300
16331
|
}
|
|
16301
16332
|
|
|
16302
16333
|
function httpRequest(options) {
|