react-native-ai-devtools-sdk 0.2.0 → 0.3.1
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 +52 -2
- package/dist/consoleBuffer.d.ts +2 -6
- package/dist/consoleBuffer.js +2 -20
- package/dist/global.d.ts +2 -0
- package/dist/global.js +6 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -0
- package/dist/networkBuffer.d.ts +2 -3
- package/dist/networkBuffer.js +2 -60
- package/dist/types.d.ts +8 -24
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -63,6 +63,40 @@ The AI assistant can then inspect store state directly:
|
|
|
63
63
|
execute_in_app with expression="globalThis.__RN_AI_DEVTOOLS__.stores.redux.getState()"
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
### With navigation
|
|
67
|
+
|
|
68
|
+
Pass your navigation reference for AI-powered navigation inspection:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import { init } from 'react-native-ai-devtools-sdk';
|
|
72
|
+
import { navigationRef } from './navigation';
|
|
73
|
+
|
|
74
|
+
if (__DEV__) {
|
|
75
|
+
init({
|
|
76
|
+
navigation: navigationRef,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### With custom references
|
|
82
|
+
|
|
83
|
+
Use `custom` to expose any additional tools, services, or objects that don't belong to stores or navigation (e.g. AsyncStorage, MMKV, analytics):
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
import { init } from 'react-native-ai-devtools-sdk';
|
|
87
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
88
|
+
import { storage } from './mmkv';
|
|
89
|
+
|
|
90
|
+
if (__DEV__) {
|
|
91
|
+
init({
|
|
92
|
+
custom: {
|
|
93
|
+
asyncStorage: AsyncStorage,
|
|
94
|
+
mmkv: storage,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
66
100
|
### Configuration options
|
|
67
101
|
|
|
68
102
|
```js
|
|
@@ -79,6 +113,15 @@ init({
|
|
|
79
113
|
queryClient: queryClient,
|
|
80
114
|
userStore: useUserStore,
|
|
81
115
|
},
|
|
116
|
+
|
|
117
|
+
// Navigation reference
|
|
118
|
+
navigation: navigationRef,
|
|
119
|
+
|
|
120
|
+
// Any additional references for AI access
|
|
121
|
+
custom: {
|
|
122
|
+
asyncStorage: AsyncStorage,
|
|
123
|
+
mmkv: storage,
|
|
124
|
+
},
|
|
82
125
|
});
|
|
83
126
|
```
|
|
84
127
|
|
|
@@ -161,13 +204,20 @@ globalThis.__RN_AI_DEVTOOLS__ = {
|
|
|
161
204
|
capabilities: {
|
|
162
205
|
network: true,
|
|
163
206
|
console: true,
|
|
164
|
-
stores: true,
|
|
165
|
-
|
|
207
|
+
stores: true, // true if stores were passed
|
|
208
|
+
navigation: true, // true if navigation was passed
|
|
209
|
+
render: false, // future: render profiling
|
|
166
210
|
},
|
|
167
211
|
|
|
168
212
|
// State store references
|
|
169
213
|
stores: { redux: store, queryClient: qc, ... },
|
|
170
214
|
|
|
215
|
+
// Navigation reference
|
|
216
|
+
navigation: navigationRef,
|
|
217
|
+
|
|
218
|
+
// Custom references (AsyncStorage, MMKV, etc.)
|
|
219
|
+
custom: { asyncStorage: AsyncStorage, mmkv: storage, ... },
|
|
220
|
+
|
|
171
221
|
// Network
|
|
172
222
|
getNetworkRequests(options?), // { count, method, urlPattern, status }
|
|
173
223
|
getNetworkRequest(id), // full details including bodies
|
package/dist/consoleBuffer.d.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { ConsoleEntry
|
|
1
|
+
import { ConsoleEntry } from './types';
|
|
2
2
|
export declare class ConsoleBuffer {
|
|
3
3
|
private entries;
|
|
4
4
|
private maxSize;
|
|
5
5
|
constructor(maxSize?: number);
|
|
6
6
|
add(entry: ConsoleEntry): void;
|
|
7
|
-
|
|
8
|
-
getStats(): {
|
|
9
|
-
total: number;
|
|
10
|
-
byLevel: Record<string, number>;
|
|
11
|
-
};
|
|
7
|
+
getAll(): ConsoleEntry[];
|
|
12
8
|
clear(): number;
|
|
13
9
|
}
|
package/dist/consoleBuffer.js
CHANGED
|
@@ -12,26 +12,8 @@ class ConsoleBuffer {
|
|
|
12
12
|
}
|
|
13
13
|
this.entries.push(entry);
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (options?.level) {
|
|
18
|
-
results = results.filter((e) => e.level === options.level);
|
|
19
|
-
}
|
|
20
|
-
if (options?.text) {
|
|
21
|
-
const text = options.text.toLowerCase();
|
|
22
|
-
results = results.filter((e) => e.message.toLowerCase().includes(text));
|
|
23
|
-
}
|
|
24
|
-
if (options?.count != null && options.count > 0) {
|
|
25
|
-
results = results.slice(0, options.count);
|
|
26
|
-
}
|
|
27
|
-
return results;
|
|
28
|
-
}
|
|
29
|
-
getStats() {
|
|
30
|
-
const byLevel = {};
|
|
31
|
-
for (const entry of this.entries) {
|
|
32
|
-
byLevel[entry.level] = (byLevel[entry.level] || 0) + 1;
|
|
33
|
-
}
|
|
34
|
-
return { total: this.entries.length, byLevel };
|
|
15
|
+
getAll() {
|
|
16
|
+
return [...this.entries];
|
|
35
17
|
}
|
|
36
18
|
clear() {
|
|
37
19
|
const count = this.entries.length;
|
package/dist/global.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface ExposeGlobalOptions {
|
|
|
8
8
|
networkBuffer: NetworkBuffer;
|
|
9
9
|
consoleBuffer: ConsoleBuffer;
|
|
10
10
|
stores: Record<string, unknown>;
|
|
11
|
+
navigation: unknown;
|
|
12
|
+
custom: Record<string, unknown>;
|
|
11
13
|
capabilities: Capabilities;
|
|
12
14
|
}
|
|
13
15
|
export declare function exposeGlobal(options: ExposeGlobalOptions): void;
|
package/dist/global.js
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.exposeGlobal = exposeGlobal;
|
|
4
4
|
function exposeGlobal(options) {
|
|
5
|
-
const { networkBuffer, consoleBuffer, stores, capabilities } = options;
|
|
5
|
+
const { networkBuffer, consoleBuffer, stores, navigation, custom, capabilities } = options;
|
|
6
6
|
const devtools = {
|
|
7
|
-
version: '0.
|
|
7
|
+
version: '0.3.0',
|
|
8
8
|
capabilities,
|
|
9
9
|
stores,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
navigation,
|
|
11
|
+
custom,
|
|
12
|
+
getNetworkEntries: () => networkBuffer.getAll(),
|
|
13
|
+
getConsoleEntries: () => consoleBuffer.getAll(),
|
|
13
14
|
clearNetwork: () => networkBuffer.clear(),
|
|
14
|
-
getConsoleLogs: (opts) => consoleBuffer.query(opts),
|
|
15
15
|
clearConsole: () => consoleBuffer.clear(),
|
|
16
16
|
};
|
|
17
17
|
globalThis.__RN_AI_DEVTOOLS__ = devtools;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { InitOptions } from './types';
|
|
2
|
-
export type { InitOptions, NetworkEntry,
|
|
2
|
+
export type { InitOptions, NetworkEntry, ConsoleEntry, Capabilities, DevToolsGlobal, } from './types';
|
|
3
3
|
export declare function init(options?: InitOptions): void;
|
|
4
4
|
export declare function _resetForTesting(): void;
|
package/dist/index.js
CHANGED
|
@@ -19,16 +19,21 @@ function init(options) {
|
|
|
19
19
|
const networkBuffer = new networkBuffer_1.NetworkBuffer(options?.maxNetworkEntries ?? 500);
|
|
20
20
|
const consoleBuffer = new consoleBuffer_1.ConsoleBuffer(options?.maxConsoleEntries ?? 500);
|
|
21
21
|
const stores = options?.stores ?? {};
|
|
22
|
+
const navigation = options?.navigation ?? null;
|
|
23
|
+
const custom = options?.custom ?? {};
|
|
22
24
|
(0, networkInterceptor_1.patchFetch)(networkBuffer);
|
|
23
25
|
(0, consoleInterceptor_1.patchConsole)(consoleBuffer);
|
|
24
26
|
(0, global_1.exposeGlobal)({
|
|
25
27
|
networkBuffer,
|
|
26
28
|
consoleBuffer,
|
|
27
29
|
stores,
|
|
30
|
+
navigation,
|
|
31
|
+
custom,
|
|
28
32
|
capabilities: {
|
|
29
33
|
network: true,
|
|
30
34
|
console: true,
|
|
31
35
|
stores: Object.keys(stores).length > 0,
|
|
36
|
+
navigation: navigation != null,
|
|
32
37
|
render: false,
|
|
33
38
|
},
|
|
34
39
|
});
|
package/dist/networkBuffer.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NetworkEntry
|
|
1
|
+
import { NetworkEntry } from './types';
|
|
2
2
|
export declare class NetworkBuffer {
|
|
3
3
|
private entries;
|
|
4
4
|
private order;
|
|
@@ -7,7 +7,6 @@ export declare class NetworkBuffer {
|
|
|
7
7
|
add(entry: NetworkEntry): void;
|
|
8
8
|
update(id: string, updates: Partial<NetworkEntry>): void;
|
|
9
9
|
get(id: string): NetworkEntry | null;
|
|
10
|
-
|
|
11
|
-
getStats(): NetworkStats;
|
|
10
|
+
getAll(): NetworkEntry[];
|
|
12
11
|
clear(): number;
|
|
13
12
|
}
|
package/dist/networkBuffer.js
CHANGED
|
@@ -27,66 +27,8 @@ class NetworkBuffer {
|
|
|
27
27
|
get(id) {
|
|
28
28
|
return this.entries.get(id) ?? null;
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
.map((id) => this.entries.get(id))
|
|
33
|
-
.reverse();
|
|
34
|
-
if (options?.method) {
|
|
35
|
-
const method = options.method.toUpperCase();
|
|
36
|
-
results = results.filter((e) => e.method === method);
|
|
37
|
-
}
|
|
38
|
-
if (options?.urlPattern) {
|
|
39
|
-
const pattern = options.urlPattern.toLowerCase();
|
|
40
|
-
results = results.filter((e) => e.url.toLowerCase().includes(pattern));
|
|
41
|
-
}
|
|
42
|
-
if (options?.status != null) {
|
|
43
|
-
results = results.filter((e) => e.status === options.status);
|
|
44
|
-
}
|
|
45
|
-
if (options?.count != null && options.count > 0) {
|
|
46
|
-
results = results.slice(0, options.count);
|
|
47
|
-
}
|
|
48
|
-
return results;
|
|
49
|
-
}
|
|
50
|
-
getStats() {
|
|
51
|
-
const all = Array.from(this.entries.values());
|
|
52
|
-
const completed = all.filter((e) => e.completed && !e.error);
|
|
53
|
-
const errors = all.filter((e) => !!e.error);
|
|
54
|
-
const durations = completed
|
|
55
|
-
.map((e) => e.duration)
|
|
56
|
-
.filter((d) => d != null);
|
|
57
|
-
const avgDuration = durations.length > 0
|
|
58
|
-
? durations.reduce((sum, d) => sum + d, 0) / durations.length
|
|
59
|
-
: null;
|
|
60
|
-
const byMethod = {};
|
|
61
|
-
for (const entry of all) {
|
|
62
|
-
byMethod[entry.method] = (byMethod[entry.method] || 0) + 1;
|
|
63
|
-
}
|
|
64
|
-
const byStatus = {};
|
|
65
|
-
for (const entry of all) {
|
|
66
|
-
if (entry.status != null) {
|
|
67
|
-
const group = `${Math.floor(entry.status / 100)}xx`;
|
|
68
|
-
byStatus[group] = (byStatus[group] || 0) + 1;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
const byDomain = {};
|
|
72
|
-
for (const entry of all) {
|
|
73
|
-
try {
|
|
74
|
-
const domain = new URL(entry.url).hostname;
|
|
75
|
-
byDomain[domain] = (byDomain[domain] || 0) + 1;
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
// skip malformed URLs
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return {
|
|
82
|
-
total: all.length,
|
|
83
|
-
completed: completed.length,
|
|
84
|
-
errors: errors.length,
|
|
85
|
-
avgDuration,
|
|
86
|
-
byMethod,
|
|
87
|
-
byStatus,
|
|
88
|
-
byDomain,
|
|
89
|
-
};
|
|
30
|
+
getAll() {
|
|
31
|
+
return this.order.map((id) => this.entries.get(id));
|
|
90
32
|
}
|
|
91
33
|
clear() {
|
|
92
34
|
const count = this.entries.size;
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ export interface InitOptions {
|
|
|
2
2
|
maxNetworkEntries?: number;
|
|
3
3
|
maxConsoleEntries?: number;
|
|
4
4
|
stores?: Record<string, unknown>;
|
|
5
|
+
navigation?: unknown;
|
|
6
|
+
/** Named references to any additional tools, services, or objects (e.g. AsyncStorage, MMKV, analytics) that don't belong to stores or navigation. */
|
|
7
|
+
custom?: Record<string, unknown>;
|
|
5
8
|
}
|
|
6
9
|
export interface NetworkEntry {
|
|
7
10
|
id: string;
|
|
@@ -19,46 +22,27 @@ export interface NetworkEntry {
|
|
|
19
22
|
error?: string;
|
|
20
23
|
completed: boolean;
|
|
21
24
|
}
|
|
22
|
-
export interface NetworkQueryOptions {
|
|
23
|
-
count?: number;
|
|
24
|
-
method?: string;
|
|
25
|
-
urlPattern?: string;
|
|
26
|
-
status?: number;
|
|
27
|
-
}
|
|
28
|
-
export interface NetworkStats {
|
|
29
|
-
total: number;
|
|
30
|
-
completed: number;
|
|
31
|
-
errors: number;
|
|
32
|
-
avgDuration: number | null;
|
|
33
|
-
byMethod: Record<string, number>;
|
|
34
|
-
byStatus: Record<string, number>;
|
|
35
|
-
byDomain: Record<string, number>;
|
|
36
|
-
}
|
|
37
25
|
export interface ConsoleEntry {
|
|
38
26
|
id: string;
|
|
39
27
|
timestamp: number;
|
|
40
28
|
level: 'log' | 'warn' | 'error' | 'info' | 'debug';
|
|
41
29
|
message: string;
|
|
42
30
|
}
|
|
43
|
-
export interface ConsoleQueryOptions {
|
|
44
|
-
count?: number;
|
|
45
|
-
level?: 'log' | 'warn' | 'error' | 'info' | 'debug';
|
|
46
|
-
text?: string;
|
|
47
|
-
}
|
|
48
31
|
export interface Capabilities {
|
|
49
32
|
network: boolean;
|
|
50
33
|
console: boolean;
|
|
51
34
|
stores: boolean;
|
|
35
|
+
navigation: boolean;
|
|
52
36
|
render: boolean;
|
|
53
37
|
}
|
|
54
38
|
export interface DevToolsGlobal {
|
|
55
39
|
version: string;
|
|
56
40
|
capabilities: Capabilities;
|
|
57
41
|
stores: Record<string, unknown>;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
42
|
+
navigation: unknown;
|
|
43
|
+
custom: Record<string, unknown>;
|
|
44
|
+
getNetworkEntries: () => NetworkEntry[];
|
|
45
|
+
getConsoleEntries: () => ConsoleEntry[];
|
|
61
46
|
clearNetwork: () => number;
|
|
62
|
-
getConsoleLogs: (options?: ConsoleQueryOptions) => ConsoleEntry[];
|
|
63
47
|
clearConsole: () => number;
|
|
64
48
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-ai-devtools-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Lightweight SDK for react-native-ai-devtools — captures network requests for AI-powered debugging",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,7 +9,13 @@
|
|
|
9
9
|
"test": "jest --config jest.config.js",
|
|
10
10
|
"prepublishOnly": "npm run build"
|
|
11
11
|
},
|
|
12
|
-
"keywords": [
|
|
12
|
+
"keywords": [
|
|
13
|
+
"react-native",
|
|
14
|
+
"debugging",
|
|
15
|
+
"ai",
|
|
16
|
+
"network",
|
|
17
|
+
"mcp"
|
|
18
|
+
],
|
|
13
19
|
"author": "Ihor Zheludkov",
|
|
14
20
|
"license": "MIT",
|
|
15
21
|
"devDependencies": {
|
|
@@ -18,5 +24,9 @@
|
|
|
18
24
|
"ts-jest": "^29.0.0",
|
|
19
25
|
"typescript": "^5.0.0"
|
|
20
26
|
},
|
|
21
|
-
"files": [
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
]
|
|
22
32
|
}
|