@dcl/hooks 1.4.1-20260609121712.commit-bda8dc1 → 1.5.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.
@@ -1,11 +1,16 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useMemo, useRef, useState } from "react";
3
3
  import { isbot } from "isbot";
4
+ import { resolveApiHost, resolveCdnUrl } from "./utils";
4
5
  import { useAsyncEffect } from "../../hooks/useAsyncEffect";
6
+ // Integration key analytics-next reserves for its own ingestion plugin
7
+ const SEGMENT_IO = "Segment.io";
5
8
  const AnalyticsContext = createContext(null);
6
9
  const AnalyticsProvider = (props) => {
7
- const { writeKey, userId, traits, children } = props;
10
+ const { writeKey, userId, traits, cdnUrl, apiHost, children } = props;
8
11
  const analyticsRef = useRef(null);
12
+ // Identifies the latest load, so an earlier one whose import resolves after it cannot take over
13
+ const loadIdRef = useRef(0);
9
14
  const [isInitialized, setIsInitialized] = useState(false);
10
15
  useAsyncEffect(async () => {
11
16
  if (!writeKey) {
@@ -18,20 +23,40 @@ const AnalyticsProvider = (props) => {
18
23
  console.log("[Analytics] Skipping load: bot detected");
19
24
  return;
20
25
  }
26
+ const loadId = ++loadIdRef.current;
21
27
  try {
22
28
  // eslint-disable-next-line @typescript-eslint/naming-convention
23
29
  const { AnalyticsBrowser } = await import("@segment/analytics-next");
24
- analyticsRef.current = AnalyticsBrowser.load({ writeKey });
30
+ const settings = { writeKey };
31
+ const resolvedCdnUrl = resolveCdnUrl(cdnUrl);
32
+ if (resolvedCdnUrl) {
33
+ settings.cdnURL = resolvedCdnUrl;
34
+ }
35
+ const options = {};
36
+ const resolvedApiHost = resolveApiHost(apiHost);
37
+ if (resolvedApiHost) {
38
+ options.integrations = { [SEGMENT_IO]: { apiHost: resolvedApiHost } };
39
+ }
40
+ const analytics = AnalyticsBrowser.load(settings, options);
41
+ // A newer configuration won while this import was in flight. analytics-next has no teardown for
42
+ // the superseded instance (`reset` only clears the identity, which would drop the anonymous id
43
+ // and break attribution), so it is left unreferenced instead of overwriting the current one.
44
+ if (loadId !== loadIdRef.current) {
45
+ return;
46
+ }
47
+ analyticsRef.current = analytics;
25
48
  if (userId) {
26
- analyticsRef.current.identify(userId, traits);
49
+ analytics.identify(userId, traits);
27
50
  }
28
51
  setIsInitialized(true);
29
52
  }
30
53
  catch (error) {
31
54
  console.error("[Analytics] Failed to initialize:", error);
32
- analyticsRef.current = null;
55
+ if (loadId === loadIdRef.current) {
56
+ analyticsRef.current = null;
57
+ }
33
58
  }
34
- }, [writeKey, userId, traits]);
59
+ }, [writeKey, userId, traits, cdnUrl, apiHost]);
35
60
  const contextValue = useMemo(() => {
36
61
  if (!analyticsRef.current || !isInitialized) {
37
62
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../../src/contexts/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../../src/contexts/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":"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"}
@@ -3,6 +3,21 @@ type AnalyticsProviderProps = {
3
3
  writeKey: string;
4
4
  userId?: string;
5
5
  traits?: Record<string, unknown>;
6
+ /**
7
+ * Origin analytics.js fetches its settings and its remote plugins from. Defaults to Segment's cdn, which ad
8
+ * blockers drop, so apps can point it at a first party proxy instead. Example: `https://analytics.example.org`.
9
+ *
10
+ * Named after this library's camelCase convention (`writeKey`, `apiHost`); the provider maps it to the
11
+ * `cdnURL` setting analytics-next actually takes.
12
+ */
13
+ cdnUrl?: string;
14
+ /**
15
+ * Host events are delivered to, without a protocol (`host/basePath`). Defaults to Segment's ingestion endpoint,
16
+ * which ad blockers drop too. Example: `analytics.example.org/v1`.
17
+ *
18
+ * The provider maps it to the `apiHost` setting of analytics-next's own `Segment.io` integration.
19
+ */
20
+ apiHost?: string;
6
21
  children: React.ReactNode;
7
22
  };
8
23
  type TrackPayload = EventProperties;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Normalizes the origin analytics.js fetches its settings and its remote plugins from, which ad blockers drop when it
3
+ * is Segment's own cdn. Returns `undefined` when unset or invalid, which keeps the default.
4
+ */
5
+ declare function resolveCdnUrl(cdnUrl?: string): string | undefined;
6
+ /**
7
+ * Normalizes the host events are delivered to. analytics-next takes it without a protocol (`host/basePath`) and
8
+ * prepends one, so a value that carries it is accepted and stripped instead of producing `https://https://host`.
9
+ * Returns `undefined` when unset or invalid, which keeps the default.
10
+ */
11
+ declare function resolveApiHost(apiHost?: string): string | undefined;
12
+ export { resolveApiHost, resolveCdnUrl };
@@ -0,0 +1,51 @@
1
+ const PROTOCOL_PREFIX = /^[a-z][a-z0-9+.-]*:\/\//i;
2
+ const TRAILING_SLASHES = /\/+$/;
3
+ /**
4
+ * Both the cdn url and the api host decide where a third party script is loaded from and where every event is
5
+ * delivered, so they are meant to be trusted values coming from the build configuration of the app, never from user
6
+ * input. A value that is not a valid url, or that is not served over https unless it belongs to the app's own origin,
7
+ * is ignored with a warning so analytics degrades to Segment's defaults instead of pointing at an untrusted host.
8
+ */
9
+ function resolveUrl(name, value) {
10
+ let resolved;
11
+ try {
12
+ resolved = new URL(value, window.location.href);
13
+ }
14
+ catch (_error) {
15
+ console.warn(`[Analytics] Ignoring the ${name} "${value}", it is not a valid url`);
16
+ return undefined;
17
+ }
18
+ if (resolved.protocol !== "https:" &&
19
+ resolved.origin !== window.location.origin) {
20
+ console.warn(`[Analytics] Ignoring the ${name} "${value}", it is not served over https`);
21
+ return undefined;
22
+ }
23
+ return resolved;
24
+ }
25
+ /**
26
+ * Normalizes the origin analytics.js fetches its settings and its remote plugins from, which ad blockers drop when it
27
+ * is Segment's own cdn. Returns `undefined` when unset or invalid, which keeps the default.
28
+ */
29
+ function resolveCdnUrl(cdnUrl) {
30
+ if (!cdnUrl) {
31
+ return undefined;
32
+ }
33
+ const resolved = resolveUrl("cdn url", cdnUrl);
34
+ // analytics-next appends `/v1/projects/<writeKey>/settings` to it, a trailing slash would double the separator
35
+ return resolved && resolved.href.replace(TRAILING_SLASHES, "");
36
+ }
37
+ /**
38
+ * Normalizes the host events are delivered to. analytics-next takes it without a protocol (`host/basePath`) and
39
+ * prepends one, so a value that carries it is accepted and stripped instead of producing `https://https://host`.
40
+ * Returns `undefined` when unset or invalid, which keeps the default.
41
+ */
42
+ function resolveApiHost(apiHost) {
43
+ if (!apiHost) {
44
+ return undefined;
45
+ }
46
+ const resolved = resolveUrl("api host", PROTOCOL_PREFIX.test(apiHost) ? apiHost : `https://${apiHost}`);
47
+ return (resolved &&
48
+ `${resolved.host}${resolved.pathname}`.replace(TRAILING_SLASHES, ""));
49
+ }
50
+ export { resolveApiHost, resolveCdnUrl };
51
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/contexts/analytics/utils.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,0BAA0B,CAAA;AAClD,MAAM,gBAAgB,GAAG,MAAM,CAAA;AAE/B;;;;;GAKG;AACH,SAAS,UAAU,CAAC,IAAY,EAAE,KAAa;IAC7C,IAAI,QAAa,CAAA;IAEjB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IACjD,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CACV,4BAA4B,IAAI,KAAK,KAAK,0BAA0B,CACrE,CAAA;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IACE,QAAQ,CAAC,QAAQ,KAAK,QAAQ;QAC9B,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,EAC1C,CAAC;QACD,OAAO,CAAC,IAAI,CACV,4BAA4B,IAAI,KAAK,KAAK,gCAAgC,CAC3E,CAAA;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,MAAe;IACpC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IAE9C,+GAA+G;IAC/G,OAAO,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;AAChE,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,OAAgB;IACtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CACzB,UAAU,EACV,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,OAAO,EAAE,CAC/D,CAAA;IAED,OAAO,CACL,QAAQ;QACR,GAAG,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CACrE,CAAA;AACH,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcl/hooks",
3
- "version": "1.4.1-20260609121712.commit-bda8dc1",
3
+ "version": "1.5.0",
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": "bda8dc1fb7508a6b17ada81d31c10201b5f4b08b"
83
+ "commit": "73b020b3ad32bd274d02fc3abb1ea8f09cce218d"
84
84
  }