@dcl/hooks 2.0.3 → 2.0.4-20261008193059.commit-428d6ed
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 +42 -20
- package/esm/contexts/analytics/AnalyticsProvider.js.map +1 -1
- package/esm/contexts/analytics/types.d.ts +26 -2
- package/esm/hooks/useAnalytics.js +4 -9
- package/esm/hooks/useAnalytics.js.map +1 -1
- package/esm/hooks/usePageTracking.d.ts +6 -4
- package/esm/hooks/usePageTracking.js +5 -3
- package/esm/hooks/usePageTracking.js.map +1 -1
- package/package.json +2 -2
|
@@ -11,13 +11,23 @@ const KEEPALIVE_DELIVERY = {
|
|
|
11
11
|
};
|
|
12
12
|
const AnalyticsContext = createContext(null);
|
|
13
13
|
const AnalyticsProvider = (props) => {
|
|
14
|
-
const { writeKey, userId, traits, cdnUrl, apiHost, children } = props;
|
|
14
|
+
const { writeKey, userId, traits, cdnUrl, apiHost, deliveryStrategy, children, } = props;
|
|
15
15
|
const analyticsRef = useRef(null);
|
|
16
|
+
// Kept out of the effect's dependencies: callers tend to pass it as an inline object, which would
|
|
17
|
+
// reload analytics on every render. It only matters at load time.
|
|
18
|
+
// Synced in an effect declared before the load effect, which runs first, so a render React discards
|
|
19
|
+
// never leaks its value into a load.
|
|
20
|
+
const deliveryStrategyRef = useRef(deliveryStrategy);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
deliveryStrategyRef.current = deliveryStrategy;
|
|
23
|
+
});
|
|
16
24
|
// Identifies the run that owns the instance. Advanced synchronously on every run AND on every
|
|
17
25
|
// cleanup, so a load still awaiting its import when the provider is reconfigured or unmounted sees a
|
|
18
26
|
// stale generation and abandons instead of taking over.
|
|
19
27
|
const generationRef = useRef(0);
|
|
20
|
-
|
|
28
|
+
// `loading`: the instance exists and buffers calls, but analytics.js has not fetched its settings and
|
|
29
|
+
// registered its plugins yet. `ready`: it has, and `isInitialized` reports true.
|
|
30
|
+
const [status, setStatus] = useState("idle");
|
|
21
31
|
useEffect(() => {
|
|
22
32
|
const generation = ++generationRef.current;
|
|
23
33
|
const isCurrent = () => generation === generationRef.current;
|
|
@@ -43,15 +53,15 @@ const AnalyticsProvider = (props) => {
|
|
|
43
53
|
if (resolvedCdnUrl) {
|
|
44
54
|
settings.cdnURL = resolvedCdnUrl;
|
|
45
55
|
}
|
|
46
|
-
// keepalive lets an event fired right before a navigation (a link click that
|
|
47
|
-
// page in the same tab) finish sending after the page unloads, instead of being
|
|
48
|
-
// with it. analytics-next leaves it off by default.
|
|
56
|
+
// keepalive, the default here, lets an event fired right before a navigation (a link click that
|
|
57
|
+
// loads the next page in the same tab) finish sending after the page unloads, instead of being
|
|
58
|
+
// cancelled with it. analytics-next leaves it off by default.
|
|
49
59
|
const resolvedApiHost = resolveApiHost(apiHost);
|
|
50
60
|
const options = {
|
|
51
61
|
integrations: {
|
|
52
62
|
[SEGMENT_IO]: {
|
|
53
63
|
...(resolvedApiHost ? { apiHost: resolvedApiHost } : {}),
|
|
54
|
-
deliveryStrategy: KEEPALIVE_DELIVERY,
|
|
64
|
+
deliveryStrategy: deliveryStrategyRef.current ?? KEEPALIVE_DELIVERY,
|
|
55
65
|
},
|
|
56
66
|
},
|
|
57
67
|
};
|
|
@@ -59,16 +69,29 @@ const AnalyticsProvider = (props) => {
|
|
|
59
69
|
if (userId) {
|
|
60
70
|
analytics.identify(userId, traits);
|
|
61
71
|
}
|
|
62
|
-
// Published
|
|
63
|
-
// the registry holding an instance this run never finished setting up.
|
|
72
|
+
// Published once everything above, which is synchronous, succeeded: a throw leaves neither
|
|
73
|
+
// the ref nor the registry holding an instance this run never finished setting up.
|
|
64
74
|
analyticsRef.current = analytics;
|
|
65
75
|
registerAnalyticsInstance(analytics);
|
|
66
|
-
|
|
76
|
+
setStatus("loading");
|
|
77
|
+
// The instance buffers calls straight away but only sends them once analytics.js has fetched
|
|
78
|
+
// its settings and registered its plugins. Reporting ready before that tells a caller that an
|
|
79
|
+
// event fired right before a navigation will go out, while it can still be sitting in the
|
|
80
|
+
// buffer when the page unloads.
|
|
81
|
+
await analytics;
|
|
82
|
+
if (isCurrent()) {
|
|
83
|
+
setStatus("ready");
|
|
84
|
+
}
|
|
67
85
|
}
|
|
68
86
|
catch (error) {
|
|
69
87
|
console.error("[Analytics] Failed to initialize:", error);
|
|
70
88
|
if (isCurrent()) {
|
|
89
|
+
const instance = analyticsRef.current;
|
|
90
|
+
if (instance) {
|
|
91
|
+
unregisterAnalyticsInstance(instance);
|
|
92
|
+
}
|
|
71
93
|
analyticsRef.current = null;
|
|
94
|
+
setStatus("idle");
|
|
72
95
|
}
|
|
73
96
|
}
|
|
74
97
|
})();
|
|
@@ -80,20 +103,18 @@ const AnalyticsProvider = (props) => {
|
|
|
80
103
|
unregisterAnalyticsInstance(instance);
|
|
81
104
|
analyticsRef.current = null;
|
|
82
105
|
}
|
|
83
|
-
|
|
106
|
+
setStatus("idle");
|
|
84
107
|
};
|
|
85
108
|
}, [writeKey, userId, traits, cdnUrl, apiHost]);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
};
|
|
109
|
+
// Calls are delegated as soon as the instance exists, so one made while it loads is buffered and sent
|
|
110
|
+
// once it is ready instead of being dropped. Only `isInitialized` waits for the load. The methods keep
|
|
111
|
+
// their identity from `loading` to `ready`, so an effect that depends on them does not fire twice.
|
|
112
|
+
const isAvailable = status !== "idle";
|
|
113
|
+
const methods = useMemo(() => {
|
|
114
|
+
if (!isAvailable) {
|
|
115
|
+
return { track: () => { }, identify: () => { }, page: () => { } };
|
|
94
116
|
}
|
|
95
117
|
return {
|
|
96
|
-
isInitialized: true,
|
|
97
118
|
track: (event, payload) => {
|
|
98
119
|
analyticsRef.current?.track(event, payload);
|
|
99
120
|
},
|
|
@@ -104,7 +125,8 @@ const AnalyticsProvider = (props) => {
|
|
|
104
125
|
analyticsRef.current?.page(name, props);
|
|
105
126
|
},
|
|
106
127
|
};
|
|
107
|
-
}, [
|
|
128
|
+
}, [isAvailable]);
|
|
129
|
+
const contextValue = useMemo(() => ({ isInitialized: status === "ready", isAvailable, ...methods }), [status, isAvailable, methods]);
|
|
108
130
|
return (_jsx(AnalyticsContext.Provider, { value: contextValue, children: children }));
|
|
109
131
|
};
|
|
110
132
|
export { AnalyticsContext, AnalyticsProvider };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../../src/contexts/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":";AAAA,OAAc,EACZ,aAAa,EACb,SAAS,EACT,OAAO,EACP,MAAM,EACN,QAAQ,GACT,MAAM,OAAO,CAAA;AAMd,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EACL,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAOvD,uEAAuE;AACvE,MAAM,UAAU,GAAG,YAAY,CAAA;AAE/B,MAAM,kBAAkB,GAAG;IACzB,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;CACnB,CAAA;AAEV,MAAM,gBAAgB,GAAG,aAAa,CAA8B,IAAI,CAAC,CAAA;AAEzE,MAAM,iBAAiB,GAAqC,CAC1D,KAA6B,EAC7B,EAAE;IACF,MAAM,
|
|
1
|
+
{"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../../src/contexts/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import type { EventProperties } from "@segment/analytics-next";
|
|
1
|
+
import type { EventProperties, InitOptions } from "@segment/analytics-next";
|
|
2
|
+
type SegmentIoOptions = Exclude<NonNullable<NonNullable<InitOptions["integrations"]>["Segment.io"]>, boolean>;
|
|
3
|
+
/** How analytics-next's Segment.io integration sends events: standard (one request per event) or batching. */
|
|
4
|
+
type AnalyticsDeliveryStrategy = NonNullable<SegmentIoOptions["deliveryStrategy"]>;
|
|
2
5
|
type AnalyticsProviderProps = {
|
|
3
6
|
writeKey: string;
|
|
4
7
|
userId?: string;
|
|
@@ -18,13 +21,34 @@ type AnalyticsProviderProps = {
|
|
|
18
21
|
* The provider maps it to the `apiHost` setting of analytics-next's own `Segment.io` integration.
|
|
19
22
|
*/
|
|
20
23
|
apiHost?: string;
|
|
24
|
+
/**
|
|
25
|
+
* How events are delivered. Defaults to standard delivery with `keepalive`, so an event fired right before a
|
|
26
|
+
* same-tab navigation still goes out. Browsers cap all in-flight keepalive requests of a page at 64KB, so an app
|
|
27
|
+
* that sends large or very frequent events can pass its own strategy, e.g. `{ strategy: "batching" }`.
|
|
28
|
+
*
|
|
29
|
+
* A strategy replaces the default entirely: `{ strategy: "standard", config: { priority: "high" } }` turns
|
|
30
|
+
* keepalive off. Batching already flushes with keepalive when the page unloads, so it normally does not lose an event
|
|
31
|
+
* fired right before a navigation. The unload flush shares the same 64KB cap, though, so a large batch `size` or
|
|
32
|
+
* large payloads can still drop part of it; adding `keepalive: true` to batching makes every batch a keepalive
|
|
33
|
+
* request and brings the 64KB pressure back for the whole session.
|
|
34
|
+
*
|
|
35
|
+
* Read when analytics loads: changing it afterwards does not reload analytics.
|
|
36
|
+
*/
|
|
37
|
+
deliveryStrategy?: AnalyticsDeliveryStrategy;
|
|
21
38
|
children: React.ReactNode;
|
|
22
39
|
};
|
|
23
40
|
type TrackPayload = EventProperties;
|
|
24
41
|
type AnalyticsContextType = {
|
|
42
|
+
/** Segment fetched its settings and registered its plugins, so a new call is dispatched right away. */
|
|
25
43
|
isInitialized: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Calls reach Segment: true from the moment the instance exists, when calls made while it still loads are
|
|
46
|
+
* buffered and sent once it is ready. False with no write key, for bots, before the SDK import and after a
|
|
47
|
+
* failed load. Optional so hand-built context values keep compiling; read `isAvailable ?? isInitialized`.
|
|
48
|
+
*/
|
|
49
|
+
isAvailable?: boolean;
|
|
26
50
|
track: (event: string, payload?: TrackPayload) => void;
|
|
27
51
|
identify: (userId: string, traits?: Record<string, unknown>) => void;
|
|
28
52
|
page: (name: string, props?: Record<string, unknown>) => void;
|
|
29
53
|
};
|
|
30
|
-
export { type AnalyticsProviderProps, type TrackPayload, type AnalyticsContextType, };
|
|
54
|
+
export { type AnalyticsDeliveryStrategy, type AnalyticsProviderProps, type TrackPayload, type AnalyticsContextType, };
|
|
@@ -5,16 +5,11 @@ const useAnalytics = () => {
|
|
|
5
5
|
if (!analyticsContext) {
|
|
6
6
|
throw new Error("useAnalytics must be used within AnalyticsProvider");
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
isInitialized: false,
|
|
11
|
-
track: () => { },
|
|
12
|
-
identify: () => { },
|
|
13
|
-
page: () => { },
|
|
14
|
-
};
|
|
15
|
-
}
|
|
8
|
+
// The provider already hands out no-op methods while there is no instance, and buffering ones while
|
|
9
|
+
// it loads: passing them through keeps a call made during the load from being dropped here.
|
|
16
10
|
return {
|
|
17
|
-
isInitialized:
|
|
11
|
+
isInitialized: analyticsContext.isInitialized,
|
|
12
|
+
isAvailable: analyticsContext.isAvailable,
|
|
18
13
|
track: analyticsContext.track,
|
|
19
14
|
identify: analyticsContext.identify,
|
|
20
15
|
page: analyticsContext.page,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAnalytics.js","sourceRoot":"","sources":["../../src/hooks/useAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AAG1E,MAAM,YAAY,GAAG,GAAyB,EAAE;IAC9C,MAAM,gBAAgB,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAA;IACrD,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACvE,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"useAnalytics.js","sourceRoot":"","sources":["../../src/hooks/useAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AAG1E,MAAM,YAAY,GAAG,GAAyB,EAAE;IAC9C,MAAM,gBAAgB,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAA;IACrD,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACvE,CAAC;IAED,oGAAoG;IACpG,4FAA4F;IAC5F,OAAO;QACL,aAAa,EAAE,gBAAgB,CAAC,aAAa;QAC7C,WAAW,EAAE,gBAAgB,CAAC,WAAW;QACzC,KAAK,EAAE,gBAAgB,CAAC,KAAK;QAC7B,QAAQ,EAAE,gBAAgB,CAAC,QAAQ;QACnC,IAAI,EAAE,gBAAgB,CAAC,IAAI;KAC5B,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -8,15 +8,17 @@ type PageTrackingProperties = Record<string, unknown>;
|
|
|
8
8
|
* Backwards-compatible with the original signature.
|
|
9
9
|
*
|
|
10
10
|
* 2. `usePageTracking(name, properties)` — fires `page(name, properties)` only
|
|
11
|
-
*
|
|
11
|
+
* once analytics is available AND `name` is a non-empty string. Use this
|
|
12
12
|
* shape when the page title is resolved asynchronously (e.g. from a CMS via
|
|
13
13
|
* Helmet + RTK Query) so the event lands AFTER `document.title` updates,
|
|
14
14
|
* avoiding the SPA race that lets Segment auto-capture the previous route's
|
|
15
15
|
* title via `properties.title`.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Both shapes wait for analytics to be AVAILABLE, not fully initialized: once
|
|
18
|
+
* the instance exists a page view is buffered while Segment loads and sent when
|
|
19
|
+
* it is ready, so a route the visitor leaves in-app before then still counts.
|
|
20
|
+
* Before that (`page` is the no-op fallback) the call is skipped and fires when
|
|
21
|
+
* analytics becomes available.
|
|
20
22
|
*/
|
|
21
23
|
declare function usePageTracking(path: string): void;
|
|
22
24
|
declare function usePageTracking(name: string | undefined, properties?: PageTrackingProperties): void;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
2
|
import { useAnalytics } from "./useAnalytics";
|
|
3
3
|
function usePageTracking(name, properties) {
|
|
4
|
-
const { isInitialized, page } = useAnalytics();
|
|
4
|
+
const { isAvailable: available, isInitialized, page } = useAnalytics();
|
|
5
|
+
// Context values built without `isAvailable` (older providers, test doubles) fall back to readiness.
|
|
6
|
+
const isAvailable = available ?? isInitialized;
|
|
5
7
|
const propertiesKey = properties ? JSON.stringify(properties) : "";
|
|
6
8
|
const propertiesRef = useRef(properties);
|
|
7
9
|
propertiesRef.current = properties;
|
|
8
10
|
useEffect(() => {
|
|
9
|
-
if (!
|
|
11
|
+
if (!isAvailable || !name)
|
|
10
12
|
return;
|
|
11
13
|
page(name, propertiesRef.current);
|
|
12
|
-
}, [
|
|
14
|
+
}, [isAvailable, name, propertiesKey, page]);
|
|
13
15
|
}
|
|
14
16
|
export { usePageTracking };
|
|
15
17
|
//# sourceMappingURL=usePageTracking.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePageTracking.js","sourceRoot":"","sources":["../../src/hooks/usePageTracking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"usePageTracking.js","sourceRoot":"","sources":["../../src/hooks/usePageTracking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AA8B7C,SAAS,eAAe,CACtB,IAAwB,EACxB,UAAmC;IAEnC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,YAAY,EAAE,CAAA;IACtE,qGAAqG;IACrG,MAAM,WAAW,GAAG,SAAS,IAAI,aAAa,CAAA;IAC9C,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAClE,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,CAAA;IACxC,aAAa,CAAC,OAAO,GAAG,UAAU,CAAA;IAElC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI;YAAE,OAAM;QACjC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;IACnC,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC,CAAA;AAC9C,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl/hooks",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4-20261008193059.commit-428d6ed",
|
|
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": "428d6ed0266ea35a87301f76446760f3b8837bdc"
|
|
84
84
|
}
|