@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
|
@@ -22,27 +22,40 @@ type ConfigEvaluation = {
|
|
|
22
22
|
context?: ConfigDirectorContext;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
|
-
* The
|
|
26
|
-
*
|
|
25
|
+
* The context to be sent to ConfigDirector: the user or other entity, such as a device or an
|
|
26
|
+
* organization, that configs are evaluated for. This context will be used for targeting rules
|
|
27
|
+
* evaluation.
|
|
27
28
|
*/
|
|
28
29
|
type ConfigDirectorContext = {
|
|
29
30
|
/**
|
|
30
|
-
* The
|
|
31
|
-
*
|
|
31
|
+
* The context's identifier. This should be a value that uniquely identifies the user or other
|
|
32
|
+
* entity among contexts of the same {@link kind}.
|
|
32
33
|
* In the case of anonymous users, you could generate a UUID or alternatively not provide
|
|
33
34
|
* the {@link id} and the SDK will generate a random UUID. However, keep in mind that this
|
|
34
|
-
* value is used for segmenting
|
|
35
|
-
* could result in the
|
|
35
|
+
* value is used for segmenting contexts in percentage rollouts, and changes to the {@link id}
|
|
36
|
+
* could result in the context being assigned to a different percentile.
|
|
36
37
|
*/
|
|
37
38
|
id?: string;
|
|
38
39
|
/**
|
|
39
|
-
* The
|
|
40
|
+
* The kind of entity this context represents, such as `user`, `device`, `organization`,
|
|
41
|
+
* `tenant` or `listing`. You can use any other kind that fits your application. A kind has 1
|
|
42
|
+
* to 64 characters, using only lowercase letters (`a`-`z`), digits, `-` and `_`. It is used
|
|
43
|
+
* exactly as given, without trimming or changing its case.
|
|
44
|
+
*
|
|
45
|
+
* A context with an invalid kind is ignored as a whole: the SDK logs an error and evaluates
|
|
46
|
+
* as if no context had been provided.
|
|
47
|
+
*
|
|
48
|
+
* @default "user"
|
|
49
|
+
*/
|
|
50
|
+
kind?: string;
|
|
51
|
+
/**
|
|
52
|
+
* The context's display name. This will be shown in the ConfigDirector dashboard and may be
|
|
40
53
|
* used for targeting rules.
|
|
41
54
|
*/
|
|
42
55
|
name?: string;
|
|
43
56
|
/**
|
|
44
|
-
* Any arbitrary traits for the
|
|
45
|
-
*
|
|
57
|
+
* Any arbitrary traits for the context. They will be shown in the ConfigDirector dashboard
|
|
58
|
+
* and may be used for targeting rules.
|
|
46
59
|
*/
|
|
47
60
|
traits?: {
|
|
48
61
|
[key: string]: unknown;
|
package/dist/testing.d.mts
CHANGED
|
@@ -29,27 +29,40 @@ type ConfigEvaluation = {
|
|
|
29
29
|
context?: ConfigDirectorContext;
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
|
-
* The
|
|
33
|
-
*
|
|
32
|
+
* The context to be sent to ConfigDirector: the user or other entity, such as a device or an
|
|
33
|
+
* organization, that configs are evaluated for. This context will be used for targeting rules
|
|
34
|
+
* evaluation.
|
|
34
35
|
*/
|
|
35
36
|
type ConfigDirectorContext = {
|
|
36
37
|
/**
|
|
37
|
-
* The
|
|
38
|
-
*
|
|
38
|
+
* The context's identifier. This should be a value that uniquely identifies the user or other
|
|
39
|
+
* entity among contexts of the same {@link kind}.
|
|
39
40
|
* In the case of anonymous users, you could generate a UUID or alternatively not provide
|
|
40
41
|
* the {@link id} and the SDK will generate a random UUID. However, keep in mind that this
|
|
41
|
-
* value is used for segmenting
|
|
42
|
-
* could result in the
|
|
42
|
+
* value is used for segmenting contexts in percentage rollouts, and changes to the {@link id}
|
|
43
|
+
* could result in the context being assigned to a different percentile.
|
|
43
44
|
*/
|
|
44
45
|
id?: string;
|
|
45
46
|
/**
|
|
46
|
-
* The
|
|
47
|
+
* The kind of entity this context represents, such as `user`, `device`, `organization`,
|
|
48
|
+
* `tenant` or `listing`. You can use any other kind that fits your application. A kind has 1
|
|
49
|
+
* to 64 characters, using only lowercase letters (`a`-`z`), digits, `-` and `_`. It is used
|
|
50
|
+
* exactly as given, without trimming or changing its case.
|
|
51
|
+
*
|
|
52
|
+
* A context with an invalid kind is ignored as a whole: the SDK logs an error and evaluates
|
|
53
|
+
* as if no context had been provided.
|
|
54
|
+
*
|
|
55
|
+
* @default "user"
|
|
56
|
+
*/
|
|
57
|
+
kind?: string;
|
|
58
|
+
/**
|
|
59
|
+
* The context's display name. This will be shown in the ConfigDirector dashboard and may be
|
|
47
60
|
* used for targeting rules.
|
|
48
61
|
*/
|
|
49
62
|
name?: string;
|
|
50
63
|
/**
|
|
51
|
-
* Any arbitrary traits for the
|
|
52
|
-
*
|
|
64
|
+
* Any arbitrary traits for the context. They will be shown in the ConfigDirector dashboard
|
|
65
|
+
* and may be used for targeting rules.
|
|
53
66
|
*/
|
|
54
67
|
traits?: {
|
|
55
68
|
[key: string]: unknown;
|
|
@@ -106,17 +119,25 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
|
|
|
106
119
|
* not attempt to re-connect and an error will be logged to the console or the provided
|
|
107
120
|
* logger.
|
|
108
121
|
*
|
|
109
|
-
*
|
|
122
|
+
* A context whose {@link ConfigDirectorContext.kind} is invalid is ignored as a whole: an error is
|
|
123
|
+
* logged, and the client connects as if no context had been provided.
|
|
124
|
+
*
|
|
125
|
+
* @param context The current context to be used for evaluating targeting rules (optional).
|
|
110
126
|
*/
|
|
111
127
|
initialize(context?: ConfigDirectorContext): Promise<void>;
|
|
112
128
|
/**
|
|
113
|
-
* Updates the
|
|
129
|
+
* Updates the context and re-evaluates all config and flag values based on the new context.
|
|
130
|
+
*
|
|
131
|
+
* A context whose {@link ConfigDirectorContext.kind} is invalid is ignored as a whole: an error is
|
|
132
|
+
* logged, the previous context is no longer used, and the client connects as if no context had been
|
|
133
|
+
* provided.
|
|
114
134
|
*
|
|
115
|
-
* @param context The current
|
|
135
|
+
* @param context The current context to be used for evaluating targeting rules (required).
|
|
116
136
|
*/
|
|
117
137
|
updateContext(context: ConfigDirectorContext): Promise<void>;
|
|
118
138
|
/**
|
|
119
|
-
* Returns the current context the client is configured with, or undefined if there is no context
|
|
139
|
+
* Returns the current context the client is configured with, or undefined if there is no context,
|
|
140
|
+
* including after a context with an invalid kind was ignored.
|
|
120
141
|
*
|
|
121
142
|
* Note that the value returned does not updated immediately after calling {@link updateContext}. Only
|
|
122
143
|
* once the underlying connection was successful or timed out, the current context is updated. This is
|
|
@@ -287,7 +308,8 @@ interface TestClient {
|
|
|
287
308
|
failContextUpdate(): void;
|
|
288
309
|
/**
|
|
289
310
|
* The context of every `initialize` and `updateContext` call, in call order. `initialize` without
|
|
290
|
-
* a context records an empty context
|
|
311
|
+
* a context records an empty context, and so does a call whose context has an invalid kind, since
|
|
312
|
+
* the client connects without it. Resumes are not recorded.
|
|
291
313
|
*/
|
|
292
314
|
readonly contextUpdates: ConfigDirectorContext[];
|
|
293
315
|
}
|
package/dist/testing.mjs
CHANGED
|
@@ -383,6 +383,7 @@ var StreamingTransport = class {
|
|
|
383
383
|
eventEmitter = new Emitter();
|
|
384
384
|
url;
|
|
385
385
|
timeoutTimer;
|
|
386
|
+
connectionGeneration = 0;
|
|
386
387
|
constructor(options) {
|
|
387
388
|
this.options = options;
|
|
388
389
|
this.options = options;
|
|
@@ -390,6 +391,9 @@ var StreamingTransport = class {
|
|
|
390
391
|
this.url = options.resolveUrl("client/sse/v1", options.baseUrl);
|
|
391
392
|
}
|
|
392
393
|
async connect(context, timeout) {
|
|
394
|
+
const generation = ++this.connectionGeneration;
|
|
395
|
+
const clientSession = await this.options.clientSession;
|
|
396
|
+
if (generation !== this.connectionGeneration) return this;
|
|
393
397
|
if (this.eventSource) this.close();
|
|
394
398
|
const eventSourcePromise = new Promise((resolve, reject) => {
|
|
395
399
|
this.eventSource = createEventSourceClient({
|
|
@@ -401,7 +405,8 @@ var StreamingTransport = class {
|
|
|
401
405
|
givenContext: context,
|
|
402
406
|
metaContext: this.options.metaContext,
|
|
403
407
|
clientSdkKey: this.options.clientSdkKey,
|
|
404
|
-
instanceId:
|
|
408
|
+
instanceId: clientSession.instanceId,
|
|
409
|
+
ephemeral: clientSession.ephemeral
|
|
405
410
|
}),
|
|
406
411
|
onMessage: ({ data }) => {
|
|
407
412
|
this.dispatchMessage(data);
|
|
@@ -466,6 +471,7 @@ var StreamingTransport = class {
|
|
|
466
471
|
this.eventEmitter.clear();
|
|
467
472
|
}
|
|
468
473
|
close() {
|
|
474
|
+
this.connectionGeneration++;
|
|
469
475
|
this.eventSource?.close();
|
|
470
476
|
clearTimeout(this.timeoutTimer);
|
|
471
477
|
}
|
|
@@ -722,10 +728,11 @@ const generateInstanceId = () => {
|
|
|
722
728
|
});
|
|
723
729
|
};
|
|
724
730
|
//#endregion
|
|
725
|
-
//#region ../js-client-core/src/
|
|
731
|
+
//#region ../js-client-core/src/client-session.ts
|
|
726
732
|
const STORAGE_KEY = "configdirector-sdk:instance-id";
|
|
727
733
|
const RECORD_VERSION = 1;
|
|
728
734
|
const MAX_AGE_MS = 360 * 60 * 1e3;
|
|
735
|
+
const STORAGE_DEADLINE_MS = 1e3;
|
|
729
736
|
const CHECKSUM_SALT = "configdirector.instanceId.v1";
|
|
730
737
|
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}$/;
|
|
731
738
|
const fnv1a = (input, offsetBasis) => {
|
|
@@ -741,7 +748,7 @@ const checksumFor = (id, createdAt) => {
|
|
|
741
748
|
const low = fnv1a(payload, 2166136261);
|
|
742
749
|
return fnv1a(`${low}|${payload}`, 16777619).toString(16).padStart(8, "0") + low.toString(16).padStart(8, "0");
|
|
743
750
|
};
|
|
744
|
-
const
|
|
751
|
+
const localStorageIfAvailable = () => {
|
|
745
752
|
try {
|
|
746
753
|
return globalThis.localStorage ?? void 0;
|
|
747
754
|
} catch {
|
|
@@ -756,34 +763,37 @@ const isUsableRecord = (record) => {
|
|
|
756
763
|
if (!UUID_V4_PATTERN.test(id)) return false;
|
|
757
764
|
return checksum === checksumFor(id, createdAt);
|
|
758
765
|
};
|
|
759
|
-
const readStoredInstanceId = (storage, logger) => {
|
|
766
|
+
const readStoredInstanceId = async (storage, logger) => {
|
|
760
767
|
let raw;
|
|
761
768
|
try {
|
|
762
|
-
raw = storage.getItem(STORAGE_KEY);
|
|
769
|
+
raw = await storage.getItem(STORAGE_KEY);
|
|
763
770
|
} catch (error) {
|
|
764
|
-
logger
|
|
765
|
-
return;
|
|
771
|
+
logger.debug("[ConfigDirectorClient] Could not read the stored instance id, using an ephemeral one", error);
|
|
772
|
+
return { outcome: "failed" };
|
|
766
773
|
}
|
|
767
|
-
if (
|
|
774
|
+
if (typeof raw !== "string" || raw === "") return { outcome: "nothing usable" };
|
|
768
775
|
let record;
|
|
769
776
|
try {
|
|
770
777
|
record = JSON.parse(raw);
|
|
771
778
|
} catch {
|
|
772
|
-
logger
|
|
773
|
-
return;
|
|
779
|
+
logger.debug("[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one");
|
|
780
|
+
return { outcome: "nothing usable" };
|
|
774
781
|
}
|
|
775
782
|
if (!isUsableRecord(record)) {
|
|
776
|
-
logger
|
|
777
|
-
return;
|
|
783
|
+
logger.debug("[ConfigDirectorClient] The stored instance id failed validation, generating a new one");
|
|
784
|
+
return { outcome: "nothing usable" };
|
|
778
785
|
}
|
|
779
786
|
const age = Date.now() - record.createdAt;
|
|
780
787
|
if (age < 0 || age >= MAX_AGE_MS) {
|
|
781
|
-
logger
|
|
782
|
-
return;
|
|
788
|
+
logger.debug("[ConfigDirectorClient] The stored instance id has expired, generating a new one");
|
|
789
|
+
return { outcome: "nothing usable" };
|
|
783
790
|
}
|
|
784
|
-
return
|
|
791
|
+
return {
|
|
792
|
+
outcome: "stored",
|
|
793
|
+
instanceId: record.id
|
|
794
|
+
};
|
|
785
795
|
};
|
|
786
|
-
const
|
|
796
|
+
const persistInstanceId = async (storage, id, logger) => {
|
|
787
797
|
const createdAt = Date.now();
|
|
788
798
|
const record = {
|
|
789
799
|
v: RECORD_VERSION,
|
|
@@ -792,19 +802,54 @@ const storeInstanceId = (storage, id, logger) => {
|
|
|
792
802
|
checksum: checksumFor(id, createdAt)
|
|
793
803
|
};
|
|
794
804
|
try {
|
|
795
|
-
storage.setItem(STORAGE_KEY, JSON.stringify(record));
|
|
805
|
+
await storage.setItem(STORAGE_KEY, JSON.stringify(record));
|
|
806
|
+
return true;
|
|
796
807
|
} catch (error) {
|
|
797
|
-
logger
|
|
808
|
+
logger.debug("[ConfigDirectorClient] Could not persist the instance id, using it as an ephemeral one", error);
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
const settleFromStorage = async (storage, provisionalId, deadline, logger) => {
|
|
813
|
+
const read = await readStoredInstanceId(storage, logger);
|
|
814
|
+
switch (read.outcome) {
|
|
815
|
+
case "stored": return { instanceId: read.instanceId };
|
|
816
|
+
case "failed": return {
|
|
817
|
+
instanceId: provisionalId,
|
|
818
|
+
ephemeral: true
|
|
819
|
+
};
|
|
820
|
+
case "nothing usable": break;
|
|
798
821
|
}
|
|
822
|
+
if (deadline.passed) return {
|
|
823
|
+
instanceId: provisionalId,
|
|
824
|
+
ephemeral: true
|
|
825
|
+
};
|
|
826
|
+
return await persistInstanceId(storage, provisionalId, logger) ? { instanceId: provisionalId } : {
|
|
827
|
+
instanceId: provisionalId,
|
|
828
|
+
ephemeral: true
|
|
829
|
+
};
|
|
799
830
|
};
|
|
800
|
-
const
|
|
801
|
-
const
|
|
802
|
-
if (!storage)
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
831
|
+
const resolveClientSession = (logger, storage = localStorageIfAvailable()) => {
|
|
832
|
+
const provisionalId = generateInstanceId();
|
|
833
|
+
if (!storage) {
|
|
834
|
+
logger.debug("[ConfigDirectorClient] No instance id storage is available, using an ephemeral instance id");
|
|
835
|
+
return Promise.resolve({
|
|
836
|
+
instanceId: provisionalId,
|
|
837
|
+
ephemeral: true
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
const deadline = { passed: false };
|
|
841
|
+
let deadlineTimer;
|
|
842
|
+
const fallbackAtDeadline = new Promise((resolve) => {
|
|
843
|
+
deadlineTimer = setTimeout(() => {
|
|
844
|
+
deadline.passed = true;
|
|
845
|
+
logger.warn(`[ConfigDirectorClient] The instance id storage did not respond within ${STORAGE_DEADLINE_MS}ms, using an ephemeral instance id`);
|
|
846
|
+
resolve({
|
|
847
|
+
instanceId: provisionalId,
|
|
848
|
+
ephemeral: true
|
|
849
|
+
});
|
|
850
|
+
}, STORAGE_DEADLINE_MS);
|
|
851
|
+
});
|
|
852
|
+
return Promise.race([settleFromStorage(storage, provisionalId, deadline, logger), fallbackAtDeadline]).finally(() => clearTimeout(deadlineTimer));
|
|
808
853
|
};
|
|
809
854
|
//#endregion
|
|
810
855
|
//#region ../shared/src/transport/AbstractPollingTransport.ts
|
|
@@ -885,6 +930,7 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
885
930
|
eventEmitter = new Emitter();
|
|
886
931
|
url;
|
|
887
932
|
lastUpdateTimestamp;
|
|
933
|
+
connectionGeneration = 0;
|
|
888
934
|
constructor(options) {
|
|
889
935
|
super();
|
|
890
936
|
this.options = options;
|
|
@@ -894,19 +940,26 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
894
940
|
this.pollingIntervalSeconds = options.pollingInterval ?? 60;
|
|
895
941
|
}
|
|
896
942
|
async connect(context, timeout) {
|
|
943
|
+
const generation = ++this.connectionGeneration;
|
|
897
944
|
this.clearPollingInterval();
|
|
945
|
+
const clientSession = await this.options.clientSession;
|
|
946
|
+
if (generation !== this.connectionGeneration) return this;
|
|
898
947
|
try {
|
|
899
|
-
await this.fetchConfigs(context, timeout);
|
|
948
|
+
await this.fetchConfigs(context, timeout, clientSession);
|
|
900
949
|
} finally {
|
|
901
950
|
if (!this.fatalError) this.schedulePollingInterval(() => {
|
|
902
|
-
this.fetchConfigs(context, timeout).catch((error) => {
|
|
951
|
+
this.fetchConfigs(context, timeout, clientSession).catch((error) => {
|
|
903
952
|
this.logger.error("[PollingTransport] Error during polling:", error);
|
|
904
953
|
});
|
|
905
954
|
});
|
|
906
955
|
}
|
|
907
956
|
return this;
|
|
908
957
|
}
|
|
909
|
-
|
|
958
|
+
close() {
|
|
959
|
+
this.connectionGeneration++;
|
|
960
|
+
super.close();
|
|
961
|
+
}
|
|
962
|
+
async fetchConfigs(context, timeout, clientSession) {
|
|
910
963
|
if (this.fatalError) {
|
|
911
964
|
this.logger.warn("[PollingTransport] There was a prior unrecoverable error. Ignoring attempt to reconnect.");
|
|
912
965
|
return;
|
|
@@ -919,7 +972,8 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
919
972
|
givenContext: context,
|
|
920
973
|
metaContext: this.options.metaContext,
|
|
921
974
|
clientSdkKey: this.options.clientSdkKey,
|
|
922
|
-
instanceId:
|
|
975
|
+
instanceId: clientSession.instanceId,
|
|
976
|
+
ephemeral: clientSession.ephemeral,
|
|
923
977
|
lastUpdateTimestamp: this.lastUpdateTimestamp
|
|
924
978
|
})
|
|
925
979
|
}, this.logger);
|
|
@@ -960,6 +1014,46 @@ const read = (readValue) => {
|
|
|
960
1014
|
const readUserAgent = () => read((globals) => globals.navigator?.userAgent);
|
|
961
1015
|
const readHost = () => read((globals) => globals.location?.host);
|
|
962
1016
|
//#endregion
|
|
1017
|
+
//#region ../shared/src/context-kind.ts
|
|
1018
|
+
const CONTEXT_KIND_MAXIMUM_LENGTH = 64;
|
|
1019
|
+
const KIND_SAMPLE_MAXIMUM_CHARACTERS = 128;
|
|
1020
|
+
const isContextKindCharacter = (character) => character >= "a" && character <= "z" || character >= "0" && character <= "9" || character === "-" || character === "_";
|
|
1021
|
+
const isValidContextKind = (kind) => {
|
|
1022
|
+
if (kind.length < 1 || kind.length > CONTEXT_KIND_MAXIMUM_LENGTH) return false;
|
|
1023
|
+
for (const character of kind) if (!isContextKindCharacter(character)) return false;
|
|
1024
|
+
return true;
|
|
1025
|
+
};
|
|
1026
|
+
const isAcceptedKind = (kind) => kind === void 0 || kind === null || typeof kind === "string" && isValidContextKind(kind);
|
|
1027
|
+
const stringFormOf = (kind) => {
|
|
1028
|
+
if (typeof kind === "string") return kind;
|
|
1029
|
+
try {
|
|
1030
|
+
return String(kind);
|
|
1031
|
+
} catch {
|
|
1032
|
+
return Object.prototype.toString.call(kind);
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
const firstCharactersOf = (text, maximumCharacters) => {
|
|
1036
|
+
let sample = "";
|
|
1037
|
+
let characterCount = 0;
|
|
1038
|
+
for (const character of text) {
|
|
1039
|
+
if (characterCount === maximumCharacters) break;
|
|
1040
|
+
sample += character;
|
|
1041
|
+
characterCount += 1;
|
|
1042
|
+
}
|
|
1043
|
+
return sample;
|
|
1044
|
+
};
|
|
1045
|
+
const admitContext = (context) => {
|
|
1046
|
+
const kind = context?.kind;
|
|
1047
|
+
if (isAcceptedKind(kind)) return {
|
|
1048
|
+
outcome: "admitted",
|
|
1049
|
+
context
|
|
1050
|
+
};
|
|
1051
|
+
return {
|
|
1052
|
+
outcome: "ignored",
|
|
1053
|
+
kindSample: firstCharactersOf(stringFormOf(kind), KIND_SAMPLE_MAXIMUM_CHARACTERS)
|
|
1054
|
+
};
|
|
1055
|
+
};
|
|
1056
|
+
//#endregion
|
|
963
1057
|
//#region ../js-client-core/src/DefaultConfigDirectorClient.ts
|
|
964
1058
|
const MAX_EXPONENTIAL_DELAY = 9;
|
|
965
1059
|
var DefaultConfigDirectorClient = class {
|
|
@@ -978,10 +1072,10 @@ var DefaultConfigDirectorClient = class {
|
|
|
978
1072
|
readyResolve;
|
|
979
1073
|
currentContext;
|
|
980
1074
|
connectionMode;
|
|
981
|
-
|
|
1075
|
+
clientSession;
|
|
982
1076
|
constructor(telemetryClient, clientSdkKey, sdkOptions, clientOptions, internalClientOptions) {
|
|
983
1077
|
this.logger = clientOptions?.logger ?? createDefaultLogger();
|
|
984
|
-
this.
|
|
1078
|
+
this.clientSession = resolveClientSession(this.logger, internalClientOptions?.instanceIdStorage);
|
|
985
1079
|
this.timeout = clientOptions?.connection?.timeout ?? 3e3;
|
|
986
1080
|
this.validateSdkKeyPresence(clientSdkKey);
|
|
987
1081
|
const urlFactory = internalClientOptions?.urlFactory ?? defaultUrlFactory;
|
|
@@ -1036,7 +1130,7 @@ var DefaultConfigDirectorClient = class {
|
|
|
1036
1130
|
}
|
|
1037
1131
|
buildTransport(clientSdkKey, sdkOptions, baseUrl, urlFactory, clientOptions, internalClientOptions) {
|
|
1038
1132
|
return new (this.getTransportConstructor(this.connectionMode))({
|
|
1039
|
-
|
|
1133
|
+
clientSession: this.clientSession,
|
|
1040
1134
|
clientSdkKey,
|
|
1041
1135
|
baseUrl,
|
|
1042
1136
|
resolveUrl: urlFactory,
|
|
@@ -1063,10 +1157,23 @@ var DefaultConfigDirectorClient = class {
|
|
|
1063
1157
|
}
|
|
1064
1158
|
async initialize(context) {
|
|
1065
1159
|
if (!this.hasReceivedConfigSet) this.initializing = true;
|
|
1066
|
-
await this.
|
|
1160
|
+
await this.submitContext(context, "initialization");
|
|
1067
1161
|
}
|
|
1068
1162
|
async updateContext(context) {
|
|
1069
|
-
await this.
|
|
1163
|
+
await this.submitContext(context, "context update");
|
|
1164
|
+
}
|
|
1165
|
+
async submitContext(context, submission) {
|
|
1166
|
+
await this.connectToTransport(this.contextToConnectWith(context, submission), submission);
|
|
1167
|
+
}
|
|
1168
|
+
contextToConnectWith(suppliedContext, submission) {
|
|
1169
|
+
const admission = admitContext(suppliedContext);
|
|
1170
|
+
switch (admission.outcome) {
|
|
1171
|
+
case "admitted": return admission.context;
|
|
1172
|
+
case "ignored":
|
|
1173
|
+
this.logger.error(`[ConfigDirectorClient] Ignored the context supplied for ${submission} because its kind '${admission.kindSample}' is invalid; connecting as if no context was supplied. A context kind has 1 to 64 characters, using only lowercase letters, digits, '-' and '_'.`);
|
|
1174
|
+
this.telemetryClient.recordInvalidContext(admission.kindSample);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1070
1177
|
}
|
|
1071
1178
|
get context() {
|
|
1072
1179
|
return this.currentContext;
|
|
@@ -1534,6 +1641,7 @@ const TEST_CLIENT_SDK_KEY = "test-client";
|
|
|
1534
1641
|
const noopTelemetryClient = {
|
|
1535
1642
|
updateContext: async () => {},
|
|
1536
1643
|
evaluatedConfig: () => {},
|
|
1644
|
+
recordInvalidContext: () => {},
|
|
1537
1645
|
close: async () => {}
|
|
1538
1646
|
};
|
|
1539
1647
|
var InMemoryTestClient = class {
|
|
@@ -1638,7 +1746,7 @@ const installTestClient = (testClient) => {
|
|
|
1638
1746
|
const createTestClient = (options) => {
|
|
1639
1747
|
return createTestClient$1({
|
|
1640
1748
|
sdkName: "nuxt-sdk",
|
|
1641
|
-
sdkVersion: "1.
|
|
1749
|
+
sdkVersion: "1.10.0"
|
|
1642
1750
|
}, options);
|
|
1643
1751
|
};
|
|
1644
1752
|
//#endregion
|
package/package.json
CHANGED
|
File without changes
|