@appxiom/4react 0.1.6

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/LICENSE ADDED
@@ -0,0 +1,5 @@
1
+ Copyright (c) 2026 BasilGregory Software Labs Private Limited
2
+
3
+ All rights reserved.
4
+
5
+ This software is licensed, not sold. No part of this software may be copied, modified, distributed, reverse engineered, or used except as expressly permitted by BasilGregory Software Labs Private Limited.
package/README.md ADDED
@@ -0,0 +1,252 @@
1
+ # Appxiom React SDK (`@appxiom/4react`)
2
+
3
+ `@appxiom/4react` initializes the Appxiom browser SDK and adds React-aware instrumentation for application lifecycle activity and `useRef` leak detection. It depends on `@appxiom/core`, which npm installs automatically.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Requirements](#requirements)
8
+ - [Installation](#installation)
9
+ - [Quick Start](#quick-start)
10
+ - [TypeScript](#typescript)
11
+ - [Automatic React Instrumentation](#automatic-react-instrumentation)
12
+ - [Vite](#vite)
13
+ - [SSR Frameworks](#ssr-frameworks)
14
+ - [Production Deployment](#production-deployment)
15
+ - [Public API](#public-api)
16
+ - [Troubleshooting](#troubleshooting)
17
+
18
+ ## Requirements
19
+
20
+ - React 18 or later.
21
+ - A browser environment. The SDK uses browser APIs and must not run during server-side rendering.
22
+ - Node.js 18 or later for package installation and builds.
23
+
24
+ ## Installation
25
+
26
+ Install the React integration and React. `@appxiom/core` is installed automatically as a dependency.
27
+
28
+ ```bash
29
+ npm install @appxiom/4react react
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ Initialize the SDK once from browser-only application startup code. Retain the returned `ax` instance to call its public API elsewhere in your application.
35
+
36
+ ### JavaScript
37
+
38
+ ```javascript
39
+ import init from '@appxiom/4react';
40
+
41
+ const ax = await init(
42
+ 'YOUR_APP_KEY',
43
+ 'YOUR_PLATFORM_KEY',
44
+ '1.0.0',
45
+ 'build-001',
46
+ );
47
+ ```
48
+
49
+ ### TypeScript
50
+
51
+ ```typescript
52
+ import init, { type AXReact } from '@appxiom/4react';
53
+
54
+ const ax: AXReact = await init(
55
+ 'YOUR_APP_KEY',
56
+ 'YOUR_PLATFORM_KEY',
57
+ '1.0.0',
58
+ 'build-001',
59
+ );
60
+ ```
61
+
62
+ ## TypeScript
63
+
64
+ `@appxiom/4react` ships first-party TypeScript declarations. No separate `@types` package is required. `init(...)` returns `Promise<AXReact>`, and `AXReact` extends the public `AX` API from `@appxiom/core`.
65
+
66
+ ```typescript
67
+ import init, { type AXReact } from '@appxiom/4react';
68
+ import type { IssueSeverity } from '@appxiom/core';
69
+
70
+ const ax: AXReact = await init(
71
+ 'YOUR_APP_KEY',
72
+ 'YOUR_PLATFORM_KEY',
73
+ '1.0.0',
74
+ 'build-001',
75
+ );
76
+
77
+ const severity: IssueSeverity = 1;
78
+
79
+ ax.setCustomId('user-12345');
80
+ ax.startGoal('checkout');
81
+ ax.logActivity('Checkout started', { cartValue: 120 });
82
+ ax.reportCustomIssue('Payment failed', 'Gateway timed out.', severity, {
83
+ orderId: 'ORD-10023',
84
+ });
85
+ ```
86
+
87
+ `IssueSeverity` is limited to `0` (Minor), `1` (Major), or `2` (Fatal).
88
+
89
+ ## Automatic React Instrumentation
90
+
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
+
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.
94
+
95
+ ## Vite
96
+
97
+ `@appxiom/4react` depends on `@appxiom/core`, which includes a WebAssembly binary. During local development, exclude both packages from Vite dependency optimization so Vite preserves the binary's source-relative URL:
98
+
99
+ ### JavaScript
100
+
101
+ ```javascript
102
+ import { defineConfig } from 'vite';
103
+ import react from '@vitejs/plugin-react';
104
+
105
+ export default defineConfig({
106
+ plugins: [react()],
107
+ optimizeDeps: {
108
+ exclude: ['@appxiom/4react', '@appxiom/core'],
109
+ },
110
+ });
111
+ ```
112
+
113
+ ### TypeScript
114
+
115
+ ```typescript
116
+ import { defineConfig } from 'vite';
117
+ import react from '@vitejs/plugin-react';
118
+
119
+ export default defineConfig({
120
+ plugins: [react()],
121
+ optimizeDeps: {
122
+ exclude: ['@appxiom/4react', '@appxiom/core'],
123
+ },
124
+ });
125
+ ```
126
+
127
+ After adding the configuration, clear Vite's optimized-dependency cache and restart the development server:
128
+
129
+ ```bash
130
+ rm -rf node_modules/.vite
131
+ npm run dev -- --force
132
+ ```
133
+
134
+ This setting only affects Vite's development dependency optimizer. It is safe to keep in the configuration for production builds.
135
+
136
+ ## SSR Frameworks
137
+
138
+ For Next.js, Nuxt, SvelteKit, Remix, or any other server-rendered application, load and initialize the SDK only on the client. Do not import or initialize it from server components, route handlers, or server rendering code.
139
+
140
+ ### JavaScript
141
+
142
+ ```javascript
143
+ if (typeof window !== 'undefined') {
144
+ const { default: init } = await import('@appxiom/4react');
145
+
146
+ const ax = await init(
147
+ 'YOUR_APP_KEY',
148
+ 'YOUR_PLATFORM_KEY',
149
+ '1.0.0',
150
+ 'build-001',
151
+ );
152
+ }
153
+ ```
154
+
155
+ ### TypeScript
156
+
157
+ ```typescript
158
+ if (typeof window !== 'undefined') {
159
+ const { default: init } = await import('@appxiom/4react');
160
+
161
+ const ax = await init(
162
+ 'YOUR_APP_KEY',
163
+ 'YOUR_PLATFORM_KEY',
164
+ '1.0.0',
165
+ 'build-001',
166
+ );
167
+ }
168
+ ```
169
+
170
+ For React client applications, initialize in the browser entry point before `createRoot(...).render(...)`. For Next.js, use a Client Component or another client-only initialization path.
171
+
172
+ ## Production Deployment
173
+
174
+ Build and deploy the application normally. For a Vite application:
175
+
176
+ ```bash
177
+ npm run build
178
+ ```
179
+
180
+ The production build emits Appxiom's WebAssembly binary as an asset and rewrites its loader URL. Deploy the complete build output, including the generated `.wasm` file, without renaming or omitting assets.
181
+
182
+ Your CDN or web server must return this header for WebAssembly assets:
183
+
184
+ ```http
185
+ Content-Type: application/wasm
186
+ ```
187
+
188
+ Ensure SPA fallback rules do not return `index.html` for `.wasm` requests. Returning HTML instead of the binary causes errors such as `expected magic word 00 61 73 6d`.
189
+
190
+ ## Public API
191
+
192
+ ### `init(appKey, platformKey, version, buildIdentifier)`
193
+
194
+ Initializes the core SDK, installs the React instrumentation, and returns `Promise<AXReact>`.
195
+
196
+ | Parameter | Type | Description |
197
+ | --- | --- | --- |
198
+ | `appKey` | `string` | Appxiom application key. |
199
+ | `platformKey` | `string` | Appxiom platform key. |
200
+ | `version` | `string` | Application version. |
201
+ | `buildIdentifier` | `string` | Optional build or release identifier. |
202
+
203
+ ### Inherited `AX` methods
204
+
205
+ The returned `AXReact` instance inherits these supported methods from `@appxiom/core`:
206
+
207
+ - `setCustomId(customId)`: associates telemetry with an application user or account identifier.
208
+ - `startGoal(name)`: starts a named goal.
209
+ - `endGoal(name, properties?, value?)`: ends a named goal with optional metadata and numeric value.
210
+ - `logActivity(name, properties?)`: records a custom activity with optional metadata.
211
+ - `reportCustomIssue(title, description, severity, data?, stacktrace?)`: reports an application-defined issue.
212
+
213
+ #### JavaScript
214
+
215
+ ```javascript
216
+ ax.setCustomId('user-12345');
217
+ ax.startGoal('checkout');
218
+ ax.logActivity('Checkout started', { cartValue: 120 });
219
+ ax.endGoal('checkout', { orderId: 'ORD-10023' }, 120);
220
+ ```
221
+
222
+ #### TypeScript
223
+
224
+ ```typescript
225
+ import type { IssueSeverity } from '@appxiom/core';
226
+
227
+ const severity: IssueSeverity = 1;
228
+
229
+ ax.setCustomId('user-12345');
230
+ ax.startGoal('checkout');
231
+ ax.logActivity('Checkout started', { cartValue: 120 });
232
+ ax.reportCustomIssue('Payment failed', 'Gateway timed out.', severity, {
233
+ orderId: 'ORD-10023',
234
+ });
235
+ ax.endGoal('checkout', { orderId: 'ORD-10023' }, 120);
236
+ ```
237
+
238
+ For the complete core API and deployment details, see the `@appxiom/core` package documentation.
239
+
240
+ ## Troubleshooting
241
+
242
+ ### Vite development reports a WASM MIME type or `expected magic word` error
243
+
244
+ Add the Vite `optimizeDeps.exclude` configuration above, delete `node_modules/.vite`, and restart the development server with `--force`.
245
+
246
+ ### Production reports `expected magic word 00 61 73 6d`
247
+
248
+ Confirm that the generated `.wasm` asset was deployed, that no SPA fallback rewrites its request to `index.html`, and that the response MIME type is `application/wasm`.
249
+
250
+ ### The SDK runs during server rendering
251
+
252
+ Move the package import and `init(...)` call to browser-only code. Use a client component, framework client plugin, browser entry point, or a dynamic import guarded by `typeof window !== 'undefined'`.
@@ -0,0 +1,18 @@
1
+ import { AX } from '@appxiom/core';
2
+
3
+ // Singleton AXReact class extending AX
4
+ export class AXReact extends AX {
5
+ constructor(appKey, platformKey, version, buildIdentifier) {
6
+ super(appKey, platformKey, version, buildIdentifier);
7
+ }
8
+
9
+ async launch() {
10
+ await super.launch();
11
+ // Load runtime patches synchronously using dynamic imports
12
+
13
+ await import('../memory/ax-react-useref-leak.js');
14
+ await import('../lifecycle/patch.js');
15
+
16
+
17
+ }
18
+ }
package/index.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { AX } from '@appxiom/core';
2
+
3
+ export class AXReact extends AX {
4
+ constructor(
5
+ appKey: string,
6
+ platformKey: string,
7
+ version: string,
8
+ buildIdentifier?: string,
9
+ );
10
+
11
+ launch(): Promise<void>;
12
+ }
13
+
14
+ export default function init(
15
+ appKey: string,
16
+ platformKey: string,
17
+ version: string,
18
+ buildIdentifier?: string,
19
+ ): Promise<AXReact>;
package/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import { AXReact } from './core/ax-react.js';
2
+
3
+ export default async function init(appKey, platformKey, version, buildIdentifier) {
4
+ const ax = new AXReact(appKey, platformKey, version, buildIdentifier);
5
+ await ax.launch();
6
+ return ax;
7
+ }
8
+
9
+ export { AXReact };
@@ -0,0 +1,296 @@
1
+ // React lifecycle tracker module
2
+ // React 18 / 19 compatible – dispatcher-based interception
3
+
4
+ import React from 'react';
5
+ import { AX } from '@appxiom/core';
6
+ import { useRefLeakTracker } from '../memory/ax-react-useref-leak.js';
7
+
8
+ function emitLifecycleEvent(name, payload = {}) {
9
+ try {
10
+ const instance = AX.instance;
11
+ if (!instance?.logEventActivity) return;
12
+ instance.logEventActivity(name, payload);
13
+ } catch {
14
+ // Never block app execution for lifecycle logging.
15
+ }
16
+ }
17
+
18
+ function lifecycleEventName(component, action) {
19
+ const label = component || 'Anonymous';
20
+ return `${label} :: ${action}`;
21
+ }
22
+
23
+ /* -------------------------------------------------------
24
+ * Component name (best-effort, non-fatal)
25
+ * ----------------------------------------------------- */
26
+ function toComponentLabel(value) {
27
+ if (!value) return 'Anonymous';
28
+
29
+ const cleaned = String(value)
30
+ .replace(/^Object\./, '')
31
+ .replace(/:\d+:\d+$/, '')
32
+ .replace(/\?.*$/, '')
33
+ .replace(/#.*$/, '');
34
+
35
+ const fileOrSymbol = cleaned.split('/').pop() || cleaned;
36
+ const stem = fileOrSymbol.replace(/\.(jsx|tsx|js|ts)$/i, '');
37
+
38
+ // Prefer component-ish names (capitalized), otherwise keep best effort label.
39
+ if (/^[A-Z][A-Za-z0-9_$]*$/.test(stem)) {
40
+ return stem;
41
+ }
42
+
43
+ return stem || 'Anonymous';
44
+ }
45
+
46
+ function normalizeFrame(frameLine) {
47
+ const symbolMatch = frameLine.match(/at\s+([^\s(]+)/);
48
+ if (symbolMatch?.[1]) {
49
+ const symbol = symbolMatch[1].replace(/^Object\./, '');
50
+
51
+ // Stack frames in Vite dev can be raw URLs like
52
+ // http://localhost:5173/src/App.jsx:845:39
53
+ // Normalize these to file/component-ish names.
54
+ if (symbol.includes('://') || symbol.includes('/')) {
55
+ const cleaned = symbol
56
+ .replace(/^https?:\/\//, '')
57
+ .replace(/^[^/]+\//, '')
58
+ .replace(/:\d+:\d+$/, '');
59
+ const file = cleaned.split('/').pop() || cleaned;
60
+ return toComponentLabel(file);
61
+ }
62
+
63
+ return toComponentLabel(symbol);
64
+ }
65
+
66
+ const pathMatch = frameLine.match(/\((.*):(\d+):(\d+)\)$/) || frameLine.match(/at\s+(.*):(\d+):(\d+)$/);
67
+ if (pathMatch?.[1]) {
68
+ const rawPath = pathMatch[1];
69
+ const parts = rawPath.split('/');
70
+ return toComponentLabel(parts[parts.length - 1] || rawPath);
71
+ }
72
+
73
+ return 'Anonymous';
74
+ }
75
+
76
+ function getBestFrame(stack) {
77
+ if (!stack) return null;
78
+
79
+ const lines = stack
80
+ .split('\n')
81
+ .map((line) => line.trim())
82
+ .filter(Boolean);
83
+
84
+ const ignoredMarkers = [
85
+ 'ax-react/lifecycle/patch.js',
86
+ 'getComponentName',
87
+ 'getBestFrame',
88
+ 'normalizeFrame',
89
+ 'wrapHook',
90
+ 'wrapped',
91
+ 'emitLifecycleEvent',
92
+ ];
93
+
94
+ const candidateLines = lines.filter((line) => {
95
+ if (!line.startsWith('at ')) return false;
96
+ if (ignoredMarkers.some((marker) => line.includes(marker))) return false;
97
+ return true;
98
+ });
99
+
100
+ const appFrame = candidateLines.find((line) =>
101
+ line.includes('/src/') || line.includes('.jsx') || line.includes('.tsx'),
102
+ );
103
+
104
+ return appFrame || candidateLines[0] || null;
105
+ }
106
+
107
+ function getComponentName() {
108
+ const internals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
109
+
110
+ try {
111
+ const reactStack = internals?.getCurrentStack?.();
112
+ const frame = getBestFrame(reactStack);
113
+ if (frame) return normalizeFrame(frame);
114
+ } catch {
115
+ // Fallback below.
116
+ }
117
+
118
+ try {
119
+ const stack = new Error().stack;
120
+ const frame = getBestFrame(stack);
121
+ if (frame) return normalizeFrame(frame);
122
+ } catch {
123
+ // Fall through.
124
+ }
125
+
126
+ return 'Anonymous';
127
+ }
128
+
129
+ /* -------------------------------------------------------
130
+ * Hook wrapper utility
131
+ * ----------------------------------------------------- */
132
+ function wrapHook(dispatcher, name, wrapper) {
133
+ if (!dispatcher[name] || dispatcher[name].__AX_WRAPPED__) return;
134
+
135
+ const original = dispatcher[name];
136
+
137
+ function wrapped(...args) {
138
+ return wrapper(original, this, args);
139
+ }
140
+
141
+ wrapped.__AX_WRAPPED__ = true;
142
+ wrapped.__AX_ORIGINAL__ = original;
143
+ dispatcher[name] = wrapped;
144
+ }
145
+
146
+ /* -------------------------------------------------------
147
+ * Dispatcher patch (THIS is the critical layer)
148
+ * ----------------------------------------------------- */
149
+ function patchDispatcher() {
150
+ const internals =
151
+ React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
152
+
153
+ if (internals.__AX_DISPATCHER_PATCHED__) return;
154
+ internals.__AX_DISPATCHER_PATCHED__ = true;
155
+
156
+ let currentDispatcher = internals.H;
157
+
158
+ Object.defineProperty(internals, 'H', {
159
+ configurable: true,
160
+ get() {
161
+ const dispatcher = currentDispatcher;
162
+
163
+ if (!dispatcher || dispatcher.__AX_PATCHED__) {
164
+ return dispatcher;
165
+ }
166
+
167
+ dispatcher.__AX_PATCHED__ = true;
168
+
169
+ /* ---------------- useRef ---------------- */
170
+ wrapHook(dispatcher, 'useRef', (original, ctx, args) => {
171
+ const component = getComponentName();
172
+ const ref = original.apply(ctx, args);
173
+
174
+ try {
175
+ useRefLeakTracker.trackRef(ref, {
176
+ component,
177
+ createdAt: performance.now(),
178
+ });
179
+ emitLifecycleEvent(lifecycleEventName(component, 'React useRef Created'), {
180
+ component,
181
+ hasInitialValue: args[0] !== undefined,
182
+ });
183
+ } catch {
184
+ }
185
+
186
+ return ref;
187
+ });
188
+
189
+ /* ---------------- useEffect ---------------- */
190
+ wrapHook(dispatcher, 'useEffect', (original, ctx, args) => {
191
+ const component = getComponentName();
192
+ const effect = args[0];
193
+
194
+ args[0] = function wrappedEffect() {
195
+ emitLifecycleEvent(lifecycleEventName(component, 'React useEffect Mounted'), { component });
196
+ const cleanup = effect();
197
+
198
+ if (typeof cleanup === 'function') {
199
+ return function wrappedCleanup() {
200
+ emitLifecycleEvent(lifecycleEventName(component, 'React useEffect Cleanup'), { component });
201
+ return cleanup();
202
+ };
203
+ }
204
+ return cleanup;
205
+ };
206
+
207
+ return original.apply(ctx, args);
208
+ });
209
+
210
+ /* ---------------- useLayoutEffect ---------------- */
211
+ wrapHook(dispatcher, 'useLayoutEffect', (original, ctx, args) => {
212
+ const component = getComponentName();
213
+ const effect = args[0];
214
+
215
+ args[0] = function wrappedLayoutEffect() {
216
+ emitLifecycleEvent(lifecycleEventName(component, 'React useLayoutEffect Mounted'), { component });
217
+ const cleanup = effect();
218
+
219
+ if (typeof cleanup === 'function') {
220
+ return function wrappedLayoutCleanup() {
221
+ emitLifecycleEvent(lifecycleEventName(component, 'React useLayoutEffect Cleanup'), { component });
222
+ return cleanup();
223
+ };
224
+ }
225
+
226
+ return cleanup;
227
+ };
228
+
229
+ return original.apply(ctx, args);
230
+ });
231
+
232
+ /* ---------------- useState ---------------- */
233
+ wrapHook(dispatcher, 'useState', (original, ctx, args) => {
234
+ const component = getComponentName();
235
+ const [state, setState] = original.apply(ctx, args);
236
+
237
+ const wrappedSetState = (value) => {
238
+ emitLifecycleEvent(lifecycleEventName(component, 'React useState Updated'), {
239
+ component,
240
+ updateType: typeof value,
241
+ });
242
+ return setState(value);
243
+ };
244
+
245
+ return [state, wrappedSetState];
246
+ });
247
+
248
+ /* ---------------- useReducer ---------------- */
249
+ wrapHook(dispatcher, 'useReducer', (original, ctx, args) => {
250
+ const component = getComponentName();
251
+
252
+ const [state, dispatch] = original.apply(ctx, args);
253
+
254
+ const wrappedDispatch = (action) => {
255
+ emitLifecycleEvent(lifecycleEventName(component, 'React useReducer Dispatched'), {
256
+ component,
257
+ actionType: typeof action,
258
+ });
259
+ return dispatch(action);
260
+ };
261
+
262
+ return [state, wrappedDispatch];
263
+ });
264
+
265
+ /* ---------------- useMemo ---------------- */
266
+ wrapHook(dispatcher, 'useMemo', (original, ctx, args) => {
267
+ const component = getComponentName();
268
+ emitLifecycleEvent(lifecycleEventName(component, 'React useMemo Evaluated'), { component });
269
+ return original.apply(ctx, args);
270
+ });
271
+
272
+ /* ---------------- useCallback ---------------- */
273
+ wrapHook(dispatcher, 'useCallback', (original, ctx, args) => {
274
+ const component = getComponentName();
275
+ emitLifecycleEvent(lifecycleEventName(component, 'React useCallback Registered'), { component });
276
+ return original.apply(ctx, args);
277
+ });
278
+
279
+ return dispatcher;
280
+ },
281
+ set(v) {
282
+ currentDispatcher = v;
283
+ },
284
+ });
285
+ }
286
+
287
+ /* -------------------------------------------------------
288
+ * Public init API
289
+ * ----------------------------------------------------- */
290
+ if (!React.__AX_REACT_PATCHED__) {
291
+
292
+ React.__AX_REACT_PATCHED__ = true;
293
+
294
+ patchDispatcher();
295
+
296
+ }
@@ -0,0 +1,15 @@
1
+ import { LeakTracker } from '@appxiom/core';
2
+
3
+ class UseRefLeakTracker extends LeakTracker {
4
+ // Constructor
5
+ constructor() {
6
+ super(2); // useRef leak type
7
+ }
8
+
9
+ trackRef(ref, metadata = {}) {
10
+ if (!ref) return;
11
+ this.trackInstance(ref, metadata);
12
+ }
13
+ }
14
+
15
+ export const useRefLeakTracker = new UseRefLeakTracker();
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@appxiom/4react",
3
+ "description": "React integration layer for Appxiom Web Observability SDK",
4
+ "license": "UNLICENSED",
5
+ "author": "BasilGregory Software Labs Private Limited",
6
+ "homepage": "https://appxiom.io",
7
+ "version": "0.1.6",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "engines": {
12
+ "node": ">=18"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./index.d.ts",
17
+ "import": "./index.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "types": "./index.d.ts",
22
+ "files": [
23
+ "index.js",
24
+ "index.d.ts",
25
+ "core/",
26
+ "lifecycle/",
27
+ "memory/",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
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",
33
+ "check:types": "tsc --project test/types/tsconfig.json --noEmit",
34
+ "pack:dry-run": "npm pack --dry-run",
35
+ "prepublishOnly": "npm run check:files && npm run pack:dry-run"
36
+ },
37
+ "sideEffects": true,
38
+ "main": "index.js",
39
+ "module": "index.js",
40
+ "dependencies": {
41
+ "@appxiom/core": "^0.1.6"
42
+ },
43
+ "devDependencies": {
44
+ "typescript": "^5.9.3"
45
+ },
46
+ "peerDependencies": {
47
+ "react": ">=18"
48
+ },
49
+ "keywords": [
50
+ "appxiom",
51
+ "react",
52
+ "observability",
53
+ "monitoring",
54
+ "analytics",
55
+ "rum",
56
+ "performance"
57
+ ],
58
+ "type": "module"
59
+ }