@configdirector/react-native-sdk 1.0.0 → 1.3.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.
|
@@ -78,7 +78,7 @@ type ConfigDirectorMetaContext = {
|
|
|
78
78
|
appVersion?: string;
|
|
79
79
|
appName?: string;
|
|
80
80
|
};
|
|
81
|
-
type ConnectionMode = "streaming" | "polling"
|
|
81
|
+
type ConnectionMode = "streaming" | "polling";
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region ../js-client-core/src/types.d.ts
|
|
84
84
|
/**
|
|
@@ -94,22 +94,21 @@ type ConfigDirectorClientOptions = {
|
|
|
94
94
|
*/
|
|
95
95
|
connection?: {
|
|
96
96
|
/**
|
|
97
|
-
* The connection mode to be used, one of `streaming` (default)
|
|
97
|
+
* The connection mode to be used, one of `streaming` (default) or `polling`.
|
|
98
98
|
* If set to `streaming`, the connection will remain open and receive updates whenever
|
|
99
99
|
* config state is updated on the ConfigDirector dashboard.
|
|
100
100
|
* When set to `polling`, there will be an initial request to retrieve config state during
|
|
101
101
|
* initialization, and additional requests on a `pollingInterval`.
|
|
102
|
-
* The `one-time` connection mode will only retrieve config state during initialization and
|
|
103
|
-
* context updates. It will not poll for regular updates.
|
|
104
102
|
*
|
|
105
103
|
* Defaults to `streaming`
|
|
106
104
|
*/
|
|
107
105
|
mode?: ConnectionMode;
|
|
108
106
|
/**
|
|
109
107
|
* The polling interval in _seconds_ when the `mode` is set to `polling`. This option has no
|
|
110
|
-
* effect when the `mode` is set to `streaming
|
|
108
|
+
* effect when the `mode` is set to `streaming`.
|
|
111
109
|
*
|
|
112
|
-
* Defaults to 60 seconds
|
|
110
|
+
* Defaults to 300 seconds (5 minutes). Values below the minimum of 60 seconds are raised
|
|
111
|
+
* to 60 seconds.
|
|
113
112
|
*/
|
|
114
113
|
pollingInterval?: number;
|
|
115
114
|
/**
|
|
@@ -162,6 +161,7 @@ type ClientHooks = {
|
|
|
162
161
|
configsUpdated?: HookHandler<"configsUpdated"> | HookHandler<"configsUpdated">[];
|
|
163
162
|
contextUpdated?: HookHandler<"contextUpdated"> | HookHandler<"contextUpdated">[];
|
|
164
163
|
configEvaluated?: HookHandler<"configEvaluated"> | HookHandler<"configEvaluated">[];
|
|
164
|
+
connectionError?: HookHandler<"connectionError"> | HookHandler<"connectionError">[];
|
|
165
165
|
};
|
|
166
166
|
type ClientConnectAction = "initialization" | "context update" | "network resume";
|
|
167
167
|
type HookHandler<TEvent extends keyof ClientEvents> = (payload: ClientEvents[TEvent]) => void;
|
|
@@ -178,6 +178,9 @@ type ClientEvents = {
|
|
|
178
178
|
configEvaluated: {
|
|
179
179
|
evaluation: ConfigEvaluation;
|
|
180
180
|
};
|
|
181
|
+
connectionError: {
|
|
182
|
+
error: Error;
|
|
183
|
+
};
|
|
181
184
|
};
|
|
182
185
|
type WatchHandler<T extends ConfigValueType> = (message: T) => void;
|
|
183
186
|
/**
|
|
@@ -255,6 +255,7 @@ var EventSourceClient = class {
|
|
|
255
255
|
_defineProperty(this, "DEFAULT_CALCULATE_RECONNECT_DELAY", () => this.serverReconnectionTime);
|
|
256
256
|
_defineProperty(this, "url", void 0);
|
|
257
257
|
_defineProperty(this, "headers", void 0);
|
|
258
|
+
_defineProperty(this, "body", void 0);
|
|
258
259
|
_defineProperty(this, "requestOptions", void 0);
|
|
259
260
|
_defineProperty(this, "lastEventId", void 0);
|
|
260
261
|
_defineProperty(this, "reconnectAttempt", 0);
|
|
@@ -276,8 +277,9 @@ var EventSourceClient = class {
|
|
|
276
277
|
Accept: "text/event-stream",
|
|
277
278
|
...options.headers
|
|
278
279
|
};
|
|
280
|
+
const body = options.body;
|
|
281
|
+
this.body = typeof body === "function" ? body : () => body;
|
|
279
282
|
this.requestOptions = {
|
|
280
|
-
body: options.body,
|
|
281
283
|
method: (_options$method = options.method) !== null && _options$method !== void 0 ? _options$method : "GET",
|
|
282
284
|
mode: options.mode,
|
|
283
285
|
credentials: options.credentials,
|
|
@@ -333,6 +335,7 @@ var EventSourceClient = class {
|
|
|
333
335
|
this._readyState = ReadyState.CONNECTING;
|
|
334
336
|
this._fetch(this.url, {
|
|
335
337
|
...this.requestOptions,
|
|
338
|
+
body: this.body(),
|
|
336
339
|
headers: this.buildRequestHeaders(),
|
|
337
340
|
signal: this.abortController.signal,
|
|
338
341
|
cache: "no-store"
|
|
@@ -466,7 +469,11 @@ var StreamingTransport = class {
|
|
|
466
469
|
},
|
|
467
470
|
shouldReconnect: (state) => {
|
|
468
471
|
const reconnect = !this.isStatusFatal(state.status);
|
|
469
|
-
if (!reconnect)
|
|
472
|
+
if (!reconnect) {
|
|
473
|
+
const error = this.prepareFatalError(state.status, state.error);
|
|
474
|
+
this.eventEmitter.emit("connectionError", error);
|
|
475
|
+
reject(error);
|
|
476
|
+
}
|
|
470
477
|
return reconnect;
|
|
471
478
|
},
|
|
472
479
|
calculateReconnectDelay: (state) => {
|
|
@@ -549,7 +556,7 @@ const isNumericNativeType = (requestedType) => {
|
|
|
549
556
|
const parseConfigValue = (configState, defaultValue) => {
|
|
550
557
|
const value = configState.value;
|
|
551
558
|
const requestedType = getRequestedType(defaultValue);
|
|
552
|
-
if (
|
|
559
|
+
if (value == null) return {
|
|
553
560
|
parsedValue: defaultValue,
|
|
554
561
|
parsedValueId: void 0,
|
|
555
562
|
requestedType,
|
|
@@ -564,7 +571,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
564
571
|
usedDefault: false,
|
|
565
572
|
reason: "found-match"
|
|
566
573
|
};
|
|
567
|
-
if (typeof defaultValue === "boolean" && (configState.type === "boolean" || configState.type === "string")) {
|
|
574
|
+
if (typeof defaultValue === "boolean" && (configState.type === "boolean" || configState.type === "string" || configState.type === "enum")) {
|
|
568
575
|
const boolValue = parseConfigBoolean(value);
|
|
569
576
|
const hasBoolean = typeof boolValue === "boolean";
|
|
570
577
|
return {
|
|
@@ -598,11 +605,11 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
598
605
|
};
|
|
599
606
|
}
|
|
600
607
|
return {
|
|
601
|
-
parsedValue:
|
|
602
|
-
parsedValueId:
|
|
608
|
+
parsedValue: defaultValue,
|
|
609
|
+
parsedValueId: void 0,
|
|
603
610
|
requestedType,
|
|
604
|
-
usedDefault:
|
|
605
|
-
reason: "
|
|
611
|
+
usedDefault: true,
|
|
612
|
+
reason: "type-mismatch"
|
|
606
613
|
};
|
|
607
614
|
};
|
|
608
615
|
const parseConfigBoolean = (value) => {
|
|
@@ -612,17 +619,22 @@ const parseConfigBoolean = (value) => {
|
|
|
612
619
|
return lowerValue === "true";
|
|
613
620
|
};
|
|
614
621
|
const parseConfigInteger = (value) => {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
if (isNaN(num) || !isFinite(num)) return;
|
|
618
|
-
return num;
|
|
622
|
+
const num = parseStrictNumber(value);
|
|
623
|
+
return num == null ? void 0 : Math.trunc(num);
|
|
619
624
|
};
|
|
620
625
|
const parseConfigFloat = (value) => {
|
|
621
|
-
|
|
622
|
-
|
|
626
|
+
return parseStrictNumber(value);
|
|
627
|
+
};
|
|
628
|
+
const parseStrictNumber = (value) => {
|
|
629
|
+
if (!value || !isDecimalCharacters(value)) return;
|
|
630
|
+
const num = Number(value);
|
|
623
631
|
if (isNaN(num) || !isFinite(num)) return;
|
|
624
632
|
return num;
|
|
625
633
|
};
|
|
634
|
+
const isDecimalCharacters = (value) => {
|
|
635
|
+
for (const character of value) if (!(character >= "0" && character <= "9") && !"+-.eE".includes(character)) return false;
|
|
636
|
+
return true;
|
|
637
|
+
};
|
|
626
638
|
const parseJson = (jsonString, defaultValue, requestedType, valueId) => {
|
|
627
639
|
if (typeof defaultValue === "string") return {
|
|
628
640
|
parsedValue: jsonString,
|
|
@@ -632,8 +644,16 @@ const parseJson = (jsonString, defaultValue, requestedType, valueId) => {
|
|
|
632
644
|
reason: "found-match"
|
|
633
645
|
};
|
|
634
646
|
try {
|
|
647
|
+
const parsed = JSON.parse(jsonString);
|
|
648
|
+
if (!isJsonTypeCompatible(parsed, defaultValue)) return {
|
|
649
|
+
parsedValue: defaultValue,
|
|
650
|
+
parsedValueId: void 0,
|
|
651
|
+
requestedType,
|
|
652
|
+
usedDefault: true,
|
|
653
|
+
reason: "type-mismatch"
|
|
654
|
+
};
|
|
635
655
|
return {
|
|
636
|
-
parsedValue:
|
|
656
|
+
parsedValue: parsed,
|
|
637
657
|
parsedValueId: valueId,
|
|
638
658
|
requestedType,
|
|
639
659
|
usedDefault: false,
|
|
@@ -649,6 +669,12 @@ const parseJson = (jsonString, defaultValue, requestedType, valueId) => {
|
|
|
649
669
|
};
|
|
650
670
|
}
|
|
651
671
|
};
|
|
672
|
+
const isJsonTypeCompatible = (parsed, defaultValue) => {
|
|
673
|
+
if (parsed === null) return false;
|
|
674
|
+
const defaultType = typeof defaultValue;
|
|
675
|
+
if (defaultType === "bigint") return typeof parsed === "number";
|
|
676
|
+
return typeof parsed === defaultType;
|
|
677
|
+
};
|
|
652
678
|
//#endregion
|
|
653
679
|
//#region ../shared/src/logger.ts
|
|
654
680
|
const LEVELS = {
|
|
@@ -716,6 +742,107 @@ const createDefaultLogger = (level, messageDecorator) => {
|
|
|
716
742
|
return new DefaultConsoleLogger(level !== null && level !== void 0 ? level : "warn", messageDecorator !== null && messageDecorator !== void 0 ? messageDecorator : new LogMessageDecorator());
|
|
717
743
|
};
|
|
718
744
|
//#endregion
|
|
745
|
+
//#region ../shared/src/url.ts
|
|
746
|
+
const defaultUrlFactory = (input, base) => new URL(input, base === null || base === void 0 ? void 0 : base.toString());
|
|
747
|
+
//#endregion
|
|
748
|
+
//#region ../shared/src/constants.ts
|
|
749
|
+
const CLIENT_BASE_URL = "https://client-sdk-api.configdirector.com";
|
|
750
|
+
//#endregion
|
|
751
|
+
//#region ../shared/src/instance-id.ts
|
|
752
|
+
const generateInstanceId = () => {
|
|
753
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
754
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (placeholder) => {
|
|
755
|
+
const random = Math.random() * 16 | 0;
|
|
756
|
+
return (placeholder === "x" ? random : random & 3 | 8).toString(16);
|
|
757
|
+
});
|
|
758
|
+
};
|
|
759
|
+
//#endregion
|
|
760
|
+
//#region ../js-client-core/src/instance-id.ts
|
|
761
|
+
const STORAGE_KEY = "configdirector-sdk:instance-id";
|
|
762
|
+
const RECORD_VERSION = 1;
|
|
763
|
+
const MAX_AGE_MS = 360 * 60 * 1e3;
|
|
764
|
+
const CHECKSUM_SALT = "configdirector.instanceId.v1";
|
|
765
|
+
const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
766
|
+
const fnv1a = (input, offsetBasis) => {
|
|
767
|
+
let hash = offsetBasis;
|
|
768
|
+
for (let i = 0; i < input.length; i++) {
|
|
769
|
+
hash ^= input.charCodeAt(i);
|
|
770
|
+
hash = Math.imul(hash, 16777619);
|
|
771
|
+
}
|
|
772
|
+
return hash >>> 0;
|
|
773
|
+
};
|
|
774
|
+
const checksumFor = (id, createdAt) => {
|
|
775
|
+
const payload = `${CHECKSUM_SALT}|${id}|${createdAt}`;
|
|
776
|
+
const low = fnv1a(payload, 2166136261);
|
|
777
|
+
return fnv1a(`${low}|${payload}`, 16777619).toString(16).padStart(8, "0") + low.toString(16).padStart(8, "0");
|
|
778
|
+
};
|
|
779
|
+
const getLocalStorage = () => {
|
|
780
|
+
try {
|
|
781
|
+
var _localStorage;
|
|
782
|
+
return (_localStorage = globalThis.localStorage) !== null && _localStorage !== void 0 ? _localStorage : void 0;
|
|
783
|
+
} catch {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
const isUsableRecord = (record) => {
|
|
788
|
+
if (!record || typeof record !== "object") return false;
|
|
789
|
+
const { v, id, createdAt, checksum } = record;
|
|
790
|
+
if (v !== RECORD_VERSION || typeof id !== "string" || typeof checksum !== "string") return false;
|
|
791
|
+
if (typeof createdAt !== "number" || !Number.isInteger(createdAt) || createdAt <= 0) return false;
|
|
792
|
+
if (!UUID_V4_PATTERN.test(id)) return false;
|
|
793
|
+
return checksum === checksumFor(id, createdAt);
|
|
794
|
+
};
|
|
795
|
+
const readStoredInstanceId = (storage, logger) => {
|
|
796
|
+
let raw;
|
|
797
|
+
try {
|
|
798
|
+
raw = storage.getItem(STORAGE_KEY);
|
|
799
|
+
} catch (error) {
|
|
800
|
+
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] Could not read the stored instance id, generating a new one", error);
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
if (!raw) return;
|
|
804
|
+
let record;
|
|
805
|
+
try {
|
|
806
|
+
record = JSON.parse(raw);
|
|
807
|
+
} catch {
|
|
808
|
+
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one");
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (!isUsableRecord(record)) {
|
|
812
|
+
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] The stored instance id failed validation, generating a new one");
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
const age = Date.now() - record.createdAt;
|
|
816
|
+
if (age < 0 || age >= MAX_AGE_MS) {
|
|
817
|
+
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] The stored instance id has expired, generating a new one");
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
return record.id;
|
|
821
|
+
};
|
|
822
|
+
const storeInstanceId = (storage, id, logger) => {
|
|
823
|
+
const createdAt = Date.now();
|
|
824
|
+
const record = {
|
|
825
|
+
v: RECORD_VERSION,
|
|
826
|
+
id,
|
|
827
|
+
createdAt,
|
|
828
|
+
checksum: checksumFor(id, createdAt)
|
|
829
|
+
};
|
|
830
|
+
try {
|
|
831
|
+
storage.setItem(STORAGE_KEY, JSON.stringify(record));
|
|
832
|
+
} catch (error) {
|
|
833
|
+
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] Could not persist the instance id", error);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
const resolveInstanceId = (logger) => {
|
|
837
|
+
const storage = getLocalStorage();
|
|
838
|
+
if (!storage) return generateInstanceId();
|
|
839
|
+
const storedInstanceId = readStoredInstanceId(storage, logger);
|
|
840
|
+
if (storedInstanceId) return storedInstanceId;
|
|
841
|
+
const instanceId = generateInstanceId();
|
|
842
|
+
storeInstanceId(storage, instanceId, logger);
|
|
843
|
+
return instanceId;
|
|
844
|
+
};
|
|
845
|
+
//#endregion
|
|
719
846
|
//#region ../shared/src/transport/AbstractPollingTransport.ts
|
|
720
847
|
var AbstractPollingTransport = class {
|
|
721
848
|
constructor() {
|
|
@@ -734,6 +861,7 @@ var AbstractPollingTransport = class {
|
|
|
734
861
|
async handleNonOkResponse(response) {
|
|
735
862
|
if (!response.ok) if (this.isStatusFatal(response.status)) {
|
|
736
863
|
this.fatalError = true;
|
|
864
|
+
this.close();
|
|
737
865
|
throw this.prepareFatalResponseStatusError(response.status, await response.text());
|
|
738
866
|
} else throw new ConfigDirectorConnectionError(`Connection failed with status: ${response.status}`, response.status);
|
|
739
867
|
}
|
|
@@ -754,9 +882,7 @@ var AbstractPollingTransport = class {
|
|
|
754
882
|
return !!status && status >= 400 && status < 500;
|
|
755
883
|
}
|
|
756
884
|
isFetchErrorFatal(fetchError) {
|
|
757
|
-
|
|
758
|
-
else if (fetchError instanceof TypeError) return true;
|
|
759
|
-
return false;
|
|
885
|
+
return (fetchError === null || fetchError === void 0 ? void 0 : fetchError.name) === "NotAllowedError";
|
|
760
886
|
}
|
|
761
887
|
get isConnected() {
|
|
762
888
|
return this.pollingInterval !== void 0;
|
|
@@ -805,7 +931,9 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
805
931
|
this.options = options;
|
|
806
932
|
this.logger = options.logger;
|
|
807
933
|
this.url = options.resolveUrl("client/polling/v1", options.baseUrl);
|
|
808
|
-
|
|
934
|
+
const requestedInterval = (_options$pollingInter = options.pollingInterval) !== null && _options$pollingInter !== void 0 ? _options$pollingInter : 300;
|
|
935
|
+
if (requestedInterval < 60) this.logger.warn(`[PollingTransport] pollingInterval of ${requestedInterval} seconds is below the minimum of 60 seconds. Using 60 seconds.`);
|
|
936
|
+
this.pollingIntervalSeconds = Math.max(requestedInterval, 60);
|
|
809
937
|
}
|
|
810
938
|
async connect(context, timeout) {
|
|
811
939
|
this.clearPollingInterval();
|
|
@@ -844,7 +972,12 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
844
972
|
this.eventEmitter.emit("configSetReceived", json);
|
|
845
973
|
}
|
|
846
974
|
} catch (fetchError) {
|
|
847
|
-
|
|
975
|
+
try {
|
|
976
|
+
this.handleFetchError(fetchError);
|
|
977
|
+
} catch (handledError) {
|
|
978
|
+
if (this.fatalError) this.eventEmitter.emit("connectionError", handledError);
|
|
979
|
+
throw handledError;
|
|
980
|
+
}
|
|
848
981
|
}
|
|
849
982
|
}
|
|
850
983
|
on(name, handler) {
|
|
@@ -858,34 +991,28 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
858
991
|
}
|
|
859
992
|
};
|
|
860
993
|
//#endregion
|
|
861
|
-
//#region ../js-client-core/src/
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
994
|
+
//#region ../js-client-core/src/browser-globals.ts
|
|
995
|
+
const read = (readValue) => {
|
|
996
|
+
try {
|
|
997
|
+
return readValue(globalThis);
|
|
998
|
+
} catch {
|
|
999
|
+
return;
|
|
866
1000
|
}
|
|
867
1001
|
};
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
const generateInstanceId = () => {
|
|
877
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
878
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (placeholder) => {
|
|
879
|
-
const random = Math.random() * 16 | 0;
|
|
880
|
-
return (placeholder === "x" ? random : random & 3 | 8).toString(16);
|
|
881
|
-
});
|
|
882
|
-
};
|
|
1002
|
+
const readUserAgent = () => read((globals) => {
|
|
1003
|
+
var _globals$navigator;
|
|
1004
|
+
return (_globals$navigator = globals.navigator) === null || _globals$navigator === void 0 ? void 0 : _globals$navigator.userAgent;
|
|
1005
|
+
});
|
|
1006
|
+
const readHost = () => read((globals) => {
|
|
1007
|
+
var _globals$location;
|
|
1008
|
+
return (_globals$location = globals.location) === null || _globals$location === void 0 ? void 0 : _globals$location.host;
|
|
1009
|
+
});
|
|
883
1010
|
//#endregion
|
|
884
1011
|
//#region ../js-client-core/src/DefaultConfigDirectorClient.ts
|
|
885
1012
|
const MAX_EXPONENTIAL_DELAY = 9;
|
|
886
1013
|
var DefaultConfigDirectorClient = class {
|
|
887
1014
|
constructor(telemetryClient, clientSdkKey, sdkOptions, clientOptions, internalClientOptions) {
|
|
888
|
-
var _clientOptions$logger, _clientOptions$connec, _clientOptions$connec2, _internalClientOption, _this$parseUrl, _clientOptions$connec3, _clientOptions$connec4, _clientOptions$connec5,
|
|
1015
|
+
var _clientOptions$logger, _clientOptions$connec, _clientOptions$connec2, _internalClientOption, _this$parseUrl, _clientOptions$connec3, _clientOptions$connec4, _clientOptions$connec5, _internalClientOption2, _clientOptions$connec6, _clientOptions$hooks, _clientOptions$hooks2, _clientOptions$hooks3, _clientOptions$hooks4, _clientOptions$hooks5;
|
|
889
1016
|
_defineProperty(this, "logger", void 0);
|
|
890
1017
|
_defineProperty(this, "telemetryClient", void 0);
|
|
891
1018
|
_defineProperty(this, "configSet", void 0);
|
|
@@ -901,8 +1028,8 @@ var DefaultConfigDirectorClient = class {
|
|
|
901
1028
|
_defineProperty(this, "currentContext", void 0);
|
|
902
1029
|
_defineProperty(this, "connectionMode", void 0);
|
|
903
1030
|
_defineProperty(this, "instanceId", void 0);
|
|
904
|
-
this.instanceId = generateInstanceId();
|
|
905
1031
|
this.logger = (_clientOptions$logger = clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.logger) !== null && _clientOptions$logger !== void 0 ? _clientOptions$logger : createDefaultLogger();
|
|
1032
|
+
this.instanceId = resolveInstanceId(this.logger);
|
|
906
1033
|
this.timeout = (_clientOptions$connec = clientOptions === null || clientOptions === void 0 || (_clientOptions$connec2 = clientOptions.connection) === null || _clientOptions$connec2 === void 0 ? void 0 : _clientOptions$connec2.timeout) !== null && _clientOptions$connec !== void 0 ? _clientOptions$connec : 3e3;
|
|
907
1034
|
this.validateSdkKeyPresence(clientSdkKey);
|
|
908
1035
|
const urlFactory = (_internalClientOption = internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.urlFactory) !== null && _internalClientOption !== void 0 ? _internalClientOption : defaultUrlFactory;
|
|
@@ -919,7 +1046,8 @@ var DefaultConfigDirectorClient = class {
|
|
|
919
1046
|
...clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.metadata,
|
|
920
1047
|
sdkName: sdkOptions.sdkName,
|
|
921
1048
|
sdkVersion: sdkOptions.sdkVersion,
|
|
922
|
-
userAgent: (
|
|
1049
|
+
userAgent: readUserAgent(),
|
|
1050
|
+
host: readHost()
|
|
923
1051
|
},
|
|
924
1052
|
logger: this.logger,
|
|
925
1053
|
fetch: internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.fetch,
|
|
@@ -946,10 +1074,15 @@ var DefaultConfigDirectorClient = class {
|
|
|
946
1074
|
}
|
|
947
1075
|
this.logger.debug("[ConfigDirectorClient] ConfigSet updated from server:", { keys: configKeys });
|
|
948
1076
|
});
|
|
1077
|
+
this.transport.on("connectionError", (error) => {
|
|
1078
|
+
this.logger.error("[ConfigDirectorClient] The connection encountered an unrecoverable error and will not be retried. Configs will no longer receive updates.", error);
|
|
1079
|
+
this.emit("connectionError", { error });
|
|
1080
|
+
});
|
|
949
1081
|
this.registerHandler("clientReady", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks = clientOptions.hooks) === null || _clientOptions$hooks === void 0 ? void 0 : _clientOptions$hooks.clientReady);
|
|
950
1082
|
this.registerHandler("configEvaluated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks2 = clientOptions.hooks) === null || _clientOptions$hooks2 === void 0 ? void 0 : _clientOptions$hooks2.configEvaluated);
|
|
951
1083
|
this.registerHandler("configsUpdated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks3 = clientOptions.hooks) === null || _clientOptions$hooks3 === void 0 ? void 0 : _clientOptions$hooks3.configsUpdated);
|
|
952
1084
|
this.registerHandler("contextUpdated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks4 = clientOptions.hooks) === null || _clientOptions$hooks4 === void 0 ? void 0 : _clientOptions$hooks4.contextUpdated);
|
|
1085
|
+
this.registerHandler("connectionError", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks5 = clientOptions.hooks) === null || _clientOptions$hooks5 === void 0 ? void 0 : _clientOptions$hooks5.connectionError);
|
|
953
1086
|
}
|
|
954
1087
|
registerHandler(event, handler) {
|
|
955
1088
|
if (!handler) return;
|
|
@@ -958,7 +1091,6 @@ var DefaultConfigDirectorClient = class {
|
|
|
958
1091
|
}
|
|
959
1092
|
getTransportConstructor(connectionMode) {
|
|
960
1093
|
switch (connectionMode) {
|
|
961
|
-
case "one-time": return OneTimeTransport;
|
|
962
1094
|
case "polling": return PollingTransport;
|
|
963
1095
|
default: return StreamingTransport;
|
|
964
1096
|
}
|
|
@@ -978,7 +1110,8 @@ var DefaultConfigDirectorClient = class {
|
|
|
978
1110
|
this.ready = false;
|
|
979
1111
|
this.readyPromise = new Promise((resolve) => {
|
|
980
1112
|
this.readyResolve = resolve;
|
|
981
|
-
}).then(() => {
|
|
1113
|
+
}).then((cancelled) => {
|
|
1114
|
+
if (cancelled) return;
|
|
982
1115
|
this.ready = true;
|
|
983
1116
|
this.initializing = false;
|
|
984
1117
|
this.emit("clientReady", { action: caller });
|
|
@@ -1143,10 +1276,11 @@ var DefaultConfigDirectorClient = class {
|
|
|
1143
1276
|
var _this$readyResolve2;
|
|
1144
1277
|
this.logger.debug("[ConfigDirectorClient] close() has been called, closing connection to server");
|
|
1145
1278
|
clearTimeout(this.timeoutTimer);
|
|
1146
|
-
(_this$readyResolve2 = this.readyResolve) === null || _this$readyResolve2 === void 0 || _this$readyResolve2.call(this);
|
|
1279
|
+
(_this$readyResolve2 = this.readyResolve) === null || _this$readyResolve2 === void 0 || _this$readyResolve2.call(this, true);
|
|
1147
1280
|
this.telemetryClient.close();
|
|
1148
1281
|
this.transport.close();
|
|
1149
1282
|
this.ready = false;
|
|
1283
|
+
this.initializing = false;
|
|
1150
1284
|
}
|
|
1151
1285
|
dispose() {
|
|
1152
1286
|
this.clear();
|
|
@@ -1368,11 +1502,25 @@ var TelemetryEventCollector = class {
|
|
|
1368
1502
|
this.flushTimeout = setTimeout(() => this.flushAndScheduleNext(), initialDelay);
|
|
1369
1503
|
}
|
|
1370
1504
|
async flushAndScheduleNext() {
|
|
1371
|
-
if (
|
|
1505
|
+
if (!this.collectEvents) return;
|
|
1506
|
+
let response;
|
|
1507
|
+
try {
|
|
1508
|
+
response = await this.flush();
|
|
1509
|
+
} catch (error) {
|
|
1510
|
+
this.logger.warn("[TelemetryEventCollector] Error flushing telemetry events: ", error);
|
|
1511
|
+
response = {
|
|
1512
|
+
success: false,
|
|
1513
|
+
fatalError: false
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
if (response.fatalError) {
|
|
1372
1517
|
this.collectEvents = false;
|
|
1373
1518
|
this.close();
|
|
1374
1519
|
this.logger.warn("[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.");
|
|
1375
|
-
} else
|
|
1520
|
+
} else if (this.collectEvents) {
|
|
1521
|
+
this.cancelScheduledFlush();
|
|
1522
|
+
this.flushTimeout = setTimeout(() => this.flushAndScheduleNext(), this.flushIntervalDelay);
|
|
1523
|
+
}
|
|
1376
1524
|
}
|
|
1377
1525
|
cancelScheduledFlush() {
|
|
1378
1526
|
clearTimeout(this.flushTimeout);
|
|
@@ -1380,7 +1528,11 @@ var TelemetryEventCollector = class {
|
|
|
1380
1528
|
async close() {
|
|
1381
1529
|
this.collectEvents = false;
|
|
1382
1530
|
clearTimeout(this.flushTimeout);
|
|
1383
|
-
|
|
1531
|
+
try {
|
|
1532
|
+
await this.flush();
|
|
1533
|
+
} catch (error) {
|
|
1534
|
+
this.logger.warn("[TelemetryEventCollector] Error flushing telemetry events during close: ", error);
|
|
1535
|
+
}
|
|
1384
1536
|
this.evaluationEventQueue.clear();
|
|
1385
1537
|
}
|
|
1386
1538
|
dispose() {
|
|
@@ -1649,7 +1801,7 @@ const createClient = (clientSdkKey, clientOptions) => {
|
|
|
1649
1801
|
var _clientOptions$logger, _clientOptions$connec;
|
|
1650
1802
|
const sdkIdentity = {
|
|
1651
1803
|
sdkName: "react-native-sdk",
|
|
1652
|
-
sdkVersion: "1.
|
|
1804
|
+
sdkVersion: "1.3.0"
|
|
1653
1805
|
};
|
|
1654
1806
|
const logger = (_clientOptions$logger = clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.logger) !== null && _clientOptions$logger !== void 0 ? _clientOptions$logger : createConsoleLogger("warn");
|
|
1655
1807
|
return new DefaultConfigDirectorClient(new ReactNativeTelemetryClient({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@configdirector/react-native-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.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",
|