@configdirector/nuxt-sdk 1.2.0 → 1.4.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.d.mts +37 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +13 -7
- package/dist/runtime/nitro/middleware.d.mts +1 -1
- package/dist/runtime/nitro/middleware.d.ts +1 -1
- package/dist/runtime/nitro/middleware.mjs +5 -3
- package/dist/runtime/nitro/plugin.d.mts +1 -0
- package/dist/runtime/nitro/plugin.d.ts +1 -0
- package/dist/runtime/nitro/plugin.mjs +12 -7
- package/dist/runtime/plugin.client.mjs +106 -7
- package/package.json +1 -1
package/dist/module.d.mts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as _$_nuxt_schema0 from "@nuxt/schema";
|
|
2
2
|
import { LogLevel } from "consola";
|
|
3
3
|
|
|
4
|
+
//#region ../shared/src/types.d.ts
|
|
5
|
+
type ConnectionMode = "streaming" | "polling";
|
|
6
|
+
//#endregion
|
|
4
7
|
//#region src/module.d.ts
|
|
5
8
|
interface ConfigDirectorRuntimeConfig {
|
|
6
9
|
/**
|
|
@@ -23,6 +26,40 @@ interface ConfigDirectorRuntimeConfig {
|
|
|
23
26
|
* Can be set via the NUXT_CONFIGDIRECTOR_BASE_URL environment variable.
|
|
24
27
|
*/
|
|
25
28
|
baseUrl?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Connection options for the server SDK client used during SSR and in Nitro handlers.
|
|
31
|
+
*/
|
|
32
|
+
connection?: {
|
|
33
|
+
/**
|
|
34
|
+
* The connection mode, one of `streaming` (default) or `polling`. In `streaming` mode the
|
|
35
|
+
* connection stays open and receives config updates as they happen. In `polling` mode configs
|
|
36
|
+
* are fetched once during initialization and then again on every `pollingInterval`.
|
|
37
|
+
* Can be set via the NUXT_CONFIGDIRECTOR_CONNECTION_MODE environment variable.
|
|
38
|
+
*/
|
|
39
|
+
mode?: ConnectionMode;
|
|
40
|
+
/**
|
|
41
|
+
* The polling interval in seconds when `mode` is `polling`. Has no effect in `streaming` mode.
|
|
42
|
+
* When omitted (or `0`), the server SDK default is used.
|
|
43
|
+
* Can be set via the NUXT_CONFIGDIRECTOR_CONNECTION_POLLING_INTERVAL environment variable.
|
|
44
|
+
*/
|
|
45
|
+
pollingInterval?: number;
|
|
46
|
+
/**
|
|
47
|
+
* How long, in milliseconds, the server SDK client waits for its initial config payload. Requests
|
|
48
|
+
* that arrive before the payload is received are held until it arrives or this timeout elapses,
|
|
49
|
+
* after which they render with default values. When omitted (or `0`), the server SDK default is used.
|
|
50
|
+
* Can be set via the NUXT_CONFIGDIRECTOR_CONNECTION_TIMEOUT environment variable.
|
|
51
|
+
*/
|
|
52
|
+
timeout?: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Whether requests that arrive before the server SDK client received its initial config payload
|
|
56
|
+
* (for example right after the server starts) wait for it, for up to the connection `timeout`, before
|
|
57
|
+
* being handled. When disabled, such requests are handled immediately and evaluate configs to their
|
|
58
|
+
* default values until the payload arrives.
|
|
59
|
+
*
|
|
60
|
+
* Defaults to `true`. Can be set via the NUXT_CONFIGDIRECTOR_WAIT_FOR_INITIALIZATION environment variable.
|
|
61
|
+
*/
|
|
62
|
+
waitForInitialization?: boolean;
|
|
26
63
|
}
|
|
27
64
|
interface ConfigDirectorPublicRuntimeConfig {
|
|
28
65
|
/**
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -11,14 +11,20 @@ var module_default = defineNuxtModule({
|
|
|
11
11
|
setup(options, nuxt) {
|
|
12
12
|
const logger = useLogger("configdirector");
|
|
13
13
|
const resolver = createResolver(import.meta.url);
|
|
14
|
-
|
|
15
|
-
serverSdkKey: "",
|
|
16
|
-
logLevel: options.logLevel,
|
|
17
|
-
baseUrl: ""
|
|
18
|
-
} : {
|
|
14
|
+
const serverDefaults = {
|
|
19
15
|
serverSdkKey: "",
|
|
20
|
-
baseUrl: ""
|
|
21
|
-
|
|
16
|
+
baseUrl: "",
|
|
17
|
+
connection: {
|
|
18
|
+
mode: "streaming",
|
|
19
|
+
pollingInterval: 0,
|
|
20
|
+
timeout: 0
|
|
21
|
+
},
|
|
22
|
+
waitForInitialization: true
|
|
23
|
+
};
|
|
24
|
+
nuxt.options.runtimeConfig.configdirector = defu(nuxt.options.runtimeConfig.configdirector, options.logLevel !== void 0 ? {
|
|
25
|
+
...serverDefaults,
|
|
26
|
+
logLevel: options.logLevel
|
|
27
|
+
} : serverDefaults);
|
|
22
28
|
nuxt.options.runtimeConfig.public.configdirector = defu(nuxt.options.runtimeConfig.public.configdirector, options.logLevel !== void 0 ? {
|
|
23
29
|
clientSdkKey: "",
|
|
24
30
|
logLevel: options.logLevel,
|
|
@@ -2,7 +2,7 @@ import * as _$h3 from "h3";
|
|
|
2
2
|
import { ConfigDirectorClient } from "@configdirector/server-sdk";
|
|
3
3
|
|
|
4
4
|
//#region src/runtime/nitro/middleware.d.ts
|
|
5
|
-
declare const _default: _$h3.EventHandler<_$h3.EventHandlerRequest, void
|
|
5
|
+
declare const _default: _$h3.EventHandler<_$h3.EventHandlerRequest, Promise<void>>;
|
|
6
6
|
declare module "h3" {
|
|
7
7
|
interface H3EventContext {
|
|
8
8
|
configDirectorClient: ConfigDirectorClient;
|
|
@@ -2,7 +2,7 @@ import * as _$h3 from "h3";
|
|
|
2
2
|
import { ConfigDirectorClient } from "@configdirector/server-sdk";
|
|
3
3
|
|
|
4
4
|
//#region src/runtime/nitro/middleware.d.ts
|
|
5
|
-
declare const _default: _$h3.EventHandler<_$h3.EventHandlerRequest, void
|
|
5
|
+
declare const _default: _$h3.EventHandler<_$h3.EventHandlerRequest, Promise<void>>;
|
|
6
6
|
declare module "h3" {
|
|
7
7
|
interface H3EventContext {
|
|
8
8
|
configDirectorClient: ConfigDirectorClient;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { useNitroApp } from "nitropack/runtime";
|
|
1
|
+
import { useNitroApp, useRuntimeConfig } from "nitropack/runtime";
|
|
2
2
|
import { defineEventHandler } from "h3";
|
|
3
3
|
//#region src/runtime/nitro/middleware.ts
|
|
4
|
-
var middleware_default = defineEventHandler((event) => {
|
|
5
|
-
|
|
4
|
+
var middleware_default = defineEventHandler(async (event) => {
|
|
5
|
+
const nitroApp = useNitroApp();
|
|
6
|
+
if (useRuntimeConfig(event).configdirector.waitForInitialization) await nitroApp.configDirectorInitialization;
|
|
7
|
+
event.context.configDirectorClient = nitroApp.configDirectorClient;
|
|
6
8
|
});
|
|
7
9
|
//#endregion
|
|
8
10
|
export { middleware_default as default };
|
|
@@ -476,7 +476,7 @@ var StreamingTransport = class {
|
|
|
476
476
|
return new ConfigDirectorConnectionError(`${`Connection failed with status: ${responseStatus ?? "unknown"}.`}${error ? ` Error: ${error}.` : ""} This is an unrecoverable error, will not attempt to reconnect.`, status);
|
|
477
477
|
}
|
|
478
478
|
isStatusFatal(status) {
|
|
479
|
-
return !!status && status >= 400 && status < 500;
|
|
479
|
+
return !!status && status >= 400 && status < 500 && status != 429;
|
|
480
480
|
}
|
|
481
481
|
get isConnected() {
|
|
482
482
|
return this.eventSource?.readyState == "open";
|
|
@@ -535,7 +535,7 @@ var AbstractPollingTransport = class {
|
|
|
535
535
|
return new ConfigDirectorConnectionError(`${`Connection failed with status: ${responseStatus ?? "unknown"}`}${(errorBody?.trim()?.length ?? 0) > 0 ? ` (${errorBody})` : ""}. This is an unrecoverable error, retry attempts will be ignored.`, status);
|
|
536
536
|
}
|
|
537
537
|
isStatusFatal(status) {
|
|
538
|
-
return !!status && status >= 400 && status < 500;
|
|
538
|
+
return !!status && status >= 400 && status < 500 && status != 429;
|
|
539
539
|
}
|
|
540
540
|
isFetchErrorFatal(fetchError) {
|
|
541
541
|
return fetchError?.name === "NotAllowedError";
|
|
@@ -7419,7 +7419,7 @@ var ServerEventReporter = class {
|
|
|
7419
7419
|
}
|
|
7420
7420
|
}
|
|
7421
7421
|
isStatusFatal(status) {
|
|
7422
|
-
return !!status && status >= 400 && status < 500;
|
|
7422
|
+
return !!status && status >= 400 && status < 500 && status != 429;
|
|
7423
7423
|
}
|
|
7424
7424
|
};
|
|
7425
7425
|
//#endregion
|
|
@@ -7967,16 +7967,21 @@ var plugin_default = defineNitroPlugin((nitroApp) => {
|
|
|
7967
7967
|
throw new ConfigDirectorInitializationError(message);
|
|
7968
7968
|
}
|
|
7969
7969
|
logger.debug("Initializing ConfigDirector Nitro plugin");
|
|
7970
|
-
const { serverSdkKey, baseUrl } = runtimeConfig.configdirector;
|
|
7970
|
+
const { serverSdkKey, baseUrl, connection } = runtimeConfig.configdirector;
|
|
7971
7971
|
const client = new DefaultConfigDirectorClient(serverSdkKey, {
|
|
7972
7972
|
sdkName: "nuxt-sdk",
|
|
7973
|
-
sdkVersion: "1.
|
|
7973
|
+
sdkVersion: "1.4.0"
|
|
7974
7974
|
}, {
|
|
7975
7975
|
logger,
|
|
7976
|
-
|
|
7976
|
+
connection: {
|
|
7977
|
+
url: baseUrl || void 0,
|
|
7978
|
+
mode: connection?.mode || void 0,
|
|
7979
|
+
pollingInterval: connection?.pollingInterval || void 0,
|
|
7980
|
+
timeout: connection?.timeout || void 0
|
|
7981
|
+
}
|
|
7977
7982
|
});
|
|
7978
7983
|
nitroApp.configDirectorClient = client;
|
|
7979
|
-
client.initialize();
|
|
7984
|
+
nitroApp.configDirectorInitialization = client.initialize();
|
|
7980
7985
|
});
|
|
7981
7986
|
//#endregion
|
|
7982
7987
|
export { plugin_default as default };
|
|
@@ -464,7 +464,7 @@ var StreamingTransport = class {
|
|
|
464
464
|
return new ConfigDirectorConnectionError(`${`Connection failed with status: ${responseStatus ?? "unknown"}.`}${error ? ` Error: ${error}` : ""}. This is an unrecoverable error, will not attempt to reconnect.`, status);
|
|
465
465
|
}
|
|
466
466
|
isStatusFatal(status) {
|
|
467
|
-
return !!status && status >= 400 && status < 500;
|
|
467
|
+
return !!status && status >= 400 && status < 500 && status != 429;
|
|
468
468
|
}
|
|
469
469
|
on(name, handler) {
|
|
470
470
|
this.eventEmitter.on(name, handler);
|
|
@@ -710,6 +710,91 @@ const generateInstanceId = () => {
|
|
|
710
710
|
});
|
|
711
711
|
};
|
|
712
712
|
//#endregion
|
|
713
|
+
//#region ../js-client-core/src/instance-id.ts
|
|
714
|
+
const STORAGE_KEY = "configdirector-sdk:instance-id";
|
|
715
|
+
const RECORD_VERSION = 1;
|
|
716
|
+
const MAX_AGE_MS = 360 * 60 * 1e3;
|
|
717
|
+
const CHECKSUM_SALT = "configdirector.instanceId.v1";
|
|
718
|
+
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}$/;
|
|
719
|
+
const fnv1a = (input, offsetBasis) => {
|
|
720
|
+
let hash = offsetBasis;
|
|
721
|
+
for (let i = 0; i < input.length; i++) {
|
|
722
|
+
hash ^= input.charCodeAt(i);
|
|
723
|
+
hash = Math.imul(hash, 16777619);
|
|
724
|
+
}
|
|
725
|
+
return hash >>> 0;
|
|
726
|
+
};
|
|
727
|
+
const checksumFor = (id, createdAt) => {
|
|
728
|
+
const payload = `${CHECKSUM_SALT}|${id}|${createdAt}`;
|
|
729
|
+
const low = fnv1a(payload, 2166136261);
|
|
730
|
+
return fnv1a(`${low}|${payload}`, 16777619).toString(16).padStart(8, "0") + low.toString(16).padStart(8, "0");
|
|
731
|
+
};
|
|
732
|
+
const getLocalStorage = () => {
|
|
733
|
+
try {
|
|
734
|
+
return globalThis.localStorage ?? void 0;
|
|
735
|
+
} catch {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
const isUsableRecord = (record) => {
|
|
740
|
+
if (!record || typeof record !== "object") return false;
|
|
741
|
+
const { v, id, createdAt, checksum } = record;
|
|
742
|
+
if (v !== RECORD_VERSION || typeof id !== "string" || typeof checksum !== "string") return false;
|
|
743
|
+
if (typeof createdAt !== "number" || !Number.isInteger(createdAt) || createdAt <= 0) return false;
|
|
744
|
+
if (!UUID_V4_PATTERN.test(id)) return false;
|
|
745
|
+
return checksum === checksumFor(id, createdAt);
|
|
746
|
+
};
|
|
747
|
+
const readStoredInstanceId = (storage, logger) => {
|
|
748
|
+
let raw;
|
|
749
|
+
try {
|
|
750
|
+
raw = storage.getItem(STORAGE_KEY);
|
|
751
|
+
} catch (error) {
|
|
752
|
+
logger?.debug("[ConfigDirectorClient] Could not read the stored instance id, generating a new one", error);
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (!raw) return;
|
|
756
|
+
let record;
|
|
757
|
+
try {
|
|
758
|
+
record = JSON.parse(raw);
|
|
759
|
+
} catch {
|
|
760
|
+
logger?.debug("[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one");
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (!isUsableRecord(record)) {
|
|
764
|
+
logger?.debug("[ConfigDirectorClient] The stored instance id failed validation, generating a new one");
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
const age = Date.now() - record.createdAt;
|
|
768
|
+
if (age < 0 || age >= MAX_AGE_MS) {
|
|
769
|
+
logger?.debug("[ConfigDirectorClient] The stored instance id has expired, generating a new one");
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
return record.id;
|
|
773
|
+
};
|
|
774
|
+
const storeInstanceId = (storage, id, logger) => {
|
|
775
|
+
const createdAt = Date.now();
|
|
776
|
+
const record = {
|
|
777
|
+
v: RECORD_VERSION,
|
|
778
|
+
id,
|
|
779
|
+
createdAt,
|
|
780
|
+
checksum: checksumFor(id, createdAt)
|
|
781
|
+
};
|
|
782
|
+
try {
|
|
783
|
+
storage.setItem(STORAGE_KEY, JSON.stringify(record));
|
|
784
|
+
} catch (error) {
|
|
785
|
+
logger?.debug("[ConfigDirectorClient] Could not persist the instance id", error);
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
const resolveInstanceId = (logger) => {
|
|
789
|
+
const storage = getLocalStorage();
|
|
790
|
+
if (!storage) return generateInstanceId();
|
|
791
|
+
const storedInstanceId = readStoredInstanceId(storage, logger);
|
|
792
|
+
if (storedInstanceId) return storedInstanceId;
|
|
793
|
+
const instanceId = generateInstanceId();
|
|
794
|
+
storeInstanceId(storage, instanceId, logger);
|
|
795
|
+
return instanceId;
|
|
796
|
+
};
|
|
797
|
+
//#endregion
|
|
713
798
|
//#region ../shared/src/transport/AbstractPollingTransport.ts
|
|
714
799
|
var AbstractPollingTransport = class {
|
|
715
800
|
fatalError = false;
|
|
@@ -743,7 +828,7 @@ var AbstractPollingTransport = class {
|
|
|
743
828
|
return new ConfigDirectorConnectionError(`${`Connection failed with status: ${responseStatus ?? "unknown"}`}${(errorBody?.trim()?.length ?? 0) > 0 ? ` (${errorBody})` : ""}. This is an unrecoverable error, retry attempts will be ignored.`, status);
|
|
744
829
|
}
|
|
745
830
|
isStatusFatal(status) {
|
|
746
|
-
return !!status && status >= 400 && status < 500;
|
|
831
|
+
return !!status && status >= 400 && status < 500 && status != 429;
|
|
747
832
|
}
|
|
748
833
|
isFetchErrorFatal(fetchError) {
|
|
749
834
|
return fetchError?.name === "NotAllowedError";
|
|
@@ -794,7 +879,9 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
794
879
|
this.options = options;
|
|
795
880
|
this.logger = options.logger;
|
|
796
881
|
this.url = options.resolveUrl("client/polling/v1", options.baseUrl);
|
|
797
|
-
|
|
882
|
+
const requestedInterval = options.pollingInterval ?? 300;
|
|
883
|
+
if (requestedInterval < 60) this.logger.warn(`[PollingTransport] pollingInterval of ${requestedInterval} seconds is below the minimum of 60 seconds. Using 60 seconds.`);
|
|
884
|
+
this.pollingIntervalSeconds = Math.max(requestedInterval, 60);
|
|
798
885
|
}
|
|
799
886
|
async connect(context, timeout) {
|
|
800
887
|
this.clearPollingInterval();
|
|
@@ -852,6 +939,17 @@ var PollingTransport = class extends AbstractPollingTransport {
|
|
|
852
939
|
}
|
|
853
940
|
};
|
|
854
941
|
//#endregion
|
|
942
|
+
//#region ../js-client-core/src/browser-globals.ts
|
|
943
|
+
const read = (readValue) => {
|
|
944
|
+
try {
|
|
945
|
+
return readValue(globalThis);
|
|
946
|
+
} catch {
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
const readUserAgent = () => read((globals) => globals.navigator?.userAgent);
|
|
951
|
+
const readHost = () => read((globals) => globals.location?.host);
|
|
952
|
+
//#endregion
|
|
855
953
|
//#region ../js-client-core/src/DefaultConfigDirectorClient.ts
|
|
856
954
|
const MAX_EXPONENTIAL_DELAY = 9;
|
|
857
955
|
var DefaultConfigDirectorClient = class {
|
|
@@ -871,8 +969,8 @@ var DefaultConfigDirectorClient = class {
|
|
|
871
969
|
connectionMode;
|
|
872
970
|
instanceId;
|
|
873
971
|
constructor(telemetryClient, clientSdkKey, sdkOptions, clientOptions, internalClientOptions) {
|
|
874
|
-
this.instanceId = generateInstanceId();
|
|
875
972
|
this.logger = clientOptions?.logger ?? createDefaultLogger$1();
|
|
973
|
+
this.instanceId = resolveInstanceId(this.logger);
|
|
876
974
|
this.timeout = clientOptions?.connection?.timeout ?? 3e3;
|
|
877
975
|
this.validateSdkKeyPresence(clientSdkKey);
|
|
878
976
|
const urlFactory = internalClientOptions?.urlFactory ?? defaultUrlFactory;
|
|
@@ -889,7 +987,8 @@ var DefaultConfigDirectorClient = class {
|
|
|
889
987
|
...clientOptions?.metadata,
|
|
890
988
|
sdkName: sdkOptions.sdkName,
|
|
891
989
|
sdkVersion: sdkOptions.sdkVersion,
|
|
892
|
-
userAgent:
|
|
990
|
+
userAgent: readUserAgent(),
|
|
991
|
+
host: readHost()
|
|
893
992
|
},
|
|
894
993
|
logger: this.logger,
|
|
895
994
|
fetch: internalClientOptions?.fetch,
|
|
@@ -1173,7 +1272,7 @@ var WebWorkerTelemetryClient = class {
|
|
|
1173
1272
|
flushIntervalDelay: options.flushIntervalDelay ?? 3e4
|
|
1174
1273
|
}
|
|
1175
1274
|
};
|
|
1176
|
-
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.sdkIdentity=e.sdkIdentity,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,metaContext:{sdkName:this.sdkIdentity.sdkName,sdkVersion:this.sdkIdentity.sdkVersion},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(){if(!this.collectEvents)return;let e;try{e=await this.flush()}catch(t){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events: `,t),e={success:!1,fatalError:!1}}e.fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.collectEvents&&(this.cancelScheduledFlush(),this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay))}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout);try{await this.flush()}catch(e){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events during close: `,e)}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=new TextEncoder,h=async e=>{if(typeof crypto>`u`||crypto.subtle==null)return;let t=await crypto.subtle.digest(`SHA-256`,m.encode(e?.toString()??``));return f(new Uint8Array(t,0,16),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`:if(g){y.warn(`[TelemetryWorker] Received a duplicate Initialize event, ignoring it`);break}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" })));
|
|
1275
|
+
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.sdkIdentity=e.sdkIdentity,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,metaContext:{sdkName:this.sdkIdentity.sdkName,sdkVersion:this.sdkIdentity.sdkVersion},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&&e!=429}},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(){if(!this.collectEvents)return;let e;try{e=await this.flush()}catch(t){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events: `,t),e={success:!1,fatalError:!1}}e.fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.collectEvents&&(this.cancelScheduledFlush(),this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay))}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout);try{await this.flush()}catch(e){this.logger.warn(`[TelemetryEventCollector] Error flushing telemetry events during close: `,e)}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=new TextEncoder,h=async e=>{if(typeof crypto>`u`||crypto.subtle==null)return;let t=await crypto.subtle.digest(`SHA-256`,m.encode(e?.toString()??``));return f(new Uint8Array(t,0,16),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`:if(g){y.warn(`[TelemetryWorker] Received a duplicate Initialize event, ignoring it`);break}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" })));
|
|
1177
1276
|
this.worker.onmessage = (message) => {
|
|
1178
1277
|
this.handleWorkerEvent(message.data);
|
|
1179
1278
|
};
|
|
@@ -1364,7 +1463,7 @@ var plugin_client_default = defineNuxtPlugin((nuxtApp) => {
|
|
|
1364
1463
|
const { clientSdkKey, appName, appVersion, baseUrl } = runtimeConfig.public.configdirector;
|
|
1365
1464
|
const client = createBrowserClient(clientSdkKey, {
|
|
1366
1465
|
sdkName: "nuxt-sdk",
|
|
1367
|
-
sdkVersion: "1.
|
|
1466
|
+
sdkVersion: "1.4.0"
|
|
1368
1467
|
}, {
|
|
1369
1468
|
metadata: {
|
|
1370
1469
|
appName,
|
package/package.json
CHANGED