@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" | "one-time";
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), `polling`, or `one-time`.
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` or `one-time`.
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) reject(this.prepareFatalError(state.status, state.error));
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 (!value) return {
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: value,
602
- parsedValueId: configState.valueId,
608
+ parsedValue: defaultValue,
609
+ parsedValueId: void 0,
603
610
  requestedType,
604
- usedDefault: false,
605
- reason: "found-match"
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
- if (!value) return;
616
- const num = Number.parseInt(value);
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
- if (!value) return;
622
- const num = Number.parseFloat(value);
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: JSON.parse(jsonString),
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
- if ((fetchError === null || fetchError === void 0 ? void 0 : fetchError.name) === "NotAllowedError") return true;
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
- this.pollingIntervalSeconds = (_options$pollingInter = options.pollingInterval) !== null && _options$pollingInter !== void 0 ? _options$pollingInter : 60;
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
- this.handleFetchError(fetchError);
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/OneTimeTransport.ts
862
- var OneTimeTransport = class extends PollingTransport {
863
- constructor(options) {
864
- super(options);
865
- this.pollingIntervalSeconds = 0;
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
- //#endregion
869
- //#region ../shared/src/url.ts
870
- const defaultUrlFactory = (input, base) => new URL(input, base === null || base === void 0 ? void 0 : base.toString());
871
- //#endregion
872
- //#region ../shared/src/constants.ts
873
- const CLIENT_BASE_URL = "https://client-sdk-api.configdirector.com";
874
- //#endregion
875
- //#region ../shared/src/instance-id.ts
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, _navigator, _internalClientOption2, _clientOptions$connec6, _clientOptions$hooks, _clientOptions$hooks2, _clientOptions$hooks3, _clientOptions$hooks4;
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: (_navigator = navigator) === null || _navigator === void 0 ? void 0 : _navigator.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 ((await this.flush()).fatalError) {
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 this.flushTimeout = setTimeout(() => this.flushAndScheduleNext(), this.flushIntervalDelay);
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
- await this.flush();
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.0.0"
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.0.0",
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",