@dcl/hooks 1.5.1 → 1.5.2-20260825155555.commit-5057e08
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/esm/contexts/analytics/AnalyticsProvider.js +57 -40
- package/esm/contexts/analytics/AnalyticsProvider.js.map +1 -1
- package/esm/contexts/analytics/registry.d.ts +18 -0
- package/esm/contexts/analytics/registry.js +30 -0
- package/esm/contexts/analytics/registry.js.map +1 -0
- package/esm/contexts/index.d.ts +1 -0
- package/esm/contexts/index.js +2 -0
- package/esm/contexts/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,61 +1,78 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { createContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
3
3
|
import { isbot } from "isbot";
|
|
4
|
+
import { registerAnalyticsInstance, unregisterAnalyticsInstance, } from "./registry";
|
|
4
5
|
import { resolveApiHost, resolveCdnUrl } from "./utils";
|
|
5
|
-
import { useAsyncEffect } from "../../hooks/useAsyncEffect";
|
|
6
6
|
// Integration key analytics-next reserves for its own ingestion plugin
|
|
7
7
|
const SEGMENT_IO = "Segment.io";
|
|
8
8
|
const AnalyticsContext = createContext(null);
|
|
9
9
|
const AnalyticsProvider = (props) => {
|
|
10
10
|
const { writeKey, userId, traits, cdnUrl, apiHost, children } = props;
|
|
11
11
|
const analyticsRef = useRef(null);
|
|
12
|
-
// Identifies the
|
|
13
|
-
|
|
12
|
+
// Identifies the run that owns the instance. Advanced synchronously on every run AND on every
|
|
13
|
+
// cleanup, so a load still awaiting its import when the provider is reconfigured or unmounted sees a
|
|
14
|
+
// stale generation and abandons instead of taking over.
|
|
15
|
+
const generationRef = useRef(0);
|
|
14
16
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
15
|
-
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const generation = ++generationRef.current;
|
|
19
|
+
const isCurrent = () => generation === generationRef.current;
|
|
16
20
|
if (!writeKey) {
|
|
17
21
|
console.log("[Analytics] No writeKey provided");
|
|
18
|
-
return;
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
const isBot = isbot(userAgent);
|
|
22
|
-
if (isBot) {
|
|
23
|
+
else if (isbot(navigator.userAgent)) {
|
|
23
24
|
console.log("[Analytics] Skipping load: bot detected");
|
|
24
|
-
return;
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
26
|
+
else {
|
|
27
|
+
void (async () => {
|
|
28
|
+
try {
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
30
|
+
const { AnalyticsBrowser } = await import("@segment/analytics-next");
|
|
31
|
+
// A newer configuration won, or the provider unmounted, while this import was in flight.
|
|
32
|
+
// analytics-next has no teardown for an instance, so this run creates none at all rather
|
|
33
|
+
// than loading one it would have to leave unreferenced.
|
|
34
|
+
if (!isCurrent()) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const settings = { writeKey };
|
|
38
|
+
const resolvedCdnUrl = resolveCdnUrl(cdnUrl);
|
|
39
|
+
if (resolvedCdnUrl) {
|
|
40
|
+
settings.cdnURL = resolvedCdnUrl;
|
|
41
|
+
}
|
|
42
|
+
const options = {};
|
|
43
|
+
const resolvedApiHost = resolveApiHost(apiHost);
|
|
44
|
+
if (resolvedApiHost) {
|
|
45
|
+
options.integrations = {
|
|
46
|
+
[SEGMENT_IO]: { apiHost: resolvedApiHost },
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const analytics = AnalyticsBrowser.load(settings, options);
|
|
50
|
+
if (userId) {
|
|
51
|
+
analytics.identify(userId, traits);
|
|
52
|
+
}
|
|
53
|
+
// Published last: everything above is synchronous, so a throw leaves neither the ref nor
|
|
54
|
+
// the registry holding an instance this run never finished setting up.
|
|
55
|
+
analyticsRef.current = analytics;
|
|
56
|
+
registerAnalyticsInstance(analytics);
|
|
57
|
+
setIsInitialized(true);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error("[Analytics] Failed to initialize:", error);
|
|
61
|
+
if (isCurrent()) {
|
|
62
|
+
analyticsRef.current = null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
})();
|
|
52
66
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
67
|
+
return () => {
|
|
68
|
+
generationRef.current++;
|
|
69
|
+
const instance = analyticsRef.current;
|
|
70
|
+
if (instance) {
|
|
71
|
+
unregisterAnalyticsInstance(instance);
|
|
56
72
|
analyticsRef.current = null;
|
|
57
73
|
}
|
|
58
|
-
|
|
74
|
+
setIsInitialized(false);
|
|
75
|
+
};
|
|
59
76
|
}, [writeKey, userId, traits, cdnUrl, apiHost]);
|
|
60
77
|
const contextValue = useMemo(() => {
|
|
61
78
|
if (!analyticsRef.current || !isInitialized) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../../src/contexts/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":";AAAA,OAAc,
|
|
1
|
+
{"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../../src/contexts/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AnalyticsBrowser } from "@segment/analytics-next";
|
|
2
|
+
/**
|
|
3
|
+
* The AnalyticsBrowser instance the mounted AnalyticsProvider loaded, for code that runs outside React
|
|
4
|
+
* (state stores, imperative modules) and cannot reach the context. Null until a provider initializes
|
|
5
|
+
* one, and null again once that provider unmounts or is reconfigured to a no-op (empty write key, bot
|
|
6
|
+
* session). analytics-next buffers the calls made through the instance while the remote script is still
|
|
7
|
+
* loading, so a caller needs no queue of its own.
|
|
8
|
+
*/
|
|
9
|
+
declare const getAnalytics: () => AnalyticsBrowser | null;
|
|
10
|
+
/** Registers the instance a successful load produced. Not part of the package's public API. */
|
|
11
|
+
declare const registerAnalyticsInstance: (instance: AnalyticsBrowser) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Clears the registry only when the given instance is the one registered, so a provider or a load that
|
|
14
|
+
* was already superseded cannot erase a newer registration when its cleanup runs late.
|
|
15
|
+
* Not part of the package's public API.
|
|
16
|
+
*/
|
|
17
|
+
declare const unregisterAnalyticsInstance: (instance: AnalyticsBrowser) => void;
|
|
18
|
+
export { getAnalytics, registerAnalyticsInstance, unregisterAnalyticsInstance };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
let current = null;
|
|
2
|
+
/**
|
|
3
|
+
* The AnalyticsBrowser instance the mounted AnalyticsProvider loaded, for code that runs outside React
|
|
4
|
+
* (state stores, imperative modules) and cannot reach the context. Null until a provider initializes
|
|
5
|
+
* one, and null again once that provider unmounts or is reconfigured to a no-op (empty write key, bot
|
|
6
|
+
* session). analytics-next buffers the calls made through the instance while the remote script is still
|
|
7
|
+
* loading, so a caller needs no queue of its own.
|
|
8
|
+
*/
|
|
9
|
+
const getAnalytics = () => current;
|
|
10
|
+
/** Registers the instance a successful load produced. Not part of the package's public API. */
|
|
11
|
+
const registerAnalyticsInstance = (instance) => {
|
|
12
|
+
// The registry is global while each provider owns its own context, so with two providers mounted at
|
|
13
|
+
// once the newest load silently wins for every caller outside React. Surface it instead.
|
|
14
|
+
if (current !== null && current !== instance) {
|
|
15
|
+
console.warn("[Analytics] Replacing the registered analytics instance: more than one AnalyticsProvider is mounted.");
|
|
16
|
+
}
|
|
17
|
+
current = instance;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Clears the registry only when the given instance is the one registered, so a provider or a load that
|
|
21
|
+
* was already superseded cannot erase a newer registration when its cleanup runs late.
|
|
22
|
+
* Not part of the package's public API.
|
|
23
|
+
*/
|
|
24
|
+
const unregisterAnalyticsInstance = (instance) => {
|
|
25
|
+
if (current === instance) {
|
|
26
|
+
current = null;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export { getAnalytics, registerAnalyticsInstance, unregisterAnalyticsInstance };
|
|
30
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/contexts/analytics/registry.ts"],"names":[],"mappings":"AAEA,IAAI,OAAO,GAA4B,IAAI,CAAA;AAE3C;;;;;;GAMG;AACH,MAAM,YAAY,GAAG,GAA4B,EAAE,CAAC,OAAO,CAAA;AAE3D,+FAA+F;AAC/F,MAAM,yBAAyB,GAAG,CAAC,QAA0B,EAAQ,EAAE;IACrE,oGAAoG;IACpG,yFAAyF;IACzF,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC7C,OAAO,CAAC,IAAI,CACV,sGAAsG,CACvG,CAAA;IACH,CAAC;IACD,OAAO,GAAG,QAAQ,CAAA;AACpB,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,2BAA2B,GAAG,CAAC,QAA0B,EAAQ,EAAE;IACvE,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,OAAO,GAAG,IAAI,CAAA;IAChB,CAAC;AACH,CAAC,CAAA;AAED,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,CAAA"}
|
package/esm/contexts/index.d.ts
CHANGED
package/esm/contexts/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export * from "./analytics/AnalyticsProvider";
|
|
2
|
+
// Only the reader is public: registering is the provider's business.
|
|
3
|
+
export { getAnalytics } from "./analytics/registry";
|
|
2
4
|
export * from "./translation/TranslationContext";
|
|
3
5
|
export * from "./translation/TranslationProvider";
|
|
4
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contexts/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contexts/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,qEAAqE;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnD,cAAc,kCAAkC,CAAA;AAChD,cAAc,mCAAmC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl/hooks",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2-20260825155555.commit-5057e08",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "esm/index.js",
|
|
6
6
|
"module": "esm/index.js",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"<rootDir>/test/setup.ts"
|
|
81
81
|
]
|
|
82
82
|
},
|
|
83
|
-
"commit": "
|
|
83
|
+
"commit": "5057e08c93dfdcc839c5f209ebfd28cf35908619"
|
|
84
84
|
}
|