@configdirector/nuxt-sdk 1.9.1 → 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/dist/module.json +1 -1
- package/dist/runtime/app/composables/useConfigDirectorClient.d.mts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorClient.d.ts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorClientHooks.d.mts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorClientHooks.d.ts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorContext.d.mts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorContext.d.ts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorContext.mjs +2 -1
- package/dist/runtime/app/composables/useConfigDirectorStatus.d.mts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorStatus.d.ts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorValue.d.mts +2 -2
- package/dist/runtime/app/composables/useConfigDirectorValue.d.ts +2 -2
- package/dist/runtime/context-kind-D6YBNij2.mjs +45 -0
- package/dist/runtime/nitro/plugin.d.mts +1 -1
- package/dist/runtime/nitro/plugin.d.ts +1 -1
- package/dist/runtime/nitro/plugin.mjs +105 -11
- package/dist/runtime/plugin.client.mjs +218 -38
- package/dist/runtime/plugin.server.mjs +50 -6
- package/dist/runtime/server/composables/useConfigDirectorClient.d.mts +1 -1
- package/dist/runtime/server/composables/useConfigDirectorClient.d.ts +1 -1
- package/dist/runtime/server/composables/useConfigDirectorServerHooks.d.mts +1 -1
- package/dist/runtime/server/composables/useConfigDirectorServerHooks.d.ts +1 -1
- package/dist/runtime/{types-Bgx2-3dY.d.mts → types-B9_4pADA.d.mts} +1 -1
- package/dist/runtime/{types-CvmjergQ.d.mts → types-DQhBe4Ei.d.mts} +13 -5
- package/dist/runtime/{types-CHmsCChN.d.mts → types-IPLvRsUO.d.mts} +22 -9
- package/dist/testing.d.mts +36 -14
- package/dist/testing.mjs +144 -36
- package/package.json +1 -1
- /package/dist/runtime/{types-CkzBXJwA.d.mts → types-F0fKKk6-.d.mts} +0 -0
package/dist/module.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ClientHooks } from "../../types-
|
|
1
|
+
import { t as ClientHooks } from "../../types-DQhBe4Ei.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/runtime/app/composables/useConfigDirectorClientHooks.d.ts
|
|
4
4
|
declare const useConfigDirectorClientHooks: (hooks: ClientHooks) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ClientHooks } from "../../types-
|
|
1
|
+
import { t as ClientHooks } from "../../types-DQhBe4Ei.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/runtime/app/composables/useConfigDirectorClientHooks.d.ts
|
|
4
4
|
declare const useConfigDirectorClientHooks: (hooks: ClientHooks) => void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useConfigDirectorClient } from "./useConfigDirectorClient.mjs";
|
|
2
|
+
import { n as admittedContextOrNone } from "../../context-kind-D6YBNij2.mjs";
|
|
2
3
|
import { useState } from "#app";
|
|
3
4
|
import { readonly, toRaw } from "vue";
|
|
4
5
|
//#region src/runtime/app/composables/useConfigDirectorContext.ts
|
|
@@ -13,7 +14,7 @@ const useConfigDirectorContext = () => {
|
|
|
13
14
|
const rawContext = toRaw(context);
|
|
14
15
|
const oldContext = JSON.stringify(state.value);
|
|
15
16
|
const newContext = JSON.stringify(rawContext);
|
|
16
|
-
state.value = rawContext;
|
|
17
|
+
state.value = admittedContextOrNone(rawContext);
|
|
17
18
|
if (oldContext != newContext) {
|
|
18
19
|
const timeout = getEffectiveTimeout(options?.timeoutMilliseconds);
|
|
19
20
|
let timer;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as ConfigValueType } from "../../types-
|
|
2
|
-
import { t as ClientStatus } from "../../types-
|
|
1
|
+
import { i as ConfigValueType } from "../../types-IPLvRsUO.mjs";
|
|
2
|
+
import { t as ClientStatus } from "../../types-F0fKKk6-.mjs";
|
|
3
3
|
import { DeepReadonly, Ref, ShallowRef } from "vue";
|
|
4
4
|
|
|
5
5
|
//#region src/runtime/app/composables/useConfigDirectorValue.d.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as ConfigValueType } from "../../types-
|
|
2
|
-
import { t as ClientStatus } from "../../types-
|
|
1
|
+
import { i as ConfigValueType } from "../../types-IPLvRsUO.mjs";
|
|
2
|
+
import { t as ClientStatus } from "../../types-F0fKKk6-.mjs";
|
|
3
3
|
import { DeepReadonly, Ref, ShallowRef } from "vue";
|
|
4
4
|
|
|
5
5
|
//#region src/runtime/app/composables/useConfigDirectorValue.d.ts
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region ../shared/src/context-kind.ts
|
|
2
|
+
const CONTEXT_KIND_MAXIMUM_LENGTH = 64;
|
|
3
|
+
const KIND_SAMPLE_MAXIMUM_CHARACTERS = 128;
|
|
4
|
+
const isContextKindCharacter = (character) => character >= "a" && character <= "z" || character >= "0" && character <= "9" || character === "-" || character === "_";
|
|
5
|
+
const isValidContextKind = (kind) => {
|
|
6
|
+
if (kind.length < 1 || kind.length > CONTEXT_KIND_MAXIMUM_LENGTH) return false;
|
|
7
|
+
for (const character of kind) if (!isContextKindCharacter(character)) return false;
|
|
8
|
+
return true;
|
|
9
|
+
};
|
|
10
|
+
const isAcceptedKind = (kind) => kind === void 0 || kind === null || typeof kind === "string" && isValidContextKind(kind);
|
|
11
|
+
const stringFormOf = (kind) => {
|
|
12
|
+
if (typeof kind === "string") return kind;
|
|
13
|
+
try {
|
|
14
|
+
return String(kind);
|
|
15
|
+
} catch {
|
|
16
|
+
return Object.prototype.toString.call(kind);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const firstCharactersOf = (text, maximumCharacters) => {
|
|
20
|
+
let sample = "";
|
|
21
|
+
let characterCount = 0;
|
|
22
|
+
for (const character of text) {
|
|
23
|
+
if (characterCount === maximumCharacters) break;
|
|
24
|
+
sample += character;
|
|
25
|
+
characterCount += 1;
|
|
26
|
+
}
|
|
27
|
+
return sample;
|
|
28
|
+
};
|
|
29
|
+
const admittedContextOrNone = (context) => {
|
|
30
|
+
const admission = admitContext(context);
|
|
31
|
+
return admission.outcome === "admitted" ? admission.context : void 0;
|
|
32
|
+
};
|
|
33
|
+
const admitContext = (context) => {
|
|
34
|
+
const kind = context?.kind;
|
|
35
|
+
if (isAcceptedKind(kind)) return {
|
|
36
|
+
outcome: "admitted",
|
|
37
|
+
context
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
outcome: "ignored",
|
|
41
|
+
kindSample: firstCharactersOf(stringFormOf(kind), KIND_SAMPLE_MAXIMUM_CHARACTERS)
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { admittedContextOrNone as n, admitContext as t };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as admitContext } from "../context-kind-D6YBNij2.mjs";
|
|
1
2
|
import EventEmitter, { EventEmitter as EventEmitter$1 } from "node:events";
|
|
2
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
4
|
import * as semver from "semver";
|
|
@@ -7017,6 +7018,7 @@ const compareArray = (givenValue, operator, targetValues) => {
|
|
|
7017
7018
|
default: return false;
|
|
7018
7019
|
}
|
|
7019
7020
|
};
|
|
7021
|
+
const effectiveContextKind = (context) => context?.context?.kind ?? "user";
|
|
7020
7022
|
//#endregion
|
|
7021
7023
|
//#region ../config-evaluator/src/ConditionEvaluator.ts
|
|
7022
7024
|
var ConditionEvaluator = class {
|
|
@@ -7065,6 +7067,7 @@ var ConditionEvaluator = class {
|
|
|
7065
7067
|
switch (condition.attribute) {
|
|
7066
7068
|
case "identifier": return orAbsent(context?.context?.id);
|
|
7067
7069
|
case "name": return orAbsent(context?.context?.name);
|
|
7070
|
+
case "kind": return effectiveContextKind(context);
|
|
7068
7071
|
case "appName": return orAbsent(context?.metadata?.appName);
|
|
7069
7072
|
case "appVersion": return orAbsent(context?.metadata?.appVersion);
|
|
7070
7073
|
case "traits":
|
|
@@ -7112,9 +7115,9 @@ const holdsAttributeConditionsOnly = (segment) => (segment.groups ?? []).every((
|
|
|
7112
7115
|
//#endregion
|
|
7113
7116
|
//#region ../config-evaluator/src/percent-hashing.ts
|
|
7114
7117
|
const SEED = 15426857351n;
|
|
7115
|
-
const assignPercentage = (
|
|
7116
|
-
const
|
|
7117
|
-
return Number(rapidhash(
|
|
7118
|
+
const assignPercentage = ({ configId, contextIdentifier, contextKind }) => {
|
|
7119
|
+
const hashInput = contextKind === "user" ? `${contextIdentifier}-${configId}` : `${contextIdentifier}-${configId}:${contextKind}`;
|
|
7120
|
+
return Number(rapidhash(hashInput, { seed: SEED }) % 1000n) / 10;
|
|
7118
7121
|
};
|
|
7119
7122
|
//#endregion
|
|
7120
7123
|
//#region ../config-evaluator/src/ConfigEvaluator.ts
|
|
@@ -7208,7 +7211,8 @@ var ConfigEvaluator = class {
|
|
|
7208
7211
|
const identifier = context?.context?.id ?? void 0;
|
|
7209
7212
|
const assignedPercentage = identifier === void 0 ? 0 : assignPercentage({
|
|
7210
7213
|
configId: config.id,
|
|
7211
|
-
contextIdentifier: identifier
|
|
7214
|
+
contextIdentifier: identifier,
|
|
7215
|
+
contextKind: effectiveContextKind(context)
|
|
7212
7216
|
});
|
|
7213
7217
|
const shares = [];
|
|
7214
7218
|
let sum = 0;
|
|
@@ -7511,6 +7515,59 @@ const resolvePollingInterval = (configuredSeconds, defaults) => {
|
|
|
7511
7515
|
warning: `pollingInterval of ${configuredSeconds} seconds is below the minimum of ${defaults.minimumSeconds} seconds. Using ${defaults.minimumSeconds} seconds.`
|
|
7512
7516
|
};
|
|
7513
7517
|
};
|
|
7518
|
+
var InvalidContextSubmissions = class {
|
|
7519
|
+
countsByKindSample = /* @__PURE__ */ new Map();
|
|
7520
|
+
countBeyondSampleLimit = 0;
|
|
7521
|
+
startTime;
|
|
7522
|
+
record(kindSample) {
|
|
7523
|
+
this.startTime ??= /* @__PURE__ */ new Date();
|
|
7524
|
+
return this.add(kindSample, 1);
|
|
7525
|
+
}
|
|
7526
|
+
absorb(entries) {
|
|
7527
|
+
for (const entry of entries) {
|
|
7528
|
+
if (this.startTime === void 0 || entry.startTime < this.startTime) this.startTime = entry.startTime;
|
|
7529
|
+
this.add(entry.event.kindSample, entry.count);
|
|
7530
|
+
}
|
|
7531
|
+
}
|
|
7532
|
+
add(kindSample, count) {
|
|
7533
|
+
if (kindSample !== void 0) {
|
|
7534
|
+
const knownCount = this.countsByKindSample.get(kindSample);
|
|
7535
|
+
if (knownCount !== void 0) {
|
|
7536
|
+
this.countsByKindSample.set(kindSample, knownCount + count);
|
|
7537
|
+
return "known-kind-sample";
|
|
7538
|
+
}
|
|
7539
|
+
if (this.countsByKindSample.size < 20) {
|
|
7540
|
+
this.countsByKindSample.set(kindSample, count);
|
|
7541
|
+
return "new-kind-sample";
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
const firstBeyondSampleLimit = this.countBeyondSampleLimit === 0;
|
|
7545
|
+
this.countBeyondSampleLimit += count;
|
|
7546
|
+
return firstBeyondSampleLimit ? "first-beyond-sample-limit" : "beyond-sample-limit";
|
|
7547
|
+
}
|
|
7548
|
+
takeSnapshot() {
|
|
7549
|
+
const endTime = /* @__PURE__ */ new Date();
|
|
7550
|
+
const startTime = this.startTime ?? endTime;
|
|
7551
|
+
const entryOf = (count, kindSample) => ({
|
|
7552
|
+
startTime,
|
|
7553
|
+
endTime,
|
|
7554
|
+
count,
|
|
7555
|
+
event: {
|
|
7556
|
+
reason: "invalid-context-kind",
|
|
7557
|
+
kindSample
|
|
7558
|
+
}
|
|
7559
|
+
});
|
|
7560
|
+
const sampledEntries = Array.from(this.countsByKindSample, ([kindSample, count]) => entryOf(count, kindSample));
|
|
7561
|
+
const entries = this.countBeyondSampleLimit > 0 ? [...sampledEntries, entryOf(this.countBeyondSampleLimit)] : sampledEntries;
|
|
7562
|
+
this.clear();
|
|
7563
|
+
return entries;
|
|
7564
|
+
}
|
|
7565
|
+
clear() {
|
|
7566
|
+
this.countsByKindSample.clear();
|
|
7567
|
+
this.countBeyondSampleLimit = 0;
|
|
7568
|
+
this.startTime = void 0;
|
|
7569
|
+
}
|
|
7570
|
+
};
|
|
7514
7571
|
//#endregion
|
|
7515
7572
|
//#region ../shared/src/telemetry/utils.ts
|
|
7516
7573
|
const CONFIG_VALUE_MAX_LENGTH = 500;
|
|
@@ -7821,6 +7878,7 @@ var ServerTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
|
7821
7878
|
reporter;
|
|
7822
7879
|
_context;
|
|
7823
7880
|
contexts;
|
|
7881
|
+
invalidContextSubmissions = new InvalidContextSubmissions();
|
|
7824
7882
|
constructor(options) {
|
|
7825
7883
|
super(options);
|
|
7826
7884
|
this.reporter = new ServerEventReporter(options);
|
|
@@ -7829,13 +7887,23 @@ var ServerTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
|
7829
7887
|
}
|
|
7830
7888
|
evaluatedConfig(payload) {
|
|
7831
7889
|
if (!this.collectEvents) return;
|
|
7832
|
-
|
|
7890
|
+
const context = payload.context ?? void 0;
|
|
7891
|
+
const contextKind = effectiveContextKind({ context });
|
|
7892
|
+
const contextId = context?.anonymous ? void 0 : context?.id;
|
|
7893
|
+
if (contextId) this.contexts.set(`${contextKind}:${contextId}`, {
|
|
7894
|
+
...context,
|
|
7895
|
+
kind: contextKind
|
|
7896
|
+
});
|
|
7833
7897
|
const event = {
|
|
7834
7898
|
...payload.evaluation,
|
|
7835
|
-
contextId
|
|
7899
|
+
contextId,
|
|
7900
|
+
contextKind: contextId === void 0 ? void 0 : contextKind
|
|
7836
7901
|
};
|
|
7837
7902
|
this.evaluationEventQueue.push(this.sanitizeEvaluatedConfigEvent(event));
|
|
7838
7903
|
}
|
|
7904
|
+
recordInvalidContext(kindSample) {
|
|
7905
|
+
return this.invalidContextSubmissions.record(kindSample);
|
|
7906
|
+
}
|
|
7839
7907
|
sanitizeEvaluatedConfigEvent(event) {
|
|
7840
7908
|
return {
|
|
7841
7909
|
...event,
|
|
@@ -7869,7 +7937,10 @@ var ServerTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
|
7869
7937
|
return await this.reporter?.report({
|
|
7870
7938
|
context: this._context,
|
|
7871
7939
|
discreteEvents: { capturedContexts: contextsSnapshot.contexts },
|
|
7872
|
-
aggregatedEvents: {
|
|
7940
|
+
aggregatedEvents: {
|
|
7941
|
+
evaluatedConfig: this.aggregator.aggregate(evaluationSnapshot),
|
|
7942
|
+
invalidContext: this.invalidContextSubmissions.takeSnapshot()
|
|
7943
|
+
},
|
|
7873
7944
|
droppedEvents: {
|
|
7874
7945
|
evaluatedConfig: evaluationSnapshot.droppedCount,
|
|
7875
7946
|
capturedContexts: contextsSnapshot.droppedCount
|
|
@@ -7903,6 +7974,13 @@ const generateValueId = async (v) => {
|
|
|
7903
7974
|
const defaultBaseUrl = new URL("https://server-sdk-api.configdirector.com");
|
|
7904
7975
|
const DEFAULT_FLUSH_INTERVAL = 3e4;
|
|
7905
7976
|
const DEFAULT_EVENT_QUEUE_LIMIT = 5e3;
|
|
7977
|
+
const logInvalidContext = {
|
|
7978
|
+
"new-kind-sample": (logger, kindSample) => logger.error(`[ConfigDirectorClient] Ignored a context with the invalid kind '${kindSample}' and evaluated as if no context was supplied. A context kind has 1 to 64 characters, using only lowercase letters, digits, '-' and '_'.`),
|
|
7979
|
+
"known-kind-sample": () => {},
|
|
7980
|
+
"first-beyond-sample-limit": (logger) => logger.error(`[ConfigDirectorClient] Ignored a context with another invalid kind and evaluated as if no context was supplied. 20 different invalid kinds were logged recently, so further invalid kinds are not logged individually.`),
|
|
7981
|
+
"beyond-sample-limit": () => {}
|
|
7982
|
+
};
|
|
7983
|
+
const usesAnySegment = (definition, segmentIds) => (definition.target?.rules ?? []).some((rule) => rule.type === "conditional" && (rule.conditions ?? []).some((condition) => condition.kind === "segment" && segmentIds.has(condition.segmentId)));
|
|
7906
7984
|
var DefaultConfigDirectorClient = class {
|
|
7907
7985
|
logger;
|
|
7908
7986
|
usageEventCollector;
|
|
@@ -7942,7 +8020,7 @@ var DefaultConfigDirectorClient = class {
|
|
|
7942
8020
|
...configBundle.segments
|
|
7943
8021
|
};
|
|
7944
8022
|
}
|
|
7945
|
-
const keys =
|
|
8023
|
+
const keys = this.findKeysUpdatedBy(configBundle);
|
|
7946
8024
|
this.eventEmitter.emit("configsUpdated", {
|
|
7947
8025
|
keys,
|
|
7948
8026
|
removedKeys
|
|
@@ -8044,6 +8122,11 @@ var DefaultConfigDirectorClient = class {
|
|
|
8044
8122
|
if (!this.configSet || configBundle.kind != "full") return [];
|
|
8045
8123
|
return Object.keys(this.configSet.configs).filter((key) => !Object.prototype.hasOwnProperty.call(configBundle.configs, key));
|
|
8046
8124
|
}
|
|
8125
|
+
findKeysUpdatedBy(configBundle) {
|
|
8126
|
+
const carriedSegmentIds = new Set(Object.keys(configBundle.segments ?? {}));
|
|
8127
|
+
const keysUsingCarriedSegments = Object.entries(this.configSet?.configs ?? {}).filter(([, definition]) => usesAnySegment(definition, carriedSegmentIds)).map(([key]) => key);
|
|
8128
|
+
return [...new Set([...Object.keys(configBundle.configs), ...keysUsingCarriedSegments])];
|
|
8129
|
+
}
|
|
8047
8130
|
updateWatchers(configKeys) {
|
|
8048
8131
|
configKeys.forEach((configKey) => this.updateWatchersForConfig(configKey));
|
|
8049
8132
|
}
|
|
@@ -8080,7 +8163,8 @@ var DefaultConfigDirectorClient = class {
|
|
|
8080
8163
|
const configDefinition = this.configSet?.configs[configKey];
|
|
8081
8164
|
return this.getValueFromConfigDefinition(configKey, configDefinition, defaultValue, context);
|
|
8082
8165
|
}
|
|
8083
|
-
getValueFromConfigDefinition(configKey, configDefinition, defaultValue,
|
|
8166
|
+
getValueFromConfigDefinition(configKey, configDefinition, defaultValue, suppliedContext) {
|
|
8167
|
+
const context = this.contextToEvaluate(suppliedContext);
|
|
8084
8168
|
if (configDefinition) {
|
|
8085
8169
|
const configState = this.configEvaluator.evaluate(configDefinition, {
|
|
8086
8170
|
context,
|
|
@@ -8134,6 +8218,15 @@ var DefaultConfigDirectorClient = class {
|
|
|
8134
8218
|
return defaultValue;
|
|
8135
8219
|
}
|
|
8136
8220
|
}
|
|
8221
|
+
contextToEvaluate(suppliedContext) {
|
|
8222
|
+
const admission = admitContext(suppliedContext);
|
|
8223
|
+
switch (admission.outcome) {
|
|
8224
|
+
case "admitted": return admission.context;
|
|
8225
|
+
case "ignored":
|
|
8226
|
+
logInvalidContext[this.usageEventCollector.recordInvalidContext(admission.kindSample)](this.logger, admission.kindSample);
|
|
8227
|
+
return;
|
|
8228
|
+
}
|
|
8229
|
+
}
|
|
8137
8230
|
dispatchEvaluationEvent(event) {
|
|
8138
8231
|
setTimeout(() => this.eventEmitter.emit("configEvaluated", { evaluation: event }), 0);
|
|
8139
8232
|
}
|
|
@@ -8171,11 +8264,12 @@ var DefaultConfigDirectorClient = class {
|
|
|
8171
8264
|
this.handlersMap.clear();
|
|
8172
8265
|
}
|
|
8173
8266
|
getAllConfigs(options) {
|
|
8267
|
+
const context = this.contextToEvaluate(options?.context);
|
|
8174
8268
|
if (!this.configSet) return {};
|
|
8175
8269
|
const entries = Object.entries(this.configSet.configs);
|
|
8176
8270
|
const filtered = options?.configKeys ? entries.filter(([key]) => options.configKeys?.includes(key)) : entries;
|
|
8177
8271
|
return Object.fromEntries(filtered.map(([key, config]) => [key, this.configEvaluator.evaluate(config, {
|
|
8178
|
-
context
|
|
8272
|
+
context,
|
|
8179
8273
|
metadata: this.metaContext
|
|
8180
8274
|
}, this.configSet?.segments)]));
|
|
8181
8275
|
}
|
|
@@ -8219,7 +8313,7 @@ var plugin_default = defineNitroPlugin((nitroApp) => {
|
|
|
8219
8313
|
const { serverSdkKey, baseUrl, connection } = runtimeConfig.configdirector;
|
|
8220
8314
|
const client = new DefaultConfigDirectorClient(serverSdkKey, {
|
|
8221
8315
|
sdkName: "nuxt-sdk",
|
|
8222
|
-
sdkVersion: "1.
|
|
8316
|
+
sdkVersion: "1.10.0"
|
|
8223
8317
|
}, {
|
|
8224
8318
|
logger,
|
|
8225
8319
|
connection: {
|