@configdirector/react-native-sdk 0.7.0 → 0.9.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.
|
@@ -26,6 +26,15 @@ interface ConfigDirectorLogger {
|
|
|
26
26
|
interface ConfigDirectorLogMessageDecorator {
|
|
27
27
|
decorateMessage(message: string): string;
|
|
28
28
|
}
|
|
29
|
+
type EvaluationReason = "found-match" | "config-state-missing" | "client-not-ready" | "type-mismatch" | "value-missing" | "invalid-number" | "invalid-json" | "invalid-boolean";
|
|
30
|
+
type ConfigEvaluation = {
|
|
31
|
+
key: string;
|
|
32
|
+
value: ConfigValueType;
|
|
33
|
+
valueId?: string;
|
|
34
|
+
isDefaultValue: boolean;
|
|
35
|
+
reason: EvaluationReason;
|
|
36
|
+
context?: ConfigDirectorContext;
|
|
37
|
+
};
|
|
29
38
|
/**
|
|
30
39
|
* The user's context to be sent to ConfigDirector. This context will be used for targeting
|
|
31
40
|
* rules evaluation.
|
|
@@ -131,8 +140,31 @@ type ConfigDirectorClientOptions = {
|
|
|
131
140
|
* );
|
|
132
141
|
*/
|
|
133
142
|
logger?: ConfigDirectorLogger;
|
|
143
|
+
/**
|
|
144
|
+
* Handlers for hooks/events emitted by the client. Each hook accepts either a single event handler or
|
|
145
|
+
* an array of event handlers.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* import { createClient, createConsoleLogger } from "@configdirector/client-sdk";
|
|
149
|
+
* const client = createClient(
|
|
150
|
+
* "YOUR-SDK-KEY",
|
|
151
|
+
* {
|
|
152
|
+
* hooks: {
|
|
153
|
+
* configEvaluated: (event) => { console.log(event.evaluation); }
|
|
154
|
+
* },
|
|
155
|
+
* },
|
|
156
|
+
* );
|
|
157
|
+
*/
|
|
158
|
+
hooks?: ClientHooks;
|
|
159
|
+
};
|
|
160
|
+
type ClientHooks = {
|
|
161
|
+
clientReady?: HookHandler<"clientReady"> | HookHandler<"clientReady">[];
|
|
162
|
+
configsUpdated?: HookHandler<"configsUpdated"> | HookHandler<"configsUpdated">[];
|
|
163
|
+
contextUpdated?: HookHandler<"contextUpdated"> | HookHandler<"contextUpdated">[];
|
|
164
|
+
configEvaluated?: HookHandler<"configEvaluated"> | HookHandler<"configEvaluated">[];
|
|
134
165
|
};
|
|
135
166
|
type ClientConnectAction = "initialization" | "context update" | "network resume";
|
|
167
|
+
type HookHandler<TEvent extends keyof ClientEvents> = (payload: ClientEvents[TEvent]) => void;
|
|
136
168
|
type ClientEvents = {
|
|
137
169
|
configsUpdated: {
|
|
138
170
|
keys: string[];
|
|
@@ -143,6 +175,9 @@ type ClientEvents = {
|
|
|
143
175
|
contextUpdated: {
|
|
144
176
|
context: ConfigDirectorContext | undefined;
|
|
145
177
|
};
|
|
178
|
+
configEvaluated: {
|
|
179
|
+
evaluation: ConfigEvaluation;
|
|
180
|
+
};
|
|
146
181
|
};
|
|
147
182
|
type WatchHandler<T extends ConfigValueType> = (message: T) => void;
|
|
148
183
|
/**
|
|
@@ -297,6 +332,7 @@ type ConfigDirectorProviderOptions = {
|
|
|
297
332
|
timeout?: number;
|
|
298
333
|
context?: ConfigDirectorContext;
|
|
299
334
|
logger?: ConfigDirectorLogger;
|
|
335
|
+
hooks?: ClientHooks;
|
|
300
336
|
netInfoSubscribe?: NetInfoSubscribe;
|
|
301
337
|
};
|
|
302
338
|
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
1
2
|
import React, { Component, useContext as useContext$1 } from "react";
|
|
2
3
|
import { AppState } from "react-native";
|
|
3
4
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -550,22 +551,25 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
550
551
|
const requestedType = getRequestedType(defaultValue);
|
|
551
552
|
if (!value) return {
|
|
552
553
|
parsedValue: defaultValue,
|
|
554
|
+
parsedValueId: void 0,
|
|
553
555
|
requestedType,
|
|
554
556
|
usedDefault: true,
|
|
555
557
|
reason: "value-missing"
|
|
556
558
|
};
|
|
557
|
-
if (configState.type === "json") return parseJson(value, defaultValue, requestedType);
|
|
559
|
+
if (configState.type === "json") return parseJson(value, defaultValue, requestedType, configState.valueId);
|
|
558
560
|
if (typeof defaultValue === "string") return {
|
|
559
561
|
parsedValue: value,
|
|
562
|
+
parsedValueId: configState.valueId,
|
|
560
563
|
requestedType,
|
|
561
564
|
usedDefault: false,
|
|
562
565
|
reason: "found-match"
|
|
563
566
|
};
|
|
564
|
-
if (typeof defaultValue === "boolean" && configState.type === "boolean") {
|
|
567
|
+
if (typeof defaultValue === "boolean" && (configState.type === "boolean" || configState.type === "string")) {
|
|
565
568
|
const boolValue = parseConfigBoolean(value);
|
|
566
569
|
const hasBoolean = typeof boolValue === "boolean";
|
|
567
570
|
return {
|
|
568
571
|
parsedValue: hasBoolean ? boolValue : defaultValue,
|
|
572
|
+
parsedValueId: hasBoolean ? configState.valueId : void 0,
|
|
569
573
|
requestedType,
|
|
570
574
|
usedDefault: !hasBoolean,
|
|
571
575
|
reason: hasBoolean ? "found-match" : "invalid-boolean"
|
|
@@ -576,16 +580,18 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
576
580
|
const hasNumber = typeof numValue === "number";
|
|
577
581
|
return {
|
|
578
582
|
parsedValue: hasNumber ? numValue : defaultValue,
|
|
583
|
+
parsedValueId: hasNumber ? configState.valueId : void 0,
|
|
579
584
|
requestedType,
|
|
580
585
|
usedDefault: !hasNumber,
|
|
581
586
|
reason: hasNumber ? "found-match" : "invalid-number"
|
|
582
587
|
};
|
|
583
588
|
}
|
|
584
|
-
if (isNumericNativeType(typeof defaultValue) && (configState.type === "float" || configState.type === "enum")) {
|
|
589
|
+
if (isNumericNativeType(typeof defaultValue) && (configState.type === "float" || configState.type === "enum" || configState.type === "string")) {
|
|
585
590
|
const numValue = parseConfigFloat(value);
|
|
586
591
|
const hasNumber = typeof numValue === "number";
|
|
587
592
|
return {
|
|
588
593
|
parsedValue: hasNumber ? numValue : defaultValue,
|
|
594
|
+
parsedValueId: hasNumber ? configState.valueId : void 0,
|
|
589
595
|
requestedType,
|
|
590
596
|
usedDefault: !hasNumber,
|
|
591
597
|
reason: hasNumber ? "found-match" : "invalid-number"
|
|
@@ -593,6 +599,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
593
599
|
}
|
|
594
600
|
return {
|
|
595
601
|
parsedValue: value,
|
|
602
|
+
parsedValueId: configState.valueId,
|
|
596
603
|
requestedType,
|
|
597
604
|
usedDefault: false,
|
|
598
605
|
reason: "found-match"
|
|
@@ -616,9 +623,10 @@ const parseConfigFloat = (value) => {
|
|
|
616
623
|
if (isNaN(num) || !isFinite(num)) return;
|
|
617
624
|
return num;
|
|
618
625
|
};
|
|
619
|
-
const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
626
|
+
const parseJson = (jsonString, defaultValue, requestedType, valueId) => {
|
|
620
627
|
if (typeof defaultValue === "string") return {
|
|
621
628
|
parsedValue: jsonString,
|
|
629
|
+
parsedValueId: valueId,
|
|
622
630
|
requestedType,
|
|
623
631
|
usedDefault: false,
|
|
624
632
|
reason: "found-match"
|
|
@@ -626,6 +634,7 @@ const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
|
626
634
|
try {
|
|
627
635
|
return {
|
|
628
636
|
parsedValue: JSON.parse(jsonString),
|
|
637
|
+
parsedValueId: valueId,
|
|
629
638
|
requestedType,
|
|
630
639
|
usedDefault: false,
|
|
631
640
|
reason: "found-match"
|
|
@@ -633,6 +642,7 @@ const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
|
633
642
|
} catch {
|
|
634
643
|
return {
|
|
635
644
|
parsedValue: defaultValue,
|
|
645
|
+
parsedValueId: void 0,
|
|
636
646
|
requestedType,
|
|
637
647
|
usedDefault: true,
|
|
638
648
|
reason: "invalid-json"
|
|
@@ -863,7 +873,7 @@ const CLIENT_BASE_URL = "https://client-sdk-api.configdirector.com";
|
|
|
863
873
|
const MAX_EXPONENTIAL_DELAY = 9;
|
|
864
874
|
var DefaultConfigDirectorClient = class {
|
|
865
875
|
constructor(telemetryClient, clientSdkKey, sdkOptions, clientOptions, internalClientOptions) {
|
|
866
|
-
var _clientOptions$logger, _clientOptions$connec, _clientOptions$connec2, _internalClientOption, _this$parseUrl, _clientOptions$connec3, _clientOptions$connec4, _clientOptions$connec5, _navigator, _internalClientOption2, _clientOptions$connec6;
|
|
876
|
+
var _clientOptions$logger, _clientOptions$connec, _clientOptions$connec2, _internalClientOption, _this$parseUrl, _clientOptions$connec3, _clientOptions$connec4, _clientOptions$connec5, _navigator, _internalClientOption2, _clientOptions$connec6, _clientOptions$hooks, _clientOptions$hooks2, _clientOptions$hooks3, _clientOptions$hooks4;
|
|
867
877
|
_defineProperty(this, "logger", void 0);
|
|
868
878
|
_defineProperty(this, "telemetryClient", void 0);
|
|
869
879
|
_defineProperty(this, "configSet", void 0);
|
|
@@ -911,18 +921,27 @@ var DefaultConfigDirectorClient = class {
|
|
|
911
921
|
const configKeys = Object.keys(configSet.configs);
|
|
912
922
|
if (!this.configSet || configSet.kind == "full") {
|
|
913
923
|
this.configSet = configSet;
|
|
914
|
-
this.
|
|
924
|
+
this.emit("configsUpdated", { keys: configKeys });
|
|
915
925
|
this.updateWatchers(configSet.configs);
|
|
916
926
|
} else {
|
|
917
927
|
this.configSet.configs = {
|
|
918
928
|
...this.configSet.configs,
|
|
919
929
|
...configSet.configs
|
|
920
930
|
};
|
|
921
|
-
this.
|
|
931
|
+
this.emit("configsUpdated", { keys: configKeys });
|
|
922
932
|
this.updateWatchers(configSet.configs);
|
|
923
933
|
}
|
|
924
934
|
this.logger.debug("[ConfigDirectorClient] ConfigSet updated from server:", { keys: configKeys });
|
|
925
935
|
});
|
|
936
|
+
this.registerHandler("clientReady", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks = clientOptions.hooks) === null || _clientOptions$hooks === void 0 ? void 0 : _clientOptions$hooks.clientReady);
|
|
937
|
+
this.registerHandler("configEvaluated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks2 = clientOptions.hooks) === null || _clientOptions$hooks2 === void 0 ? void 0 : _clientOptions$hooks2.configEvaluated);
|
|
938
|
+
this.registerHandler("configsUpdated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks3 = clientOptions.hooks) === null || _clientOptions$hooks3 === void 0 ? void 0 : _clientOptions$hooks3.configsUpdated);
|
|
939
|
+
this.registerHandler("contextUpdated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks4 = clientOptions.hooks) === null || _clientOptions$hooks4 === void 0 ? void 0 : _clientOptions$hooks4.contextUpdated);
|
|
940
|
+
}
|
|
941
|
+
registerHandler(event, handler) {
|
|
942
|
+
if (!handler) return;
|
|
943
|
+
const handlers = Array.isArray(handler) ? handler : [handler];
|
|
944
|
+
for (const h of handlers) if (typeof h === "function") this.on(event, h);
|
|
926
945
|
}
|
|
927
946
|
getTransportConstructor(connectionMode) {
|
|
928
947
|
switch (connectionMode) {
|
|
@@ -949,14 +968,14 @@ var DefaultConfigDirectorClient = class {
|
|
|
949
968
|
}).then(() => {
|
|
950
969
|
this.ready = true;
|
|
951
970
|
this.initializing = false;
|
|
952
|
-
this.
|
|
971
|
+
this.emit("clientReady", { action: caller });
|
|
953
972
|
this.logger.debug("[ConfigDirectorClient] Received initial payload from the server, client is ready");
|
|
954
973
|
});
|
|
955
974
|
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
956
975
|
await this.transport.connect(context !== null && context !== void 0 ? context : {}, this.timeout);
|
|
957
976
|
this.currentContext = context;
|
|
958
977
|
this.telemetryClient.updateContext(context);
|
|
959
|
-
this.
|
|
978
|
+
this.emit("contextUpdated", { context });
|
|
960
979
|
const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - startTime;
|
|
961
980
|
const remainingTimeout = this.timeout - elapsedTime;
|
|
962
981
|
clearTimeout(this.timeoutTimer);
|
|
@@ -1006,10 +1025,11 @@ var DefaultConfigDirectorClient = class {
|
|
|
1006
1025
|
return this.getValueFromConfigState(configKey, configState, defaultValue);
|
|
1007
1026
|
}
|
|
1008
1027
|
getValueFromConfigState(configKey, configState, defaultValue) {
|
|
1009
|
-
var _this$currentContext2;
|
|
1028
|
+
var _this$currentContext2, _parseResult$parsedVa;
|
|
1010
1029
|
if (!configState) {
|
|
1011
1030
|
var _this$currentContext;
|
|
1012
1031
|
this.logger.debug(`[ConfigDirectorClient] No config state found for '${configKey}', returning default value '${defaultValue}'`);
|
|
1032
|
+
const reason = this.isReady ? "config-state-missing" : "client-not-ready";
|
|
1013
1033
|
this.telemetryClient.evaluatedConfig({
|
|
1014
1034
|
contextId: (_this$currentContext = this.currentContext) === null || _this$currentContext === void 0 ? void 0 : _this$currentContext.id,
|
|
1015
1035
|
key: configKey,
|
|
@@ -1017,7 +1037,14 @@ var DefaultConfigDirectorClient = class {
|
|
|
1017
1037
|
requestedType: getRequestedType(defaultValue),
|
|
1018
1038
|
evaluatedValue: defaultValue,
|
|
1019
1039
|
usedDefault: true,
|
|
1020
|
-
evaluationReason:
|
|
1040
|
+
evaluationReason: reason
|
|
1041
|
+
});
|
|
1042
|
+
this.dispatchEvaluationEvent({
|
|
1043
|
+
key: configKey,
|
|
1044
|
+
value: defaultValue,
|
|
1045
|
+
isDefaultValue: true,
|
|
1046
|
+
reason,
|
|
1047
|
+
context: this.context
|
|
1021
1048
|
});
|
|
1022
1049
|
return defaultValue;
|
|
1023
1050
|
}
|
|
@@ -1029,12 +1056,31 @@ var DefaultConfigDirectorClient = class {
|
|
|
1029
1056
|
defaultValue,
|
|
1030
1057
|
requestedType: parseResult.requestedType,
|
|
1031
1058
|
evaluatedValue: parseResult.parsedValue,
|
|
1059
|
+
evaluatedValueId: parseResult.parsedValueId,
|
|
1032
1060
|
usedDefault: parseResult.usedDefault,
|
|
1033
1061
|
evaluationReason: parseResult.reason
|
|
1034
1062
|
});
|
|
1063
|
+
this.dispatchEvaluationEvent({
|
|
1064
|
+
key: configKey,
|
|
1065
|
+
value: parseResult.parsedValue,
|
|
1066
|
+
valueId: (_parseResult$parsedVa = parseResult.parsedValueId) !== null && _parseResult$parsedVa !== void 0 ? _parseResult$parsedVa : void 0,
|
|
1067
|
+
isDefaultValue: parseResult.usedDefault,
|
|
1068
|
+
reason: parseResult.reason,
|
|
1069
|
+
context: this.context
|
|
1070
|
+
});
|
|
1035
1071
|
this.logger.debug(`[ConfigDirectorClient] Evaluated '${configKey}' to '${parseResult.parsedValue}'`);
|
|
1036
1072
|
return parseResult.parsedValue;
|
|
1037
1073
|
}
|
|
1074
|
+
dispatchEvaluationEvent(event) {
|
|
1075
|
+
setTimeout(() => this.emit("configEvaluated", { evaluation: event }), 0);
|
|
1076
|
+
}
|
|
1077
|
+
emit(name, payload) {
|
|
1078
|
+
try {
|
|
1079
|
+
this.eventEmitter.emit(name, payload);
|
|
1080
|
+
} catch (error) {
|
|
1081
|
+
this.logger.error(`[ConfigDirectorClient] Error executing event handlers for '${name}'`, error);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1038
1084
|
parseUrl(url, urlFactory) {
|
|
1039
1085
|
if (!url) return;
|
|
1040
1086
|
try {
|
|
@@ -1094,26 +1140,36 @@ var DefaultConfigDirectorClient = class {
|
|
|
1094
1140
|
//#endregion
|
|
1095
1141
|
//#region ../shared/src/telemetry/utils.ts
|
|
1096
1142
|
const CONFIG_VALUE_MAX_LENGTH = 500;
|
|
1097
|
-
const
|
|
1098
|
-
if (
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
return {
|
|
1143
|
+
const compactTelemetryValue = async (tv, valueIdGenerator) => {
|
|
1144
|
+
if (tv.valueId) return { valueId: tv.valueId };
|
|
1145
|
+
if (tv.value) {
|
|
1146
|
+
if (tv.value.length <= CONFIG_VALUE_MAX_LENGTH && tv.type != "json") return { value: tv.value };
|
|
1147
|
+
return { valueId: await valueIdGenerator(tv.value) };
|
|
1102
1148
|
}
|
|
1103
|
-
|
|
1104
|
-
else return { value: value.toString() };
|
|
1149
|
+
return tv;
|
|
1105
1150
|
};
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1151
|
+
const mapToTelemetryValue = (ev) => {
|
|
1152
|
+
var _ev$value;
|
|
1153
|
+
if (ev.type === "json" || ev.type == null && typeof ev.value === "object") {
|
|
1154
|
+
if (ev.valueId) return {
|
|
1155
|
+
valueId: ev.valueId,
|
|
1156
|
+
type: "json"
|
|
1157
|
+
};
|
|
1158
|
+
try {
|
|
1159
|
+
return {
|
|
1160
|
+
value: JSON.stringify(ev.value),
|
|
1161
|
+
type: "json"
|
|
1162
|
+
};
|
|
1163
|
+
} catch {
|
|
1164
|
+
return {
|
|
1165
|
+
value: ev.value.toString(),
|
|
1166
|
+
type: "json"
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
const stringValue = (_ev$value = ev.value) === null || _ev$value === void 0 ? void 0 : _ev$value.toString();
|
|
1171
|
+
if (stringValue && stringValue.length <= CONFIG_VALUE_MAX_LENGTH) return { value: stringValue };
|
|
1172
|
+
return ev.valueId ? { valueId: ev.valueId } : { value: stringValue };
|
|
1117
1173
|
};
|
|
1118
1174
|
const isEventListEmpty = (eventList) => {
|
|
1119
1175
|
const keys = Object.keys(eventList);
|
|
@@ -1289,9 +1345,6 @@ var TelemetryEventCollector = class {
|
|
|
1289
1345
|
const initialDelay = (_options$initialFlush = options.initialFlushIntervalDelay) !== null && _options$initialFlush !== void 0 ? _options$initialFlush : 5e3;
|
|
1290
1346
|
this.flushTimeout = setTimeout(() => this.flushAndScheduleNext(), initialDelay);
|
|
1291
1347
|
}
|
|
1292
|
-
sanitizeValue(value, type) {
|
|
1293
|
-
return sanitizeValue(value, type);
|
|
1294
|
-
}
|
|
1295
1348
|
async flushAndScheduleNext() {
|
|
1296
1349
|
if ((await this.flush()).fatalError) {
|
|
1297
1350
|
this.collectEvents = false;
|
|
@@ -1299,20 +1352,6 @@ var TelemetryEventCollector = class {
|
|
|
1299
1352
|
this.logger.warn("[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.");
|
|
1300
1353
|
} else this.flushTimeout = setTimeout(() => this.flushAndScheduleNext(), this.flushIntervalDelay);
|
|
1301
1354
|
}
|
|
1302
|
-
async flush() {
|
|
1303
|
-
var _this$reporter;
|
|
1304
|
-
if (!this.reporter) return {
|
|
1305
|
-
success: false,
|
|
1306
|
-
fatalError: false
|
|
1307
|
-
};
|
|
1308
|
-
const evaluationSnapshot = this.evaluationEventQueue.takeSnapshot();
|
|
1309
|
-
return await ((_this$reporter = this.reporter) === null || _this$reporter === void 0 ? void 0 : _this$reporter.report({
|
|
1310
|
-
context: this._context,
|
|
1311
|
-
discreteEvents: {},
|
|
1312
|
-
aggregatedEvents: { evaluatedConfig: this.aggregator.aggregate(evaluationSnapshot) },
|
|
1313
|
-
droppedEvents: { evaluatedConfig: evaluationSnapshot.droppedCount }
|
|
1314
|
-
}));
|
|
1315
|
-
}
|
|
1316
1355
|
cancelScheduledFlush() {
|
|
1317
1356
|
clearTimeout(this.flushTimeout);
|
|
1318
1357
|
}
|
|
@@ -1327,13 +1366,36 @@ var TelemetryEventCollector = class {
|
|
|
1327
1366
|
}
|
|
1328
1367
|
};
|
|
1329
1368
|
//#endregion
|
|
1369
|
+
//#region ../shared/src/telemetry/EvaluatedConfigEventPreprocessor.ts
|
|
1370
|
+
var EvaluatedConfigEventPreprocessor = class {
|
|
1371
|
+
constructor(valueIdGenerator) {
|
|
1372
|
+
this.valueIdGenerator = valueIdGenerator;
|
|
1373
|
+
this.valueIdGenerator = valueIdGenerator;
|
|
1374
|
+
}
|
|
1375
|
+
async process(snapshot) {
|
|
1376
|
+
const events = await Promise.all(snapshot.events.map(async (e) => {
|
|
1377
|
+
return {
|
|
1378
|
+
...e,
|
|
1379
|
+
defaultValue: await compactTelemetryValue(e.defaultValue, this.valueIdGenerator),
|
|
1380
|
+
evaluatedValue: await compactTelemetryValue(e.evaluatedValue, this.valueIdGenerator)
|
|
1381
|
+
};
|
|
1382
|
+
}));
|
|
1383
|
+
return {
|
|
1384
|
+
...snapshot,
|
|
1385
|
+
events
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
//#endregion
|
|
1330
1390
|
//#region ../js-client-core/src/telemetry/ClientTelemetryEventCollector.ts
|
|
1331
1391
|
var ClientTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
1332
1392
|
constructor(options) {
|
|
1333
1393
|
super(options);
|
|
1394
|
+
_defineProperty(this, "evaluationEventSnapshotPreprocessor", void 0);
|
|
1334
1395
|
_defineProperty(this, "reporter", void 0);
|
|
1335
1396
|
_defineProperty(this, "_context", void 0);
|
|
1336
1397
|
this.reporter = new ClientEventReporter(options);
|
|
1398
|
+
this.evaluationEventSnapshotPreprocessor = new EvaluatedConfigEventPreprocessor(options.valueIdGenerator);
|
|
1337
1399
|
}
|
|
1338
1400
|
async updateContext(value) {
|
|
1339
1401
|
this.cancelScheduledFlush();
|
|
@@ -1349,6 +1411,20 @@ var ClientTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
|
1349
1411
|
this.cancelScheduledFlush();
|
|
1350
1412
|
await this.flushAndScheduleNext();
|
|
1351
1413
|
}
|
|
1414
|
+
async flush() {
|
|
1415
|
+
var _this$reporter;
|
|
1416
|
+
if (!this.reporter) return {
|
|
1417
|
+
success: false,
|
|
1418
|
+
fatalError: false
|
|
1419
|
+
};
|
|
1420
|
+
const evaluationSnapshot = await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());
|
|
1421
|
+
return await ((_this$reporter = this.reporter) === null || _this$reporter === void 0 ? void 0 : _this$reporter.report({
|
|
1422
|
+
context: this._context,
|
|
1423
|
+
discreteEvents: {},
|
|
1424
|
+
aggregatedEvents: { evaluatedConfig: this.aggregator.aggregate(evaluationSnapshot) },
|
|
1425
|
+
droppedEvents: { evaluatedConfig: evaluationSnapshot.droppedCount }
|
|
1426
|
+
}));
|
|
1427
|
+
}
|
|
1352
1428
|
};
|
|
1353
1429
|
//#endregion
|
|
1354
1430
|
//#region src/logger.ts
|
|
@@ -1475,6 +1551,28 @@ const parseHeaders = (raw) => {
|
|
|
1475
1551
|
return headers;
|
|
1476
1552
|
};
|
|
1477
1553
|
//#endregion
|
|
1554
|
+
//#region ../shared/src/base62-encoder.ts
|
|
1555
|
+
const BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
1556
|
+
const toBase62 = (buf, length) => {
|
|
1557
|
+
const ZERO = BigInt(0);
|
|
1558
|
+
const BASE = BigInt(62);
|
|
1559
|
+
const hex = Array.from(buf).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1560
|
+
let n = BigInt("0x" + hex);
|
|
1561
|
+
let result = "";
|
|
1562
|
+
while (n > ZERO) {
|
|
1563
|
+
result = BASE62[Number(n % BASE)] + result;
|
|
1564
|
+
n /= BASE;
|
|
1565
|
+
}
|
|
1566
|
+
return result.padStart(length, "0");
|
|
1567
|
+
};
|
|
1568
|
+
const BASE62_LENGTH = Math.ceil(128 / Math.log2(62));
|
|
1569
|
+
//#endregion
|
|
1570
|
+
//#region src/value-id-generator.ts
|
|
1571
|
+
const generateValueId = (v) => {
|
|
1572
|
+
var _v$toString;
|
|
1573
|
+
return toBase62(sha256(encodeUtf8((_v$toString = v === null || v === void 0 ? void 0 : v.toString()) !== null && _v$toString !== void 0 ? _v$toString : "")).subarray(0, 16), BASE62_LENGTH);
|
|
1574
|
+
};
|
|
1575
|
+
//#endregion
|
|
1478
1576
|
//#region src/ReactNativeTelemetryClient.ts
|
|
1479
1577
|
var ReactNativeTelemetryClient = class {
|
|
1480
1578
|
constructor(sdkKey, baseUrl, logger, urlFactory) {
|
|
@@ -1483,7 +1581,8 @@ var ReactNativeTelemetryClient = class {
|
|
|
1483
1581
|
sdkKey,
|
|
1484
1582
|
logger,
|
|
1485
1583
|
baseUrl,
|
|
1486
|
-
urlFactory
|
|
1584
|
+
urlFactory,
|
|
1585
|
+
valueIdGenerator: async (v) => generateValueId(v)
|
|
1487
1586
|
});
|
|
1488
1587
|
}
|
|
1489
1588
|
async updateContext(value) {
|
|
@@ -1498,8 +1597,15 @@ var ReactNativeTelemetryClient = class {
|
|
|
1498
1597
|
sanitizeEvaluatedConfigEvent(event) {
|
|
1499
1598
|
return {
|
|
1500
1599
|
...event,
|
|
1501
|
-
defaultValue:
|
|
1502
|
-
|
|
1600
|
+
defaultValue: mapToTelemetryValue({
|
|
1601
|
+
value: event.defaultValue,
|
|
1602
|
+
type: event.type
|
|
1603
|
+
}),
|
|
1604
|
+
evaluatedValue: mapToTelemetryValue({
|
|
1605
|
+
value: event.evaluatedValue,
|
|
1606
|
+
valueId: event.evaluatedValueId,
|
|
1607
|
+
type: event.type
|
|
1608
|
+
})
|
|
1503
1609
|
};
|
|
1504
1610
|
}
|
|
1505
1611
|
};
|
|
@@ -1525,7 +1631,7 @@ const createClient = (clientSdkKey, clientOptions) => {
|
|
|
1525
1631
|
const logger = (_clientOptions$logger = clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.logger) !== null && _clientOptions$logger !== void 0 ? _clientOptions$logger : createConsoleLogger("warn");
|
|
1526
1632
|
return new DefaultConfigDirectorClient(new ReactNativeTelemetryClient(clientSdkKey, (clientOptions === null || clientOptions === void 0 || (_clientOptions$connec = clientOptions.connection) === null || _clientOptions$connec === void 0 ? void 0 : _clientOptions$connec.url) ? urlFactory(clientOptions.connection.url) : CLIENT_BASE_URL, logger, urlFactory), clientSdkKey, {
|
|
1527
1633
|
sdkName: "react-native-sdk",
|
|
1528
|
-
sdkVersion: "0.
|
|
1634
|
+
sdkVersion: "0.9.0"
|
|
1529
1635
|
}, {
|
|
1530
1636
|
...clientOptions,
|
|
1531
1637
|
logger
|
|
@@ -1575,7 +1681,8 @@ var ConfigDirectorProvider = class extends Component {
|
|
|
1575
1681
|
appName: props.appName,
|
|
1576
1682
|
appVersion: props.appVersion
|
|
1577
1683
|
},
|
|
1578
|
-
logger: (_props$logger = props.logger) !== null && _props$logger !== void 0 ? _props$logger : createConsoleLogger("warn")
|
|
1684
|
+
logger: (_props$logger = props.logger) !== null && _props$logger !== void 0 ? _props$logger : createConsoleLogger("warn"),
|
|
1685
|
+
hooks: props.hooks
|
|
1579
1686
|
}),
|
|
1580
1687
|
status: "loading"
|
|
1581
1688
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@configdirector/react-native-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "React Native client SDK for ConfigDirector. ConfigDirector is a remote configuration and feature flag service.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ConfigDirector",
|
|
@@ -52,6 +52,9 @@
|
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"registry": "https://registry.npmjs.org/"
|
|
54
54
|
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@noble/hashes": "^2.2.0"
|
|
57
|
+
},
|
|
55
58
|
"devDependencies": {
|
|
56
59
|
"@babel/core": "^7.29.0",
|
|
57
60
|
"@eslint/js": "^10.0.1",
|
|
@@ -112,7 +115,7 @@
|
|
|
112
115
|
"^@eventsource/(.*)$": "<rootDir>/../eventsource/src/$1"
|
|
113
116
|
},
|
|
114
117
|
"transformIgnorePatterns": [
|
|
115
|
-
"node_modules/(?!((jest-)?react-native|@react-native(-community)
|
|
118
|
+
"node_modules/(?!((jest-)?react-native|@react-native(-community)?|@noble)/)"
|
|
116
119
|
]
|
|
117
120
|
}
|
|
118
121
|
}
|