@appxiom/4react 0.1.6 → 0.1.8

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/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  ## Requirements
19
19
 
20
- - React 18 or later.
20
+ - React 18 or React 19.
21
21
  - A browser environment. The SDK uses browser APIs and must not run during server-side rendering.
22
22
  - Node.js 18 or later for package installation and builds.
23
23
 
@@ -90,7 +90,7 @@ ax.reportCustomIssue('Payment failed', 'Gateway timed out.', severity, {
90
90
 
91
91
  After initialization, the integration adds automatic browser-side observation for React hook activity. It records lifecycle activity associated with `useEffect`, `useLayoutEffect`, `useState`, `useReducer`, `useMemo`, and `useCallback`. It also tracks `useRef` instances for leak analysis.
92
92
 
93
- Initialize the package before rendering the application so the instrumentation is available when components begin rendering. These integrations are installed once per page and do not require component-level wrappers or hooks.
93
+ Initialize the package before rendering the application so the instrumentation is available when components begin rendering. These integrations are installed once per page and do not require component-level wrappers or hooks. React 18 and React 19 use different internal dispatcher locations; `@appxiom/4react` resolves the compatible location automatically.
94
94
 
95
95
  ## Vite
96
96
 
@@ -4,6 +4,7 @@
4
4
  import React from 'react';
5
5
  import { AX } from '@appxiom/core';
6
6
  import { useRefLeakTracker } from '../memory/ax-react-useref-leak.js';
7
+ import { getDispatcherSlot, getReactInternals } from './react-internals.js';
7
8
 
8
9
  function emitLifecycleEvent(name, payload = {}) {
9
10
  try {
@@ -105,7 +106,7 @@ function getBestFrame(stack) {
105
106
  }
106
107
 
107
108
  function getComponentName() {
108
- const internals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
109
+ const internals = getReactInternals(React);
109
110
 
110
111
  try {
111
112
  const reactStack = internals?.getCurrentStack?.();
@@ -147,17 +148,24 @@ function wrapHook(dispatcher, name, wrapper) {
147
148
  * Dispatcher patch (THIS is the critical layer)
148
149
  * ----------------------------------------------------- */
149
150
  function patchDispatcher() {
150
- const internals =
151
- React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
151
+ const internals = getReactInternals(React);
152
+ const dispatcherSlot = getDispatcherSlot(internals);
152
153
 
153
- if (internals.__AX_DISPATCHER_PATCHED__) return;
154
- internals.__AX_DISPATCHER_PATCHED__ = true;
154
+ if (!internals || !dispatcherSlot) return;
155
155
 
156
- let currentDispatcher = internals.H;
156
+ if (internals?.__AX_DISPATCHER_PATCHED__) return;
157
+ try {
158
+ internals.__AX_DISPATCHER_PATCHED__ = true;
159
+ } catch {
160
+ return;
161
+ }
157
162
 
158
- Object.defineProperty(internals, 'H', {
159
- configurable: true,
160
- get() {
163
+ let currentDispatcher = dispatcherSlot.target[dispatcherSlot.key];
164
+
165
+ try {
166
+ Object.defineProperty(dispatcherSlot.target, dispatcherSlot.key, {
167
+ configurable: true,
168
+ get() {
161
169
  const dispatcher = currentDispatcher;
162
170
 
163
171
  if (!dispatcher || dispatcher.__AX_PATCHED__) {
@@ -276,12 +284,17 @@ function patchDispatcher() {
276
284
  return original.apply(ctx, args);
277
285
  });
278
286
 
279
- return dispatcher;
280
- },
281
- set(v) {
282
- currentDispatcher = v;
283
- },
284
- });
287
+ return dispatcher;
288
+ },
289
+ set(v) {
290
+ currentDispatcher = v;
291
+ },
292
+ });
293
+ } catch {
294
+ try {
295
+ internals.__AX_DISPATCHER_PATCHED__ = false;
296
+ } catch {}
297
+ }
285
298
  }
286
299
 
287
300
  /* -------------------------------------------------------
@@ -0,0 +1,19 @@
1
+ export function getReactInternals(react) {
2
+ return react?.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
3
+ || react?.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
4
+ || null;
5
+ }
6
+
7
+ export function getDispatcherSlot(internals) {
8
+ if (!internals) return null;
9
+
10
+ if ('H' in internals) {
11
+ return { target: internals, key: 'H' };
12
+ }
13
+
14
+ if (internals.ReactCurrentDispatcher) {
15
+ return { target: internals.ReactCurrentDispatcher, key: 'current' };
16
+ }
17
+
18
+ return null;
19
+ }
package/package.json CHANGED
@@ -3,8 +3,8 @@
3
3
  "description": "React integration layer for Appxiom Web Observability SDK",
4
4
  "license": "UNLICENSED",
5
5
  "author": "BasilGregory Software Labs Private Limited",
6
- "homepage": "https://appxiom.io",
7
- "version": "0.1.6",
6
+ "homepage": "https://www.appxiom.com",
7
+ "version": "0.1.8",
8
8
  "publishConfig": {
9
9
  "access": "public"
10
10
  },
@@ -29,10 +29,11 @@
29
29
  "LICENSE"
30
30
  ],
31
31
  "scripts": {
32
- "check:files": "test -f index.js && test -f core/ax-react.js && test -f lifecycle/patch.js && test -f memory/ax-react-useref-leak.js",
32
+ "check:files": "test -f index.js && test -f core/ax-react.js && test -f lifecycle/patch.js && test -f lifecycle/react-internals.js && test -f memory/ax-react-useref-leak.js",
33
+ "check:react-compat": "node test/react-internals.test.js",
33
34
  "check:types": "tsc --project test/types/tsconfig.json --noEmit",
34
35
  "pack:dry-run": "npm pack --dry-run",
35
- "prepublishOnly": "npm run check:files && npm run pack:dry-run"
36
+ "prepublishOnly": "npm run check:files && npm run check:react-compat && npm run pack:dry-run"
36
37
  },
37
38
  "sideEffects": true,
38
39
  "main": "index.js",
@@ -44,7 +45,7 @@
44
45
  "typescript": "^5.9.3"
45
46
  },
46
47
  "peerDependencies": {
47
- "react": ">=18"
48
+ "react": "^18.0.0 || ^19.0.0"
48
49
  },
49
50
  "keywords": [
50
51
  "appxiom",