@configdirector/nuxt-sdk 0.6.0 → 0.8.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/useConfigDirectorContext.d.mts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorContext.d.ts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorValue.d.mts +1 -1
- package/dist/runtime/app/composables/useConfigDirectorValue.d.ts +1 -1
- package/dist/runtime/nitro/plugin.d.mts +1 -1
- package/dist/runtime/nitro/plugin.d.ts +1 -1
- package/dist/runtime/nitro/plugin.mjs +103 -41
- package/dist/runtime/plugin.client.mjs +49 -25
- package/dist/runtime/server/composables/useConfigDirectorClient.d.mts +1 -1
- package/dist/runtime/server/composables/useConfigDirectorClient.d.ts +1 -1
- package/dist/runtime/{types-BWxsGnk2.d.mts → types-BqdrorBY.d.mts} +9 -0
- package/dist/runtime/{types-DGQ1B6mZ.d.mts → types-Ce8HdKnT.d.mts} +1 -1
- package/dist/runtime/{types-D9IS8RoC.d.mts → types-DE44nrVT.d.mts} +1 -1
- package/package.json +3 -3
package/dist/module.json
CHANGED
|
@@ -849,13 +849,15 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
849
849
|
const requestedType = getRequestedType(defaultValue);
|
|
850
850
|
if (!value) return {
|
|
851
851
|
parsedValue: defaultValue,
|
|
852
|
+
parsedValueId: void 0,
|
|
852
853
|
requestedType,
|
|
853
854
|
usedDefault: true,
|
|
854
855
|
reason: "value-missing"
|
|
855
856
|
};
|
|
856
|
-
if (configState.type === "json") return parseJson(value, defaultValue, requestedType);
|
|
857
|
+
if (configState.type === "json") return parseJson(value, defaultValue, requestedType, configState.valueId);
|
|
857
858
|
if (typeof defaultValue === "string") return {
|
|
858
859
|
parsedValue: value,
|
|
860
|
+
parsedValueId: configState.valueId,
|
|
859
861
|
requestedType,
|
|
860
862
|
usedDefault: false,
|
|
861
863
|
reason: "found-match"
|
|
@@ -865,6 +867,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
865
867
|
const hasBoolean = typeof boolValue === "boolean";
|
|
866
868
|
return {
|
|
867
869
|
parsedValue: hasBoolean ? boolValue : defaultValue,
|
|
870
|
+
parsedValueId: hasBoolean ? configState.valueId : void 0,
|
|
868
871
|
requestedType,
|
|
869
872
|
usedDefault: !hasBoolean,
|
|
870
873
|
reason: hasBoolean ? "found-match" : "invalid-boolean"
|
|
@@ -875,6 +878,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
875
878
|
const hasNumber = typeof numValue === "number";
|
|
876
879
|
return {
|
|
877
880
|
parsedValue: hasNumber ? numValue : defaultValue,
|
|
881
|
+
parsedValueId: hasNumber ? configState.valueId : void 0,
|
|
878
882
|
requestedType,
|
|
879
883
|
usedDefault: !hasNumber,
|
|
880
884
|
reason: hasNumber ? "found-match" : "invalid-number"
|
|
@@ -885,6 +889,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
885
889
|
const hasNumber = typeof numValue === "number";
|
|
886
890
|
return {
|
|
887
891
|
parsedValue: hasNumber ? numValue : defaultValue,
|
|
892
|
+
parsedValueId: hasNumber ? configState.valueId : void 0,
|
|
888
893
|
requestedType,
|
|
889
894
|
usedDefault: !hasNumber,
|
|
890
895
|
reason: hasNumber ? "found-match" : "invalid-number"
|
|
@@ -892,6 +897,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
892
897
|
}
|
|
893
898
|
return {
|
|
894
899
|
parsedValue: value,
|
|
900
|
+
parsedValueId: configState.valueId,
|
|
895
901
|
requestedType,
|
|
896
902
|
usedDefault: false,
|
|
897
903
|
reason: "found-match"
|
|
@@ -915,9 +921,10 @@ const parseConfigFloat = (value) => {
|
|
|
915
921
|
if (isNaN(num) || !isFinite(num)) return;
|
|
916
922
|
return num;
|
|
917
923
|
};
|
|
918
|
-
const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
924
|
+
const parseJson = (jsonString, defaultValue, requestedType, valueId) => {
|
|
919
925
|
if (typeof defaultValue === "string") return {
|
|
920
926
|
parsedValue: jsonString,
|
|
927
|
+
parsedValueId: valueId,
|
|
921
928
|
requestedType,
|
|
922
929
|
usedDefault: false,
|
|
923
930
|
reason: "found-match"
|
|
@@ -925,6 +932,7 @@ const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
|
925
932
|
try {
|
|
926
933
|
return {
|
|
927
934
|
parsedValue: JSON.parse(jsonString),
|
|
935
|
+
parsedValueId: valueId,
|
|
928
936
|
requestedType,
|
|
929
937
|
usedDefault: false,
|
|
930
938
|
reason: "found-match"
|
|
@@ -932,6 +940,7 @@ const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
|
932
940
|
} catch {
|
|
933
941
|
return {
|
|
934
942
|
parsedValue: defaultValue,
|
|
943
|
+
parsedValueId: void 0,
|
|
935
944
|
requestedType,
|
|
936
945
|
usedDefault: true,
|
|
937
946
|
reason: "invalid-json"
|
|
@@ -1007,25 +1016,35 @@ const defaultUrlFactory = (input, base) => new URL(input, base?.toString());
|
|
|
1007
1016
|
//#endregion
|
|
1008
1017
|
//#region ../shared/src/telemetry/utils.ts
|
|
1009
1018
|
const CONFIG_VALUE_MAX_LENGTH = 500;
|
|
1010
|
-
const
|
|
1011
|
-
if (
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
return {
|
|
1019
|
+
const compactTelemetryValue = async (tv, valueIdGenerator) => {
|
|
1020
|
+
if (tv.valueId) return { valueId: tv.valueId };
|
|
1021
|
+
if (tv.value) {
|
|
1022
|
+
if (tv.value.length <= CONFIG_VALUE_MAX_LENGTH && tv.type != "json") return { value: tv.value };
|
|
1023
|
+
return { valueId: await valueIdGenerator(tv.value) };
|
|
1015
1024
|
}
|
|
1016
|
-
|
|
1017
|
-
else return { value: value.toString() };
|
|
1018
|
-
};
|
|
1019
|
-
const djb2Hash = (data) => {
|
|
1020
|
-
return djb2(new TextEncoder().encode(data)).toString(16).padStart(8, "0");
|
|
1025
|
+
return tv;
|
|
1021
1026
|
};
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
+
const mapToTelemetryValue = (ev) => {
|
|
1028
|
+
if (ev.type === "json" || ev.type == null && typeof ev.value === "object") {
|
|
1029
|
+
if (ev.valueId) return {
|
|
1030
|
+
valueId: ev.valueId,
|
|
1031
|
+
type: "json"
|
|
1032
|
+
};
|
|
1033
|
+
try {
|
|
1034
|
+
return {
|
|
1035
|
+
value: JSON.stringify(ev.value),
|
|
1036
|
+
type: "json"
|
|
1037
|
+
};
|
|
1038
|
+
} catch {
|
|
1039
|
+
return {
|
|
1040
|
+
value: ev.value.toString(),
|
|
1041
|
+
type: "json"
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1027
1044
|
}
|
|
1028
|
-
|
|
1045
|
+
const stringValue = ev.value?.toString();
|
|
1046
|
+
if (stringValue && stringValue.length <= CONFIG_VALUE_MAX_LENGTH) return { value: stringValue };
|
|
1047
|
+
return ev.valueId ? { valueId: ev.valueId } : { value: stringValue };
|
|
1029
1048
|
};
|
|
1030
1049
|
const isEventListEmpty = (eventList) => {
|
|
1031
1050
|
const keys = Object.keys(eventList);
|
|
@@ -1189,9 +1208,6 @@ var TelemetryEventCollector = class {
|
|
|
1189
1208
|
const initialDelay = options.initialFlushIntervalDelay ?? 5e3;
|
|
1190
1209
|
this.flushTimeout = setTimeout(() => this.flushAndScheduleNext(), initialDelay);
|
|
1191
1210
|
}
|
|
1192
|
-
sanitizeValue(value, type) {
|
|
1193
|
-
return sanitizeValue(value, type);
|
|
1194
|
-
}
|
|
1195
1211
|
async flushAndScheduleNext() {
|
|
1196
1212
|
if ((await this.flush()).fatalError) {
|
|
1197
1213
|
this.collectEvents = false;
|
|
@@ -1199,19 +1215,6 @@ var TelemetryEventCollector = class {
|
|
|
1199
1215
|
this.logger.warn("[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.");
|
|
1200
1216
|
} else this.flushTimeout = setTimeout(() => this.flushAndScheduleNext(), this.flushIntervalDelay);
|
|
1201
1217
|
}
|
|
1202
|
-
async flush() {
|
|
1203
|
-
if (!this.reporter) return {
|
|
1204
|
-
success: false,
|
|
1205
|
-
fatalError: false
|
|
1206
|
-
};
|
|
1207
|
-
const evaluationSnapshot = this.evaluationEventQueue.takeSnapshot();
|
|
1208
|
-
return await this.reporter?.report({
|
|
1209
|
-
context: this._context,
|
|
1210
|
-
discreteEvents: {},
|
|
1211
|
-
aggregatedEvents: { evaluatedConfig: this.aggregator.aggregate(evaluationSnapshot) },
|
|
1212
|
-
droppedEvents: { evaluatedConfig: evaluationSnapshot.droppedCount }
|
|
1213
|
-
});
|
|
1214
|
-
}
|
|
1215
1218
|
cancelScheduledFlush() {
|
|
1216
1219
|
clearTimeout(this.flushTimeout);
|
|
1217
1220
|
}
|
|
@@ -1258,9 +1261,31 @@ var LimitedMap = class extends Map {
|
|
|
1258
1261
|
}
|
|
1259
1262
|
};
|
|
1260
1263
|
//#endregion
|
|
1264
|
+
//#region ../shared/src/telemetry/EvaluatedConfigEventPreprocessor.ts
|
|
1265
|
+
var EvaluatedConfigEventPreprocessor = class {
|
|
1266
|
+
constructor(valueIdGenerator) {
|
|
1267
|
+
this.valueIdGenerator = valueIdGenerator;
|
|
1268
|
+
this.valueIdGenerator = valueIdGenerator;
|
|
1269
|
+
}
|
|
1270
|
+
async process(snapshot) {
|
|
1271
|
+
const events = await Promise.all(snapshot.events.map(async (e) => {
|
|
1272
|
+
return {
|
|
1273
|
+
...e,
|
|
1274
|
+
defaultValue: await compactTelemetryValue(e.defaultValue, this.valueIdGenerator),
|
|
1275
|
+
evaluatedValue: await compactTelemetryValue(e.evaluatedValue, this.valueIdGenerator)
|
|
1276
|
+
};
|
|
1277
|
+
}));
|
|
1278
|
+
return {
|
|
1279
|
+
...snapshot,
|
|
1280
|
+
events
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
//#endregion
|
|
1261
1285
|
//#region ../js-server-sdk/src/telemetry/ServerTelemetryEventCollector.ts
|
|
1262
1286
|
const DEFAULT_CONTEXTS_LIMIT = 1e3;
|
|
1263
1287
|
var ServerTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
1288
|
+
evaluationEventSnapshotPreprocessor;
|
|
1264
1289
|
reporter;
|
|
1265
1290
|
_context;
|
|
1266
1291
|
contexts;
|
|
@@ -1268,21 +1293,29 @@ var ServerTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
|
1268
1293
|
super(options);
|
|
1269
1294
|
this.reporter = new ServerEventReporter(options);
|
|
1270
1295
|
this.contexts = new LimitedMap(options.contextLimit ?? DEFAULT_CONTEXTS_LIMIT);
|
|
1296
|
+
this.evaluationEventSnapshotPreprocessor = new EvaluatedConfigEventPreprocessor(options.valueIdGenerator);
|
|
1271
1297
|
}
|
|
1272
1298
|
evaluatedConfig(payload) {
|
|
1273
1299
|
if (!this.collectEvents) return;
|
|
1274
|
-
if (payload.context?.id) this.contexts.set(payload.context.id, payload.context);
|
|
1300
|
+
if (payload.context?.id && !payload.context.anonymous) this.contexts.set(payload.context.id, payload.context);
|
|
1275
1301
|
const event = {
|
|
1276
1302
|
...payload.evaluation,
|
|
1277
|
-
contextId: payload.context?.id
|
|
1303
|
+
contextId: payload.context?.anonymous ? void 0 : payload.context?.id
|
|
1278
1304
|
};
|
|
1279
1305
|
this.evaluationEventQueue.push(this.sanitizeEvaluatedConfigEvent(event));
|
|
1280
1306
|
}
|
|
1281
1307
|
sanitizeEvaluatedConfigEvent(event) {
|
|
1282
1308
|
return {
|
|
1283
1309
|
...event,
|
|
1284
|
-
defaultValue:
|
|
1285
|
-
|
|
1310
|
+
defaultValue: mapToTelemetryValue({
|
|
1311
|
+
value: event.defaultValue,
|
|
1312
|
+
type: event.type
|
|
1313
|
+
}),
|
|
1314
|
+
evaluatedValue: mapToTelemetryValue({
|
|
1315
|
+
value: event.evaluatedValue,
|
|
1316
|
+
valueId: event.evaluatedValueId,
|
|
1317
|
+
type: event.type
|
|
1318
|
+
})
|
|
1286
1319
|
};
|
|
1287
1320
|
}
|
|
1288
1321
|
snapshotContexts() {
|
|
@@ -1299,7 +1332,7 @@ var ServerTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
|
1299
1332
|
success: false,
|
|
1300
1333
|
fatalError: false
|
|
1301
1334
|
};
|
|
1302
|
-
const evaluationSnapshot = this.evaluationEventQueue.takeSnapshot();
|
|
1335
|
+
const evaluationSnapshot = await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());
|
|
1303
1336
|
const contextsSnapshot = this.snapshotContexts();
|
|
1304
1337
|
return await this.reporter?.report({
|
|
1305
1338
|
context: this._context,
|
|
@@ -1313,6 +1346,33 @@ var ServerTelemetryEventCollector = class extends TelemetryEventCollector {
|
|
|
1313
1346
|
}
|
|
1314
1347
|
};
|
|
1315
1348
|
//#endregion
|
|
1349
|
+
//#region ../shared/src/base62-encoder.ts
|
|
1350
|
+
const BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
1351
|
+
const toBase62 = (buf, length) => {
|
|
1352
|
+
const ZERO = BigInt(0);
|
|
1353
|
+
const BASE = BigInt(62);
|
|
1354
|
+
const hex = Array.from(buf).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1355
|
+
let n = BigInt("0x" + hex);
|
|
1356
|
+
let result = "";
|
|
1357
|
+
while (n > ZERO) {
|
|
1358
|
+
result = BASE62[Number(n % BASE)] + result;
|
|
1359
|
+
n /= BASE;
|
|
1360
|
+
}
|
|
1361
|
+
return result.padStart(length, "0");
|
|
1362
|
+
};
|
|
1363
|
+
//#endregion
|
|
1364
|
+
//#region ../shared/src/value-id-generator.ts
|
|
1365
|
+
const DIGEST_BYTES = 16;
|
|
1366
|
+
const BASE62_LENGTH = Math.ceil(DIGEST_BYTES * 8 / Math.log2(62));
|
|
1367
|
+
const sha256 = async (value) => {
|
|
1368
|
+
const encoded = new TextEncoder().encode(value);
|
|
1369
|
+
const hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", encoded);
|
|
1370
|
+
return new Uint8Array(hashBuffer).subarray(0, DIGEST_BYTES);
|
|
1371
|
+
};
|
|
1372
|
+
const generateValueId = async (v) => {
|
|
1373
|
+
return toBase62(await sha256(v?.toString() ?? ""), BASE62_LENGTH);
|
|
1374
|
+
};
|
|
1375
|
+
//#endregion
|
|
1316
1376
|
//#region ../js-server-sdk/src/DefaultConfigDirectorClient.ts
|
|
1317
1377
|
const defaultBaseUrl = new URL("https://server-sdk-api.configdirector.com");
|
|
1318
1378
|
const DEFAULT_FLUSH_INTERVAL = 3e4;
|
|
@@ -1347,7 +1407,8 @@ var DefaultConfigDirectorClient = class {
|
|
|
1347
1407
|
flushIntervalDelay: clientOptions?.telemetry?.flushInterval ?? DEFAULT_FLUSH_INTERVAL,
|
|
1348
1408
|
evaluationQueueLimit: Math.ceil(queueLimit * .7),
|
|
1349
1409
|
contextLimit: Math.floor(queueLimit * .3),
|
|
1350
|
-
urlFactory: defaultUrlFactory
|
|
1410
|
+
urlFactory: defaultUrlFactory,
|
|
1411
|
+
valueIdGenerator: generateValueId
|
|
1351
1412
|
});
|
|
1352
1413
|
this.transport = new transportConstructor({
|
|
1353
1414
|
serverSdkKey,
|
|
@@ -1460,6 +1521,7 @@ var DefaultConfigDirectorClient = class {
|
|
|
1460
1521
|
defaultValue,
|
|
1461
1522
|
requestedType: parseResult.requestedType,
|
|
1462
1523
|
evaluatedValue: parseResult.parsedValue,
|
|
1524
|
+
evaluatedValueId: parseResult.parsedValueId,
|
|
1463
1525
|
usedDefault: parseResult.usedDefault,
|
|
1464
1526
|
evaluationReason: parseResult.reason
|
|
1465
1527
|
}
|
|
@@ -1552,7 +1614,7 @@ var plugin_default = defineNitroPlugin((nitroApp) => {
|
|
|
1552
1614
|
const { serverSdkKey, baseUrl } = runtimeConfig.configdirector;
|
|
1553
1615
|
const client = new DefaultConfigDirectorClient(serverSdkKey, {
|
|
1554
1616
|
sdkName: "nuxt-sdk",
|
|
1555
|
-
sdkVersion: "0.
|
|
1617
|
+
sdkVersion: "0.8.0"
|
|
1556
1618
|
}, {
|
|
1557
1619
|
logger,
|
|
1558
1620
|
...baseUrl ? { connection: { url: baseUrl } } : {}
|
|
@@ -407,7 +407,8 @@ var StreamingTransport = class {
|
|
|
407
407
|
body: JSON.stringify({
|
|
408
408
|
givenContext: context,
|
|
409
409
|
metaContext: this.options.metaContext,
|
|
410
|
-
clientSdkKey: this.options.clientSdkKey
|
|
410
|
+
clientSdkKey: this.options.clientSdkKey,
|
|
411
|
+
instanceId: this.options.instanceId
|
|
411
412
|
}),
|
|
412
413
|
onMessage: ({ data }) => {
|
|
413
414
|
this.dispatchMessage(data);
|
|
@@ -501,13 +502,15 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
501
502
|
const requestedType = getRequestedType(defaultValue);
|
|
502
503
|
if (!value) return {
|
|
503
504
|
parsedValue: defaultValue,
|
|
505
|
+
parsedValueId: void 0,
|
|
504
506
|
requestedType,
|
|
505
507
|
usedDefault: true,
|
|
506
508
|
reason: "value-missing"
|
|
507
509
|
};
|
|
508
|
-
if (configState.type === "json") return parseJson(value, defaultValue, requestedType);
|
|
510
|
+
if (configState.type === "json") return parseJson(value, defaultValue, requestedType, configState.valueId);
|
|
509
511
|
if (typeof defaultValue === "string") return {
|
|
510
512
|
parsedValue: value,
|
|
513
|
+
parsedValueId: configState.valueId,
|
|
511
514
|
requestedType,
|
|
512
515
|
usedDefault: false,
|
|
513
516
|
reason: "found-match"
|
|
@@ -517,6 +520,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
517
520
|
const hasBoolean = typeof boolValue === "boolean";
|
|
518
521
|
return {
|
|
519
522
|
parsedValue: hasBoolean ? boolValue : defaultValue,
|
|
523
|
+
parsedValueId: hasBoolean ? configState.valueId : void 0,
|
|
520
524
|
requestedType,
|
|
521
525
|
usedDefault: !hasBoolean,
|
|
522
526
|
reason: hasBoolean ? "found-match" : "invalid-boolean"
|
|
@@ -527,6 +531,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
527
531
|
const hasNumber = typeof numValue === "number";
|
|
528
532
|
return {
|
|
529
533
|
parsedValue: hasNumber ? numValue : defaultValue,
|
|
534
|
+
parsedValueId: hasNumber ? configState.valueId : void 0,
|
|
530
535
|
requestedType,
|
|
531
536
|
usedDefault: !hasNumber,
|
|
532
537
|
reason: hasNumber ? "found-match" : "invalid-number"
|
|
@@ -537,6 +542,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
537
542
|
const hasNumber = typeof numValue === "number";
|
|
538
543
|
return {
|
|
539
544
|
parsedValue: hasNumber ? numValue : defaultValue,
|
|
545
|
+
parsedValueId: hasNumber ? configState.valueId : void 0,
|
|
540
546
|
requestedType,
|
|
541
547
|
usedDefault: !hasNumber,
|
|
542
548
|
reason: hasNumber ? "found-match" : "invalid-number"
|
|
@@ -544,6 +550,7 @@ const parseConfigValue = (configState, defaultValue) => {
|
|
|
544
550
|
}
|
|
545
551
|
return {
|
|
546
552
|
parsedValue: value,
|
|
553
|
+
parsedValueId: configState.valueId,
|
|
547
554
|
requestedType,
|
|
548
555
|
usedDefault: false,
|
|
549
556
|
reason: "found-match"
|
|
@@ -567,9 +574,10 @@ const parseConfigFloat = (value) => {
|
|
|
567
574
|
if (isNaN(num) || !isFinite(num)) return;
|
|
568
575
|
return num;
|
|
569
576
|
};
|
|
570
|
-
const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
577
|
+
const parseJson = (jsonString, defaultValue, requestedType, valueId) => {
|
|
571
578
|
if (typeof defaultValue === "string") return {
|
|
572
579
|
parsedValue: jsonString,
|
|
580
|
+
parsedValueId: valueId,
|
|
573
581
|
requestedType,
|
|
574
582
|
usedDefault: false,
|
|
575
583
|
reason: "found-match"
|
|
@@ -577,6 +585,7 @@ const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
|
577
585
|
try {
|
|
578
586
|
return {
|
|
579
587
|
parsedValue: JSON.parse(jsonString),
|
|
588
|
+
parsedValueId: valueId,
|
|
580
589
|
requestedType,
|
|
581
590
|
usedDefault: false,
|
|
582
591
|
reason: "found-match"
|
|
@@ -584,6 +593,7 @@ const parseJson = (jsonString, defaultValue, requestedType) => {
|
|
|
584
593
|
} catch {
|
|
585
594
|
return {
|
|
586
595
|
parsedValue: defaultValue,
|
|
596
|
+
parsedValueId: void 0,
|
|
587
597
|
requestedType,
|
|
588
598
|
usedDefault: true,
|
|
589
599
|
reason: "invalid-json"
|
|
@@ -764,6 +774,7 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
764
774
|
givenContext: context,
|
|
765
775
|
metaContext: this.options.metaContext,
|
|
766
776
|
clientSdkKey: this.options.clientSdkKey,
|
|
777
|
+
instanceId: this.options.instanceId,
|
|
767
778
|
lastUpdateTimestamp: this.lastUpdateTimestamp
|
|
768
779
|
})
|
|
769
780
|
}, this.logger);
|
|
@@ -824,7 +835,9 @@ var DefaultConfigDirectorClient = class {
|
|
|
824
835
|
readyResolve;
|
|
825
836
|
currentContext;
|
|
826
837
|
connectionMode;
|
|
838
|
+
instanceId;
|
|
827
839
|
constructor(telemetryClient, clientSdkKey, sdkOptions, clientOptions, internalClientOptions) {
|
|
840
|
+
this.instanceId = crypto.randomUUID();
|
|
828
841
|
this.logger = clientOptions?.logger ?? createDefaultLogger$1();
|
|
829
842
|
this.timeout = clientOptions?.connection?.timeout ?? 3e3;
|
|
830
843
|
const urlFactory = internalClientOptions?.urlFactory ?? defaultUrlFactory;
|
|
@@ -833,6 +846,7 @@ var DefaultConfigDirectorClient = class {
|
|
|
833
846
|
const transportConstructor = this.getTransportConstructor(this.connectionMode);
|
|
834
847
|
this.telemetryClient = telemetryClient;
|
|
835
848
|
this.transport = new transportConstructor({
|
|
849
|
+
instanceId: this.instanceId,
|
|
836
850
|
clientSdkKey,
|
|
837
851
|
baseUrl,
|
|
838
852
|
resolveUrl: urlFactory,
|
|
@@ -968,6 +982,7 @@ var DefaultConfigDirectorClient = class {
|
|
|
968
982
|
defaultValue,
|
|
969
983
|
requestedType: parseResult.requestedType,
|
|
970
984
|
evaluatedValue: parseResult.parsedValue,
|
|
985
|
+
evaluatedValueId: parseResult.parsedValueId,
|
|
971
986
|
usedDefault: parseResult.usedDefault,
|
|
972
987
|
evaluationReason: parseResult.reason
|
|
973
988
|
});
|
|
@@ -1032,25 +1047,27 @@ var DefaultConfigDirectorClient = class {
|
|
|
1032
1047
|
//#endregion
|
|
1033
1048
|
//#region ../shared/src/telemetry/utils.ts
|
|
1034
1049
|
const CONFIG_VALUE_MAX_LENGTH = 500;
|
|
1035
|
-
const
|
|
1036
|
-
if (type === "json" || type == null && typeof value === "object")
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1050
|
+
const mapToTelemetryValue = (ev) => {
|
|
1051
|
+
if (ev.type === "json" || ev.type == null && typeof ev.value === "object") {
|
|
1052
|
+
if (ev.valueId) return {
|
|
1053
|
+
valueId: ev.valueId,
|
|
1054
|
+
type: "json"
|
|
1055
|
+
};
|
|
1056
|
+
try {
|
|
1057
|
+
return {
|
|
1058
|
+
value: JSON.stringify(ev.value),
|
|
1059
|
+
type: "json"
|
|
1060
|
+
};
|
|
1061
|
+
} catch {
|
|
1062
|
+
return {
|
|
1063
|
+
value: ev.value.toString(),
|
|
1064
|
+
type: "json"
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1052
1067
|
}
|
|
1053
|
-
|
|
1068
|
+
const stringValue = ev.value?.toString();
|
|
1069
|
+
if (stringValue && stringValue.length <= CONFIG_VALUE_MAX_LENGTH) return { value: stringValue };
|
|
1070
|
+
return ev.valueId ? { valueId: ev.valueId } : { value: stringValue };
|
|
1054
1071
|
};
|
|
1055
1072
|
//#endregion
|
|
1056
1073
|
//#region ../js-browser-client/src/telemetry/WebWorkerTelemetryClient.ts
|
|
@@ -1072,7 +1089,7 @@ var WebWorkerTelemetryClient = class {
|
|
|
1072
1089
|
flushIntervalDelay: options.flushIntervalDelay ?? 3e4
|
|
1073
1090
|
}
|
|
1074
1091
|
};
|
|
1075
|
-
this.worker = new Worker(URL.createObjectURL(new Blob(["(function(){let e=(e,
|
|
1092
|
+
this.worker = new Worker(URL.createObjectURL(new Blob(["(function(){let e=async(e,t)=>e.valueId?{valueId:e.valueId}:e.value?e.value.length<=500&&e.type!=`json`?{value:e.value}:{valueId:await t(e.value)}:e,t=e=>{let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]?.length??0)>0)return!1;return!0},n=e=>{if(!e)return!0;let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]??0)>0)return!1;return!0},r=async(e,t,n,r)=>{let i=new AbortController,a=setTimeout(()=>{r.debug(`[fetchWithTimeout] Reached timeout, aborting request`),i.abort()},e);try{let e=await fetch(typeof t==`string`||t instanceof Request?t:t.toString(),{...n,signal:i.signal});return clearTimeout(a),e}catch(e){throw r.warn(`[fetchWithTimeout] Fetch error: `,e),clearTimeout(a),e}},i=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var a=class{constructor(e){this.executeRequests=!0,this.sdkKey=e.sdkKey,this.logger=e.logger,this.url=e.urlFactory(`client/telemetry/v1`,e.baseUrl)}async report({context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r}){if(!this.executeRequests)return{success:!1,fatalError:!0};let i={clientSdkKey:this.sdkKey,context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r};if(this.isReportEmpty(i))return{success:!0,fatalError:!1};let a=await this.sendReport(i);return a.fatalError&&(this.executeRequests=!1),a}isReportEmpty(e){return t(e.discreteEvents)&&t(e.aggregatedEvents)&&n(e.droppedEvents)}async sendReport(e){try{let t=await r(5e3,this.url,{method:`POST`,body:JSON.stringify(e),keepalive:!0},this.logger),n=this.isStatusFatal(t.status);return n&&this.logger.warn(`[EventReporter] Received a fatal status response (${t.status}) from the telemetry endpoint. No more telemetry data will be sent.`),{success:t.ok,fatalError:n}}catch(e){let t=i(e);return this.logger.warn(`[EventReporter] Error attempting to send telemetry data: ${e}`,{error:e}),{success:!1,fatalError:t}}}isStatusFatal(e){return!!e&&e>=400&&e<500}},o=class{aggregate(e){if(e.events.length==0)return[];let t=new Map;for(let n of e.events){let e=JSON.stringify(n),r=t.get(e)?.count||0;t.set(e,{event:n,count:r+1})}return Array.from(t).map(([,t])=>({startTime:e.startTime,endTime:e.endTime,count:t.count,event:t.event}))}},s=class{constructor(e){this._events=[],this._droppedEventCount=0,this.limit=e??1e3}get events(){return this._events}get reachedLimit(){return this._events.length>=this.limit}get droppedEventCount(){return this._droppedEventCount}push(...e){this.startTime||=new Date;let t=Math.max(0,e.length-this.limit),n=e.slice(t,e.length);if(this._droppedEventCount+=t,this._events.length+n.length>this.limit){let e=this._events.length+n.length-this.limit;this._events.splice(0,e),this._droppedEventCount+=e}return this._events.push(...n)}takeSnapshot(){let e=new Date,t=this.startTime??e,n=this._events.splice(0),r=this._droppedEventCount;return this.startTime=void 0,this._droppedEventCount=0,{startTime:t,endTime:e,events:n,droppedCount:r}}clear(){this._events=[],this.startTime=void 0,this._droppedEventCount=0}},c=class{constructor(e){this.aggregator=new o,this.collectEvents=!0,this.logger=e.logger,this.evaluationEventQueue=new s(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4;let t=e.initialFlushIntervalDelay??5e3;this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),t)}async flushAndScheduleNext(){(await this.flush()).fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay)}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout),await this.flush(),this.evaluationEventQueue.clear()}dispose(){this.close()}},l=class{constructor(e){this.valueIdGenerator=e,this.valueIdGenerator=e}async process(t){let n=await Promise.all(t.events.map(async t=>({...t,defaultValue:await e(t.defaultValue,this.valueIdGenerator),evaluatedValue:await e(t.evaluatedValue,this.valueIdGenerator)})));return{...t,events:n}}},u=class extends c{constructor(e){super(e),this.reporter=new a(e),this.evaluationEventSnapshotPreprocessor=new l(e.valueIdGenerator)}async updateContext(e){this.cancelScheduledFlush(),await this.flush(),this._context=e,await this.flushAndScheduleNext()}evaluatedConfig(e){this.collectEvents&&this.evaluationEventQueue.push(e)}async forceFlush(){this.cancelScheduledFlush(),await this.flushAndScheduleNext()}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e)},droppedEvents:{evaluatedConfig:e.droppedCount}})}};let d=(e,t)=>new URL(e,t?.toString()),f=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},p=Math.ceil(128/Math.log2(62)),m=async e=>{let t=new TextEncoder().encode(e),n=await globalThis.crypto.subtle.digest(`SHA-256`,t);return new Uint8Array(n).subarray(0,16)},h=async e=>f(await m(e?.toString()??``),p),g,_=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),v=e=>{try{self.postMessage(e)}catch{self.postMessage(_(e.payload.level,e.payload.message))}},y={debug:function(e,...t){v(_(`debug`,e,t))},info:function(e,...t){v(_(`info`,e,t))},warn:function(e,...t){v(_(`warn`,e,t))},error:function(e,...t){v(_(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!g){y.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(y.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:g=new u({...t.payload,baseUrl:d(t.payload.baseUrl),urlFactory:d,valueIdGenerator:h,logger:y});break;case`EvaluatedConfigEvent`:g?.evaluatedConfig(t.payload);break;case`UpdateContext`:g?.updateContext(t.payload.context);break;case`Flush`:g?.forceFlush();break;case`Close`:(g?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"], { type: "application/javascript" })));
|
|
1076
1093
|
this.worker.onmessage = (message) => {
|
|
1077
1094
|
this.handleWorkerEvent(message.data);
|
|
1078
1095
|
};
|
|
@@ -1103,8 +1120,15 @@ var WebWorkerTelemetryClient = class {
|
|
|
1103
1120
|
sanitizeEvaluatedConfigEvent(event) {
|
|
1104
1121
|
return {
|
|
1105
1122
|
...event,
|
|
1106
|
-
defaultValue:
|
|
1107
|
-
|
|
1123
|
+
defaultValue: mapToTelemetryValue({
|
|
1124
|
+
value: event.defaultValue,
|
|
1125
|
+
type: event.type
|
|
1126
|
+
}),
|
|
1127
|
+
evaluatedValue: mapToTelemetryValue({
|
|
1128
|
+
value: event.evaluatedValue,
|
|
1129
|
+
valueId: event.evaluatedValueId,
|
|
1130
|
+
type: event.type
|
|
1131
|
+
})
|
|
1108
1132
|
};
|
|
1109
1133
|
}
|
|
1110
1134
|
handleWorkerEvent(event) {
|
|
@@ -1212,7 +1236,7 @@ var plugin_client_default = defineNuxtPlugin((nuxtApp) => {
|
|
|
1212
1236
|
const { clientSdkKey, appName, appVersion, baseUrl } = runtimeConfig.public.configdirector;
|
|
1213
1237
|
const client = createBrowserClient(clientSdkKey, {
|
|
1214
1238
|
sdkName: "nuxt-sdk",
|
|
1215
|
-
sdkVersion: "0.
|
|
1239
|
+
sdkVersion: "0.8.0"
|
|
1216
1240
|
}, {
|
|
1217
1241
|
metadata: {
|
|
1218
1242
|
appName,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ConfigDirectorClient } from "../../types-
|
|
1
|
+
import { t as ConfigDirectorClient } from "../../types-Ce8HdKnT.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/runtime/server/composables/useConfigDirectorClient.d.ts
|
|
4
4
|
declare const useConfigDirectorClient: () => ConfigDirectorClient;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ConfigDirectorClient } from "../../types-
|
|
1
|
+
import { t as ConfigDirectorClient } from "../../types-Ce8HdKnT.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/runtime/server/composables/useConfigDirectorClient.d.ts
|
|
4
4
|
declare const useConfigDirectorClient: () => ConfigDirectorClient;
|
|
@@ -10,6 +10,7 @@ type ConfigState = {
|
|
|
10
10
|
key: string;
|
|
11
11
|
type: ConfigType;
|
|
12
12
|
value: string | undefined | null;
|
|
13
|
+
valueId?: string | undefined | null;
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
15
16
|
* The user's context to be sent to ConfigDirector. This context will be used for targeting
|
|
@@ -37,6 +38,14 @@ type ConfigDirectorContext = {
|
|
|
37
38
|
traits?: {
|
|
38
39
|
[key: string]: unknown;
|
|
39
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Whether or not to treat the context as anonymous during evaluation. When `true`, the
|
|
43
|
+
* context values will be used for targeting rules evaluation but the context will not be
|
|
44
|
+
* persisted and will not appear in the dashboard.
|
|
45
|
+
*
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
anonymous?: boolean;
|
|
40
49
|
};
|
|
41
50
|
//#endregion
|
|
42
51
|
export { ConfigState as n, ConfigValueType as r, ConfigDirectorContext as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as ConfigState, r as ConfigValueType, t as ConfigDirectorContext } from "./types-
|
|
1
|
+
import { n as ConfigState, r as ConfigValueType, t as ConfigDirectorContext } from "./types-BqdrorBY.mjs";
|
|
2
2
|
|
|
3
3
|
//#region ../js-server-sdk/src/types.d.ts
|
|
4
4
|
type ClientEvents = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@configdirector/nuxt-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Nuxt SDK for ConfigDirector. ConfigDirector is a remote configuration and feature flag service.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ConfigDirector",
|
|
@@ -63,13 +63,13 @@
|
|
|
63
63
|
"@types/node": "latest",
|
|
64
64
|
"changelogen": "^0.6.2",
|
|
65
65
|
"eslint": "^10.2.1",
|
|
66
|
-
"nuxt": "^4.4.
|
|
66
|
+
"nuxt": "^4.4.8",
|
|
67
67
|
"playwright": "^1.60.0",
|
|
68
68
|
"rimraf": "^6.1.3",
|
|
69
69
|
"tsdown": "^0.21.7",
|
|
70
70
|
"tslib": "^2.8.1",
|
|
71
71
|
"typescript": "~6.0.3",
|
|
72
|
-
"vite": "^8.0.
|
|
72
|
+
"vite": "^8.0.16",
|
|
73
73
|
"vitest": "^4.1.8",
|
|
74
74
|
"vue-tsc": "^3.2.7"
|
|
75
75
|
}
|