@configdirector/react-native-sdk 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/dist/configdirector-react-native-testing.d.mts +1 -1
- package/dist/configdirector-react-native-testing.mjs +2 -2
- package/dist/configdirector-react-native.d.mts +2 -2
- package/dist/configdirector-react-native.mjs +47 -39
- package/dist/{installedTestClient-BluKT8Qj.mjs → installedTestClient-BaCuY_Ru.mjs} +65 -41
- package/dist/{types-BBQmjjf5.d.mts → types-DmbDeZqL.d.mts} +28 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,10 +11,13 @@ npm install --save @configdirector/react-native-sdk
|
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Install `@react-native-async-storage/async-storage` as well, so the SDK recognizes the app install
|
|
14
|
-
across app starts
|
|
15
|
-
the SDK stores for the install, so the context
|
|
16
|
-
active user, however often the app is opened.
|
|
17
|
-
|
|
14
|
+
across app starts and keeps the last values it received on the device. For a context without an
|
|
15
|
+
`id`, ConfigDirector derives an identifier from an ID the SDK stores for the install, so the context
|
|
16
|
+
keeps that identifier, and counts as one monthly active user, however often the app is opened. The
|
|
17
|
+
last values are served on the next app start of the same context until live values arrive, so an
|
|
18
|
+
app opened without a network shows them instead of the in-code default values. It is an optional
|
|
19
|
+
peer dependency and works in Expo Go. Without it, every app start looks like a new install, nothing
|
|
20
|
+
is kept on the device, and the SDK logs a warning.
|
|
18
21
|
|
|
19
22
|
```bash
|
|
20
23
|
npm install --save @react-native-async-storage/async-storage
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as NativeJsonValue, d as ConfigDirectorContext, i as ConfigDirectorClient, l as NativeValue, p as ConfigDirectorLogger, u as NativeValues } from "./types-
|
|
1
|
+
import { c as NativeJsonValue, d as ConfigDirectorContext, i as ConfigDirectorClient, l as NativeValue, p as ConfigDirectorLogger, u as NativeValues } from "./types-DmbDeZqL.mjs";
|
|
2
2
|
|
|
3
3
|
//#region ../shared/src/errors.d.ts
|
|
4
4
|
declare class ConfigDirectorConnectionError extends Error {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createDefaultLogger, d as ConfigDirectorConnectionError, f as ConfigDirectorValidationError, l as nativeValueConfigState, m as _defineProperty, p as Emitter, r as DefaultConfigDirectorClient, s as discardingTelemetryClient, t as INSTALLED_TEST_CLIENT_SLOT } from "./installedTestClient-
|
|
1
|
+
import { c as createDefaultLogger, d as ConfigDirectorConnectionError, f as ConfigDirectorValidationError, l as nativeValueConfigState, m as _defineProperty, p as Emitter, r as DefaultConfigDirectorClient, s as discardingTelemetryClient, t as INSTALLED_TEST_CLIENT_SLOT } from "./installedTestClient-BaCuY_Ru.mjs";
|
|
2
2
|
//#region ../js-client-core/src/testing/InMemoryConnection.ts
|
|
3
3
|
const TEST_ENVIRONMENT = {
|
|
4
4
|
environmentId: "test-environment",
|
|
@@ -295,7 +295,7 @@ const installTestClient = (testClient) => {
|
|
|
295
295
|
const createTestClient = (options) => {
|
|
296
296
|
return createTestClient$1({
|
|
297
297
|
sdkName: "react-native-sdk",
|
|
298
|
-
sdkVersion: "1.
|
|
298
|
+
sdkVersion: "1.10.0"
|
|
299
299
|
}, options);
|
|
300
300
|
};
|
|
301
301
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ConfigDirectorClientOptions, d as ConfigDirectorContext, f as ConfigDirectorLogMessageDecorator, g as
|
|
1
|
+
import { _ as ConnectionMode, a as ConfigDirectorClientOptions, d as ConfigDirectorContext, f as ConfigDirectorLogMessageDecorator, g as ConfigValueType, h as ConfigEvaluation, i as ConfigDirectorClient, m as ConfigDirectorLoggingLevel, n as CachingProvider, o as OfflineValue, p as ConfigDirectorLogger, r as ClientHooks, s as OfflineValues, t as CachingOptions, v as EvaluationReason } from "./types-DmbDeZqL.mjs";
|
|
2
2
|
import { Component, PropsWithChildren } from "react";
|
|
3
3
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
|
|
@@ -151,4 +151,4 @@ declare class ConfigDirectorReactContextError extends Error {
|
|
|
151
151
|
//#region src/logger.d.ts
|
|
152
152
|
declare const createConsoleLogger: (level?: ConfigDirectorLoggingLevel) => DefaultConsoleLogger;
|
|
153
153
|
//#endregion
|
|
154
|
-
export { type CachingOptions, type CachingProvider, type ClientStatus, type ConfigDirectorClient, type ConfigDirectorClientOptions, type ConfigDirectorContext, type ConfigDirectorLogger, type ConfigDirectorLoggingLevel, ConfigDirectorProvider, type ConfigDirectorProviderClientProps, type ConfigDirectorProviderOptions, type ConfigDirectorProviderProps, ConfigDirectorReactContextError, type ConnectionMode, type NetInfoSubscribe, type OfflineValue, type OfflineValues, createClient, createConsoleLogger, useClient, useConfigValue, useContext };
|
|
154
|
+
export { type CachingOptions, type CachingProvider, type ClientStatus, type ConfigDirectorClient, type ConfigDirectorClientOptions, type ConfigDirectorContext, type ConfigDirectorLogger, type ConfigDirectorLoggingLevel, ConfigDirectorProvider, type ConfigDirectorProviderClientProps, type ConfigDirectorProviderOptions, type ConfigDirectorProviderProps, ConfigDirectorReactContextError, type ConfigEvaluation, type ConnectionMode, type EvaluationReason, type NetInfoSubscribe, type OfflineValue, type OfflineValues, createClient, createConsoleLogger, useClient, useConfigValue, useContext };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DEFAULT_CACHING_SIZE_LIMIT_BYTES, c as createDefaultLogger, i as CACHED_VALUES_STORAGE_KEY_PREFIX, m as _defineProperty, n as readInstalledTestClient, o as fetchWithTimeout, r as DefaultConfigDirectorClient, u as isFetchErrorFatal } from "./installedTestClient-
|
|
1
|
+
import { a as DEFAULT_CACHING_SIZE_LIMIT_BYTES, c as createDefaultLogger, i as CACHED_VALUES_STORAGE_KEY_PREFIX, m as _defineProperty, n as readInstalledTestClient, o as fetchWithTimeout, r as DefaultConfigDirectorClient, u as isFetchErrorFatal } from "./installedTestClient-BaCuY_Ru.mjs";
|
|
2
2
|
import React, { Component, useContext as useContext$1 } from "react";
|
|
3
3
|
import { AppState, NativeModules } from "react-native";
|
|
4
4
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
@@ -65,20 +65,24 @@ var ClientEventReporter = class {
|
|
|
65
65
|
_defineProperty(this, "metaContext", void 0);
|
|
66
66
|
_defineProperty(this, "logger", void 0);
|
|
67
67
|
_defineProperty(this, "url", void 0);
|
|
68
|
+
_defineProperty(this, "clientSession", void 0);
|
|
68
69
|
_defineProperty(this, "executeRequests", true);
|
|
69
70
|
this.sdkKey = options.sdkKey;
|
|
70
71
|
this.logger = options.logger;
|
|
71
72
|
this.sdkIdentity = options.sdkIdentity;
|
|
72
73
|
this.metaContext = options.metaContext;
|
|
73
74
|
this.url = options.urlFactory("client/telemetry/v1", options.baseUrl);
|
|
75
|
+
this.clientSession = options.clientSession;
|
|
74
76
|
}
|
|
75
77
|
async report({ context, discreteEvents, aggregatedEvents, droppedEvents }) {
|
|
76
78
|
if (!this.executeRequests) return {
|
|
77
79
|
success: false,
|
|
78
80
|
fatalError: true
|
|
79
81
|
};
|
|
82
|
+
const { instanceId } = await this.clientSession;
|
|
80
83
|
const eventReport = {
|
|
81
84
|
clientSdkKey: this.sdkKey,
|
|
85
|
+
instanceId,
|
|
82
86
|
metaContext: {
|
|
83
87
|
sdkName: this.sdkIdentity.sdkName,
|
|
84
88
|
sdkVersion: this.sdkIdentity.sdkVersion,
|
|
@@ -538,6 +542,41 @@ const findAsyncStorage = (logger) => importAsyncStorage().then((lookup) => {
|
|
|
538
542
|
return lookup;
|
|
539
543
|
});
|
|
540
544
|
//#endregion
|
|
545
|
+
//#region src/cachingProvider.ts
|
|
546
|
+
const asyncStorageCachingProvider = (asyncStorage) => (clientSdkKeyDigest) => {
|
|
547
|
+
const storageKey = clientSdkKeyDigest.then((digest) => CACHED_VALUES_STORAGE_KEY_PREFIX + digest);
|
|
548
|
+
return {
|
|
549
|
+
read: async () => {
|
|
550
|
+
const lookup = await asyncStorage;
|
|
551
|
+
return lookup.outcome === "installed" ? lookup.storage.getItem(await storageKey) : void 0;
|
|
552
|
+
},
|
|
553
|
+
write: async (value) => {
|
|
554
|
+
const lookup = await asyncStorage;
|
|
555
|
+
if (lookup.outcome === "installed") await lookup.storage.setItem(await storageKey, value);
|
|
556
|
+
},
|
|
557
|
+
remove: async () => {
|
|
558
|
+
const lookup = await asyncStorage;
|
|
559
|
+
if (lookup.outcome === "installed") await lookup.storage.removeItem(await storageKey);
|
|
560
|
+
},
|
|
561
|
+
sizeLimit: () => DEFAULT_CACHING_SIZE_LIMIT_BYTES
|
|
562
|
+
};
|
|
563
|
+
};
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/instanceIdStorage.ts
|
|
566
|
+
const asyncStorageInstanceIdStorage = (asyncStorage) => {
|
|
567
|
+
const installedAsyncStorage = async () => {
|
|
568
|
+
const lookup = await asyncStorage;
|
|
569
|
+
switch (lookup.outcome) {
|
|
570
|
+
case "installed": return lookup.storage;
|
|
571
|
+
case "not installed": throw new Error("@react-native-async-storage/async-storage is not installed");
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
return {
|
|
575
|
+
getItem: async (key) => (await installedAsyncStorage()).getItem(key),
|
|
576
|
+
setItem: async (key, value) => (await installedAsyncStorage()).setItem(key, value)
|
|
577
|
+
};
|
|
578
|
+
};
|
|
579
|
+
//#endregion
|
|
541
580
|
//#region src/utf8Encoder.ts
|
|
542
581
|
/**
|
|
543
582
|
* Encodes a string to a UTF-8 byte sequence.
|
|
@@ -578,42 +617,6 @@ const encodeManually = (str) => {
|
|
|
578
617
|
return new Uint8Array(bytes);
|
|
579
618
|
};
|
|
580
619
|
//#endregion
|
|
581
|
-
//#region src/cachingProvider.ts
|
|
582
|
-
const storageKeyFor = (clientSdkKey) => CACHED_VALUES_STORAGE_KEY_PREFIX + bytesToHex(sha256(encodeUtf8(clientSdkKey)));
|
|
583
|
-
const asyncStorageCachingProvider = (asyncStorage) => (clientSdkKey) => {
|
|
584
|
-
const storageKey = storageKeyFor(clientSdkKey);
|
|
585
|
-
return {
|
|
586
|
-
read: async () => {
|
|
587
|
-
const lookup = await asyncStorage;
|
|
588
|
-
return lookup.outcome === "installed" ? lookup.storage.getItem(storageKey) : void 0;
|
|
589
|
-
},
|
|
590
|
-
write: async (value) => {
|
|
591
|
-
const lookup = await asyncStorage;
|
|
592
|
-
if (lookup.outcome === "installed") await lookup.storage.setItem(storageKey, value);
|
|
593
|
-
},
|
|
594
|
-
remove: async () => {
|
|
595
|
-
const lookup = await asyncStorage;
|
|
596
|
-
if (lookup.outcome === "installed") await lookup.storage.removeItem(storageKey);
|
|
597
|
-
},
|
|
598
|
-
sizeLimit: () => DEFAULT_CACHING_SIZE_LIMIT_BYTES
|
|
599
|
-
};
|
|
600
|
-
};
|
|
601
|
-
//#endregion
|
|
602
|
-
//#region src/instanceIdStorage.ts
|
|
603
|
-
const asyncStorageInstanceIdStorage = (asyncStorage) => {
|
|
604
|
-
const installedAsyncStorage = async () => {
|
|
605
|
-
const lookup = await asyncStorage;
|
|
606
|
-
switch (lookup.outcome) {
|
|
607
|
-
case "installed": return lookup.storage;
|
|
608
|
-
case "not installed": throw new Error("@react-native-async-storage/async-storage is not installed");
|
|
609
|
-
}
|
|
610
|
-
};
|
|
611
|
-
return {
|
|
612
|
-
getItem: async (key) => (await installedAsyncStorage()).getItem(key),
|
|
613
|
-
setItem: async (key, value) => (await installedAsyncStorage()).setItem(key, value)
|
|
614
|
-
};
|
|
615
|
-
};
|
|
616
|
-
//#endregion
|
|
617
620
|
//#region src/reactNativeStreamingFetch.ts
|
|
618
621
|
const abortError = (message) => {
|
|
619
622
|
const err = new Error(message);
|
|
@@ -750,6 +753,9 @@ var ReactNativeTelemetryClient = class {
|
|
|
750
753
|
}
|
|
751
754
|
};
|
|
752
755
|
//#endregion
|
|
756
|
+
//#region src/sha256HexDigest.ts
|
|
757
|
+
const sha256HexDigest = (text) => Promise.resolve(bytesToHex(sha256(encodeUtf8(text))));
|
|
758
|
+
//#endregion
|
|
753
759
|
//#region src/url.ts
|
|
754
760
|
var MinimalUrl = class {
|
|
755
761
|
constructor(input, base) {
|
|
@@ -771,7 +777,7 @@ const createReactNativeClient = (clientSdkKey, clientOptions) => {
|
|
|
771
777
|
var _clientOptions$logger;
|
|
772
778
|
const sdkIdentity = {
|
|
773
779
|
sdkName: "react-native-sdk",
|
|
774
|
-
sdkVersion: "1.
|
|
780
|
+
sdkVersion: "1.10.0"
|
|
775
781
|
};
|
|
776
782
|
const logger = (_clientOptions$logger = clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.logger) !== null && _clientOptions$logger !== void 0 ? _clientOptions$logger : createConsoleLogger("warn");
|
|
777
783
|
const metadata = resolveMetadata(clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.metadata, logger);
|
|
@@ -782,7 +788,8 @@ const createReactNativeClient = (clientSdkKey, clientOptions) => {
|
|
|
782
788
|
metaContext: metadata,
|
|
783
789
|
baseUrl: liveTelemetry.baseUrl,
|
|
784
790
|
logger,
|
|
785
|
-
urlFactory
|
|
791
|
+
urlFactory,
|
|
792
|
+
clientSession: liveTelemetry.clientSession
|
|
786
793
|
}), clientSdkKey, sdkIdentity, {
|
|
787
794
|
...clientOptions,
|
|
788
795
|
logger,
|
|
@@ -791,6 +798,7 @@ const createReactNativeClient = (clientSdkKey, clientOptions) => {
|
|
|
791
798
|
fetch: reactNativeStreamingFetch,
|
|
792
799
|
urlFactory,
|
|
793
800
|
instanceIdStorage: asyncStorageInstanceIdStorage(asyncStorage),
|
|
801
|
+
sha256HexDigest,
|
|
794
802
|
platformCachingProvider: asyncStorageCachingProvider(asyncStorage)
|
|
795
803
|
});
|
|
796
804
|
};
|
|
@@ -875,9 +875,12 @@ const parseJson = (jsonString, defaultValue, requestedType, valueId) => {
|
|
|
875
875
|
};
|
|
876
876
|
const isJsonTypeCompatible = (parsed, defaultValue) => {
|
|
877
877
|
if (parsed === null) return false;
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
878
|
+
return jsonShapeOf(parsed) === jsonShapeOf(defaultValue);
|
|
879
|
+
};
|
|
880
|
+
const jsonShapeOf = (value) => {
|
|
881
|
+
if (Array.isArray(value)) return "array";
|
|
882
|
+
const nativeType = typeof value;
|
|
883
|
+
return nativeType === "bigint" ? "number" : nativeType;
|
|
881
884
|
};
|
|
882
885
|
//#endregion
|
|
883
886
|
//#region ../shared/src/logger.ts
|
|
@@ -1331,11 +1334,12 @@ const utf8ByteLength = (text) => {
|
|
|
1331
1334
|
};
|
|
1332
1335
|
//#endregion
|
|
1333
1336
|
//#region ../js-client-core/src/cached-values.ts
|
|
1334
|
-
const ENTRY_FORMAT_VERSION =
|
|
1337
|
+
const ENTRY_FORMAT_VERSION = 2;
|
|
1338
|
+
const FIRST_ENTRY_FORMAT_VERSION = 1;
|
|
1335
1339
|
const DEFAULT_CONTEXT_KIND = "user";
|
|
1336
1340
|
const CACHED_VALUES_STORAGE_KEY_PREFIX = "configdirector-sdk:cached-values:";
|
|
1337
1341
|
const DEFAULT_CACHING_SIZE_LIMIT_BYTES = 256 * 1024;
|
|
1338
|
-
const planCaching = (connectionPlan, caching,
|
|
1342
|
+
const planCaching = (connectionPlan, caching, sha256HexDigest, platformCachingProvider) => {
|
|
1339
1343
|
var _caching$provider;
|
|
1340
1344
|
if (connectionPlan.kind === "stay-offline") return {
|
|
1341
1345
|
kind: "no cache",
|
|
@@ -1345,7 +1349,12 @@ const planCaching = (connectionPlan, caching, platformProvider) => {
|
|
|
1345
1349
|
kind: "no cache",
|
|
1346
1350
|
reason: "turned off"
|
|
1347
1351
|
};
|
|
1348
|
-
|
|
1352
|
+
if (!sha256HexDigest) return {
|
|
1353
|
+
kind: "no cache",
|
|
1354
|
+
reason: "no SHA-256 available"
|
|
1355
|
+
};
|
|
1356
|
+
const clientSdkKeyDigest = sha256HexDigest(connectionPlan.clientSdkKey);
|
|
1357
|
+
const provider = (_caching$provider = caching === null || caching === void 0 ? void 0 : caching.provider) !== null && _caching$provider !== void 0 ? _caching$provider : platformCachingProvider === null || platformCachingProvider === void 0 ? void 0 : platformCachingProvider(clientSdkKeyDigest);
|
|
1349
1358
|
if (!provider) return {
|
|
1350
1359
|
kind: "no cache",
|
|
1351
1360
|
reason: "no provider available"
|
|
@@ -1353,7 +1362,7 @@ const planCaching = (connectionPlan, caching, platformProvider) => {
|
|
|
1353
1362
|
return {
|
|
1354
1363
|
kind: "cache",
|
|
1355
1364
|
provider,
|
|
1356
|
-
|
|
1365
|
+
clientSdkKeyDigest
|
|
1357
1366
|
};
|
|
1358
1367
|
};
|
|
1359
1368
|
const contextTagFor = (context, instanceId) => {
|
|
@@ -1389,15 +1398,30 @@ const isConfigStateMap = (candidate) => {
|
|
|
1389
1398
|
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return false;
|
|
1390
1399
|
return Object.values(candidate).every((config) => config && typeof config === "object" && typeof config.id === "string" && typeof config.key === "string");
|
|
1391
1400
|
};
|
|
1392
|
-
const isEntryFor = (
|
|
1401
|
+
const isEntryFor = (clientSdkKeyDigest, candidate) => {
|
|
1393
1402
|
if (!candidate || typeof candidate !== "object") return false;
|
|
1394
1403
|
const entry = candidate;
|
|
1395
|
-
return entry.formatVersion === ENTRY_FORMAT_VERSION && entry.
|
|
1404
|
+
return entry.formatVersion === ENTRY_FORMAT_VERSION && entry.clientSdkKeyDigest === clientSdkKeyDigest && isContextTag(entry.contextTag) && typeof entry.environmentId === "string" && typeof entry.projectId === "string" && isConfigStateMap(entry.configs) && typeof entry.receivedAt === "number";
|
|
1405
|
+
};
|
|
1406
|
+
const hasFirstFormatVersion = (candidate) => !!candidate && typeof candidate === "object" && candidate.formatVersion === FIRST_ENTRY_FORMAT_VERSION;
|
|
1407
|
+
const parseEntry = (raw, clientSdkKeyDigest) => {
|
|
1408
|
+
let candidate;
|
|
1409
|
+
try {
|
|
1410
|
+
candidate = JSON.parse(raw);
|
|
1411
|
+
} catch {
|
|
1412
|
+
return { outcome: "unreadable" };
|
|
1413
|
+
}
|
|
1414
|
+
if (isEntryFor(clientSdkKeyDigest, candidate)) return {
|
|
1415
|
+
outcome: "stored",
|
|
1416
|
+
cachedValues: candidate
|
|
1417
|
+
};
|
|
1418
|
+
if (hasFirstFormatVersion(candidate)) return { outcome: "first format" };
|
|
1419
|
+
return { outcome: "unreadable" };
|
|
1396
1420
|
};
|
|
1397
1421
|
var CachedValuesStore = class {
|
|
1398
|
-
constructor(provider,
|
|
1422
|
+
constructor(provider, clientSdkKeyDigest, logger) {
|
|
1399
1423
|
this.provider = provider;
|
|
1400
|
-
this.
|
|
1424
|
+
this.clientSdkKeyDigest = clientSdkKeyDigest;
|
|
1401
1425
|
this.logger = logger;
|
|
1402
1426
|
_defineProperty(this, "warned", /* @__PURE__ */ new Set());
|
|
1403
1427
|
_defineProperty(this, "pendingRead", void 0);
|
|
@@ -1422,23 +1446,16 @@ var CachedValuesStore = class {
|
|
|
1422
1446
|
return { outcome: "failed" };
|
|
1423
1447
|
}
|
|
1424
1448
|
if (raw == null || raw === "") return { outcome: "nothing stored" };
|
|
1425
|
-
const
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
}
|
|
1436
|
-
parseEntry(raw) {
|
|
1437
|
-
try {
|
|
1438
|
-
const candidate = JSON.parse(raw);
|
|
1439
|
-
return isEntryFor(this.clientSdkKey, candidate) ? candidate : void 0;
|
|
1440
|
-
} catch {
|
|
1441
|
-
return;
|
|
1449
|
+
const entryParseOutcome = parseEntry(raw, await this.clientSdkKeyDigest);
|
|
1450
|
+
switch (entryParseOutcome.outcome) {
|
|
1451
|
+
case "stored": return entryParseOutcome;
|
|
1452
|
+
case "first format":
|
|
1453
|
+
await this.removeEntry();
|
|
1454
|
+
return entryParseOutcome;
|
|
1455
|
+
case "unreadable":
|
|
1456
|
+
this.warnOnce("unreadable", "The values kept on the device could not be read and were removed, starting without them");
|
|
1457
|
+
await this.removeEntry();
|
|
1458
|
+
return entryParseOutcome;
|
|
1442
1459
|
}
|
|
1443
1460
|
}
|
|
1444
1461
|
async writeQueued() {
|
|
@@ -1457,7 +1474,7 @@ var CachedValuesStore = class {
|
|
|
1457
1474
|
async writeEntry(cachedValues) {
|
|
1458
1475
|
const entry = {
|
|
1459
1476
|
formatVersion: ENTRY_FORMAT_VERSION,
|
|
1460
|
-
|
|
1477
|
+
clientSdkKeyDigest: await this.clientSdkKeyDigest,
|
|
1461
1478
|
...cachedValues
|
|
1462
1479
|
};
|
|
1463
1480
|
const serialized = JSON.stringify(entry);
|
|
@@ -1522,7 +1539,7 @@ var DefaultConfigDirectorClient = class DefaultConfigDirectorClient {
|
|
|
1522
1539
|
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;
|
|
1523
1540
|
const urlFactory = (_internalClientOption = internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.urlFactory) !== null && _internalClientOption !== void 0 ? _internalClientOption : defaultUrlFactory;
|
|
1524
1541
|
this.connectionPlan = planConnection(clientSdkKey, clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.connection, urlFactory);
|
|
1525
|
-
this.cachedValuesStore = this.buildCachedValuesStore(planCaching(this.connectionPlan, clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.caching, internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.platformCachingProvider));
|
|
1542
|
+
this.cachedValuesStore = this.buildCachedValuesStore(planCaching(this.connectionPlan, clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.caching, internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.sha256HexDigest, internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.platformCachingProvider));
|
|
1526
1543
|
this.telemetryClient = this.buildTelemetryClient(liveTelemetryClient, clientOptions);
|
|
1527
1544
|
this.transport = (_internalClientOption2 = internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.transport) !== null && _internalClientOption2 !== void 0 ? _internalClientOption2 : this.buildTransport(sdkOptions, clientOptions, urlFactory, internalClientOptions);
|
|
1528
1545
|
this.transport.on("configSetReceived", (configSet) => {
|
|
@@ -1566,7 +1583,7 @@ var DefaultConfigDirectorClient = class DefaultConfigDirectorClient {
|
|
|
1566
1583
|
this.logger.debug(`[ConfigDirectorClient] No values are kept on the device: ${cachingPlan.reason}`);
|
|
1567
1584
|
return;
|
|
1568
1585
|
case "cache": {
|
|
1569
|
-
const store = new CachedValuesStore(cachingPlan.provider, cachingPlan.
|
|
1586
|
+
const store = new CachedValuesStore(cachingPlan.provider, cachingPlan.clientSdkKeyDigest, this.logger);
|
|
1570
1587
|
store.read();
|
|
1571
1588
|
return store;
|
|
1572
1589
|
}
|
|
@@ -1582,6 +1599,7 @@ var DefaultConfigDirectorClient = class DefaultConfigDirectorClient {
|
|
|
1582
1599
|
const read = await store.read();
|
|
1583
1600
|
switch (read.outcome) {
|
|
1584
1601
|
case "nothing stored":
|
|
1602
|
+
case "first format":
|
|
1585
1603
|
case "unreadable":
|
|
1586
1604
|
case "failed": return;
|
|
1587
1605
|
case "stored": break;
|
|
@@ -1655,7 +1673,8 @@ var DefaultConfigDirectorClient = class DefaultConfigDirectorClient {
|
|
|
1655
1673
|
clientSdkKey: plan.clientSdkKey,
|
|
1656
1674
|
baseUrl: plan.baseUrl,
|
|
1657
1675
|
logger: this.logger,
|
|
1658
|
-
metadata: clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.metadata
|
|
1676
|
+
metadata: clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.metadata,
|
|
1677
|
+
clientSession: this.clientSession
|
|
1659
1678
|
});
|
|
1660
1679
|
}
|
|
1661
1680
|
}
|
|
@@ -1778,7 +1797,7 @@ var DefaultConfigDirectorClient = class DefaultConfigDirectorClient {
|
|
|
1778
1797
|
var _this$configSet, _this$handlersMap$get;
|
|
1779
1798
|
const configState = (_this$configSet = this.configSet) === null || _this$configSet === void 0 ? void 0 : _this$configSet.configs[configKey];
|
|
1780
1799
|
(_this$handlersMap$get = this.handlersMap.get(configKey)) === null || _this$handlersMap$get === void 0 || _this$handlersMap$get.forEach((h) => {
|
|
1781
|
-
const value = this.
|
|
1800
|
+
const value = this.evaluationOf(configKey, configState, h.defaultValue).value;
|
|
1782
1801
|
h.handler(value);
|
|
1783
1802
|
});
|
|
1784
1803
|
}
|
|
@@ -1803,12 +1822,15 @@ var DefaultConfigDirectorClient = class DefaultConfigDirectorClient {
|
|
|
1803
1822
|
} else handlers.splice(0);
|
|
1804
1823
|
}
|
|
1805
1824
|
getValue(configKey, defaultValue) {
|
|
1825
|
+
return this.evaluate(configKey, defaultValue).value;
|
|
1826
|
+
}
|
|
1827
|
+
evaluate(configKey, defaultValue) {
|
|
1806
1828
|
var _this$configSet2;
|
|
1807
1829
|
this.validateDefaultValue(defaultValue);
|
|
1808
1830
|
const configState = (_this$configSet2 = this.configSet) === null || _this$configSet2 === void 0 ? void 0 : _this$configSet2.configs[configKey];
|
|
1809
|
-
return this.
|
|
1831
|
+
return this.evaluationOf(configKey, configState, defaultValue);
|
|
1810
1832
|
}
|
|
1811
|
-
|
|
1833
|
+
evaluationOf(configKey, configState, defaultValue) {
|
|
1812
1834
|
var _this$currentContext2, _parseResult$parsedVa;
|
|
1813
1835
|
if (!configState) {
|
|
1814
1836
|
var _this$currentContext;
|
|
@@ -1823,14 +1845,15 @@ var DefaultConfigDirectorClient = class DefaultConfigDirectorClient {
|
|
|
1823
1845
|
usedDefault: true,
|
|
1824
1846
|
evaluationReason: reason
|
|
1825
1847
|
});
|
|
1826
|
-
|
|
1848
|
+
const evaluation = {
|
|
1827
1849
|
key: configKey,
|
|
1828
1850
|
value: defaultValue,
|
|
1829
1851
|
isDefaultValue: true,
|
|
1830
1852
|
reason,
|
|
1831
1853
|
context: this.context
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1854
|
+
};
|
|
1855
|
+
this.dispatchEvaluationEvent(evaluation);
|
|
1856
|
+
return evaluation;
|
|
1834
1857
|
}
|
|
1835
1858
|
const parseResult = parseConfigValue(configState, defaultValue);
|
|
1836
1859
|
const reason = this.servedReason(parseResult.reason);
|
|
@@ -1845,16 +1868,17 @@ var DefaultConfigDirectorClient = class DefaultConfigDirectorClient {
|
|
|
1845
1868
|
usedDefault: parseResult.usedDefault,
|
|
1846
1869
|
evaluationReason: reason
|
|
1847
1870
|
});
|
|
1848
|
-
|
|
1871
|
+
const evaluation = {
|
|
1849
1872
|
key: configKey,
|
|
1850
1873
|
value: parseResult.parsedValue,
|
|
1851
1874
|
valueId: (_parseResult$parsedVa = parseResult.parsedValueId) !== null && _parseResult$parsedVa !== void 0 ? _parseResult$parsedVa : void 0,
|
|
1852
1875
|
isDefaultValue: parseResult.usedDefault,
|
|
1853
1876
|
reason,
|
|
1854
1877
|
context: this.context
|
|
1855
|
-
}
|
|
1878
|
+
};
|
|
1879
|
+
this.dispatchEvaluationEvent(evaluation);
|
|
1856
1880
|
this.logger.debug(`[ConfigDirectorClient] Evaluated '${configKey}' to '${parseResult.parsedValue}'`);
|
|
1857
|
-
return
|
|
1881
|
+
return evaluation;
|
|
1858
1882
|
}
|
|
1859
1883
|
dispatchEvaluationEvent(event) {
|
|
1860
1884
|
setTimeout(() => this.emit("configEvaluated", { evaluation: event }), 0);
|
|
@@ -23,13 +23,24 @@ interface ConfigDirectorLogger {
|
|
|
23
23
|
interface ConfigDirectorLogMessageDecorator {
|
|
24
24
|
decorateMessage(message: string): string;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Why an evaluation returned the value it did. `found-match` returns a value from ConfigDirector,
|
|
28
|
+
* and `cached` a value kept on the device while a client SDK waits for live values. `value-missing`
|
|
29
|
+
* returns the in-code default value because the config has no value. Every other reason returns the
|
|
30
|
+
* in-code default value because of an error: the config does not exist (`config-state-missing`), no
|
|
31
|
+
* values have arrived yet (`client-not-ready`), or the value cannot be read as the type of the in-code
|
|
32
|
+
* default value.
|
|
33
|
+
*/
|
|
26
34
|
type EvaluationReason = "found-match" | "config-state-missing" | "client-not-ready" | "type-mismatch" | "value-missing" | "invalid-number" | "invalid-json" | "invalid-boolean" | "cached";
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
/**
|
|
36
|
+
* One evaluation of a config: the value it returned, why, and the context it was evaluated for.
|
|
37
|
+
*/
|
|
38
|
+
type ConfigEvaluation<T extends ConfigValueType = ConfigValueType> = {
|
|
39
|
+
/** The config key that was evaluated. */key: string; /** The value returned, which is the in-code default value when {@link isDefaultValue} is `true`. */
|
|
40
|
+
value: T; /** The ID ConfigDirector assigned to the value returned, when ConfigDirector sent one with it. */
|
|
41
|
+
valueId?: string; /** Whether the evaluation returned the in-code default value. */
|
|
42
|
+
isDefaultValue: boolean; /** Why the evaluation returned this value. */
|
|
43
|
+
reason: EvaluationReason; /** The context the config was evaluated for, if any. */
|
|
33
44
|
context?: ConfigDirectorContext;
|
|
34
45
|
};
|
|
35
46
|
/**
|
|
@@ -350,6 +361,16 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
|
|
|
350
361
|
* is called before initialization is done.
|
|
351
362
|
*/
|
|
352
363
|
getValue<T extends ConfigValueType>(configKey: string, defaultValue: T): T;
|
|
364
|
+
/**
|
|
365
|
+
* Evaluates a config as {@link getValue} does and returns the evaluation: the value, the reason it
|
|
366
|
+
* was served and its value ID. Like every read, it fires `configEvaluated` and is counted in
|
|
367
|
+
* telemetry.
|
|
368
|
+
*
|
|
369
|
+
* @returns The evaluation, whose `value` is what {@link getValue} returns
|
|
370
|
+
* @param configKey The config key to evaluate
|
|
371
|
+
* @param defaultValue The in-code default value, returned when no value from ConfigDirector can be served
|
|
372
|
+
*/
|
|
373
|
+
evaluate<T extends ConfigValueType>(configKey: string, defaultValue: T): ConfigEvaluation<T>;
|
|
353
374
|
/**
|
|
354
375
|
* Watches for changes to a a config evaluation value. Whenever the config value changes, the
|
|
355
376
|
* provided callback function will be called with the new value. Changes can happen due to updates
|
|
@@ -397,4 +418,4 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
|
|
|
397
418
|
dispose(): void;
|
|
398
419
|
}
|
|
399
420
|
//#endregion
|
|
400
|
-
export { ConfigDirectorClientOptions as a, NativeJsonValue as c, ConfigDirectorContext as d, ConfigDirectorLogMessageDecorator as f,
|
|
421
|
+
export { ConnectionMode as _, ConfigDirectorClientOptions as a, NativeJsonValue as c, ConfigDirectorContext as d, ConfigDirectorLogMessageDecorator as f, ConfigValueType as g, ConfigEvaluation as h, ConfigDirectorClient as i, NativeValue as l, ConfigDirectorLoggingLevel as m, CachingProvider as n, OfflineValue as o, ConfigDirectorLogger as p, ClientHooks as r, OfflineValues as s, CachingOptions as t, NativeValues as u, EvaluationReason as v };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@configdirector/react-native-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.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",
|