@hakam-aldeen-kh/blix 0.3.2
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 +21 -0
- package/README.md +720 -0
- package/dist/DevToolsPanel-GBMCZRMW.js +5895 -0
- package/dist/capture/index.d.ts +548 -0
- package/dist/capture/index.js +18 -0
- package/dist/chunk-MRTSIXR7.js +1076 -0
- package/dist/chunk-OQHKPRNI.js +287 -0
- package/dist/chunk-PQIOIMAQ.js +7 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +40 -0
- package/package.json +106 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MONITOR_ENABLED,
|
|
3
|
+
PERSIST_MAX_ENTRY_BYTES,
|
|
4
|
+
configureDbName,
|
|
5
|
+
estimateBytes,
|
|
6
|
+
getOwner,
|
|
7
|
+
networkMonitor,
|
|
8
|
+
now,
|
|
9
|
+
serializeBody,
|
|
10
|
+
serializeHeaders,
|
|
11
|
+
truncateForPersist
|
|
12
|
+
} from "./chunk-MRTSIXR7.js";
|
|
13
|
+
|
|
14
|
+
// src/capture/monitorStamp.ts
|
|
15
|
+
var MONITOR_ID = /* @__PURE__ */ Symbol.for("blix.monitorId");
|
|
16
|
+
var stampFallback = /* @__PURE__ */ new WeakMap();
|
|
17
|
+
function stampMonitorId(config, id) {
|
|
18
|
+
try {
|
|
19
|
+
Object.defineProperty(config, MONITOR_ID, {
|
|
20
|
+
value: id,
|
|
21
|
+
enumerable: false,
|
|
22
|
+
writable: true,
|
|
23
|
+
configurable: true
|
|
24
|
+
});
|
|
25
|
+
} catch (e) {
|
|
26
|
+
stampFallback.set(config, id);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function readMonitorId(config) {
|
|
30
|
+
if (config === null || typeof config !== "object") return void 0;
|
|
31
|
+
const stamped = config;
|
|
32
|
+
const direct = stamped[MONITOR_ID];
|
|
33
|
+
if (typeof direct === "string") return direct;
|
|
34
|
+
if (typeof stamped.__monitorId === "string") return stamped.__monitorId;
|
|
35
|
+
return stampFallback.get(config);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/capture/attachHttp.ts
|
|
39
|
+
function attachHttpMonitor(instance, options) {
|
|
40
|
+
if (!MONITOR_ENABLED) return;
|
|
41
|
+
if (options == null ? void 0 : options.dbName) configureDbName(options.dbName);
|
|
42
|
+
instance.interceptors.request.use((config) => {
|
|
43
|
+
var _a, _b;
|
|
44
|
+
if (networkMonitor.isPaused) return config;
|
|
45
|
+
try {
|
|
46
|
+
const id = networkMonitor.nextId();
|
|
47
|
+
const monitored = config;
|
|
48
|
+
monitored.__monitorId = id;
|
|
49
|
+
stampMonitorId(config, id);
|
|
50
|
+
const hadFormData = typeof FormData !== "undefined" && config.data instanceof FormData;
|
|
51
|
+
const requestPayload = serializeBody(config.data);
|
|
52
|
+
const owner = getOwner();
|
|
53
|
+
networkMonitor.start({
|
|
54
|
+
id,
|
|
55
|
+
method: ((_a = config.method) != null ? _a : "post").toUpperCase(),
|
|
56
|
+
url: (_b = config.url) != null ? _b : "",
|
|
57
|
+
baseURL: config.baseURL,
|
|
58
|
+
at: Date.now(),
|
|
59
|
+
startTime: now(),
|
|
60
|
+
requestPayload,
|
|
61
|
+
requestHeaders: serializeHeaders(config.headers),
|
|
62
|
+
sizeBytes: estimateBytes(requestPayload),
|
|
63
|
+
skipEncryption: monitored.skipEncryption === true,
|
|
64
|
+
hadFormData,
|
|
65
|
+
replayOf: monitored.__monitorReplayOf,
|
|
66
|
+
initiator: monitored.__monitorInitiator,
|
|
67
|
+
ownerId: owner == null ? void 0 : owner.id,
|
|
68
|
+
initiatorKind: owner == null ? void 0 : owner.kind
|
|
69
|
+
});
|
|
70
|
+
if (owner) networkMonitor.linkChild(owner.id, id);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
}
|
|
73
|
+
return config;
|
|
74
|
+
});
|
|
75
|
+
instance.interceptors.response.use(
|
|
76
|
+
(response) => {
|
|
77
|
+
const id = response.config.__monitorId;
|
|
78
|
+
if (!id) return response;
|
|
79
|
+
try {
|
|
80
|
+
const payload = response.data;
|
|
81
|
+
networkMonitor.update(id, {
|
|
82
|
+
state: "success",
|
|
83
|
+
status: response.status,
|
|
84
|
+
endTime: now(),
|
|
85
|
+
responsePayload: payload,
|
|
86
|
+
responseHeaders: serializeHeaders(response.headers),
|
|
87
|
+
sizeBytes: estimateBytes(payload)
|
|
88
|
+
});
|
|
89
|
+
} catch (e) {
|
|
90
|
+
}
|
|
91
|
+
return response;
|
|
92
|
+
},
|
|
93
|
+
(error) => {
|
|
94
|
+
var _a, _b, _c, _d, _e;
|
|
95
|
+
const id = (_a = error.config) == null ? void 0 : _a.__monitorId;
|
|
96
|
+
if (id) {
|
|
97
|
+
try {
|
|
98
|
+
const payload = (_c = (_b = error.response) == null ? void 0 : _b.data) != null ? _c : error.message;
|
|
99
|
+
networkMonitor.update(id, {
|
|
100
|
+
state: "error",
|
|
101
|
+
status: (_d = error.response) == null ? void 0 : _d.status,
|
|
102
|
+
endTime: now(),
|
|
103
|
+
error: payload,
|
|
104
|
+
responseHeaders: serializeHeaders((_e = error.response) == null ? void 0 : _e.headers),
|
|
105
|
+
sizeBytes: estimateBytes(payload)
|
|
106
|
+
});
|
|
107
|
+
} catch (e) {
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return Promise.reject(error);
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/capture/captureEncrypted.ts
|
|
116
|
+
var MAX_ENCRYPTED_BYTES = PERSIST_MAX_ENTRY_BYTES;
|
|
117
|
+
var BINARY_PREVIEW_BYTES = 512;
|
|
118
|
+
var HEX = "0123456789abcdef";
|
|
119
|
+
function toBytes(value) {
|
|
120
|
+
if (typeof ArrayBuffer === "undefined") return null;
|
|
121
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
122
|
+
if (ArrayBuffer.isView(value)) {
|
|
123
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
function labelOf(value) {
|
|
128
|
+
var _a;
|
|
129
|
+
const name = (_a = value.constructor) == null ? void 0 : _a.name;
|
|
130
|
+
return typeof name === "string" && name.length > 0 ? name : "BufferSource";
|
|
131
|
+
}
|
|
132
|
+
function binaryPreview(bytes, label) {
|
|
133
|
+
const limit = Math.min(bytes.length, BINARY_PREVIEW_BYTES);
|
|
134
|
+
let head = "";
|
|
135
|
+
for (let i = 0; i < limit; i += 1) {
|
|
136
|
+
const byte = bytes[i];
|
|
137
|
+
head += HEX[byte >> 4] + HEX[byte & 15];
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
__blixBinary: label,
|
|
141
|
+
byteLength: bytes.length,
|
|
142
|
+
head,
|
|
143
|
+
truncated: bytes.length > limit
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function normalize(value) {
|
|
147
|
+
const bytes = toBytes(value);
|
|
148
|
+
if (bytes) return binaryPreview(bytes, labelOf(value));
|
|
149
|
+
return truncateForPersist(serializeBody(value), MAX_ENCRYPTED_BYTES).value;
|
|
150
|
+
}
|
|
151
|
+
function captureEncrypted(config, payload) {
|
|
152
|
+
if (!MONITOR_ENABLED) return;
|
|
153
|
+
try {
|
|
154
|
+
const id = readMonitorId(config);
|
|
155
|
+
if (!id) return;
|
|
156
|
+
if (!payload) return;
|
|
157
|
+
const patch = {};
|
|
158
|
+
if (payload.request != null) patch.encryptedRequest = normalize(payload.request);
|
|
159
|
+
if (payload.response != null) patch.encryptedResponse = normalize(payload.response);
|
|
160
|
+
if (patch.encryptedRequest === void 0 && patch.encryptedResponse === void 0) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
networkMonitor.update(id, patch);
|
|
164
|
+
} catch (e) {
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/capture/realtimeCapture.ts
|
|
169
|
+
var frameCounter = 0;
|
|
170
|
+
function makeFrame(direction, event, data) {
|
|
171
|
+
frameCounter += 1;
|
|
172
|
+
return {
|
|
173
|
+
id: `f${frameCounter}`,
|
|
174
|
+
at: Date.now(),
|
|
175
|
+
direction,
|
|
176
|
+
event,
|
|
177
|
+
data,
|
|
178
|
+
sizeBytes: estimateBytes(data)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function tapRealtimeAdapter(adapter, transport) {
|
|
182
|
+
if (!MONITOR_ENABLED) return adapter;
|
|
183
|
+
let connectionId = null;
|
|
184
|
+
const frame = (direction, event, data) => {
|
|
185
|
+
if (!connectionId) return;
|
|
186
|
+
try {
|
|
187
|
+
networkMonitor.appendFrame(connectionId, makeFrame(direction, event, data));
|
|
188
|
+
} catch (e) {
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
const openConnection = (url) => {
|
|
192
|
+
try {
|
|
193
|
+
const id = networkMonitor.nextId();
|
|
194
|
+
connectionId = id;
|
|
195
|
+
const startTime = now();
|
|
196
|
+
networkMonitor.start({
|
|
197
|
+
id,
|
|
198
|
+
kind: "ws",
|
|
199
|
+
transport,
|
|
200
|
+
method: "WS",
|
|
201
|
+
// Strip the token from the query string — it is a credential, and the
|
|
202
|
+
// panel already masks the equivalent HTTP header.
|
|
203
|
+
url: redactUrl(url),
|
|
204
|
+
at: Date.now(),
|
|
205
|
+
startTime,
|
|
206
|
+
// A connection has no response body; size accrues from its frames.
|
|
207
|
+
sizeBytes: 0,
|
|
208
|
+
frames: []
|
|
209
|
+
});
|
|
210
|
+
return id;
|
|
211
|
+
} catch (e) {
|
|
212
|
+
connectionId = null;
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const closeConnection = (state, reason) => {
|
|
217
|
+
if (!connectionId) return;
|
|
218
|
+
try {
|
|
219
|
+
networkMonitor.update(connectionId, {
|
|
220
|
+
state,
|
|
221
|
+
endTime: now(),
|
|
222
|
+
responsePayload: { closed: reason != null ? reason : "disconnected" }
|
|
223
|
+
});
|
|
224
|
+
} catch (e) {
|
|
225
|
+
}
|
|
226
|
+
connectionId = null;
|
|
227
|
+
};
|
|
228
|
+
return new Proxy(adapter, {
|
|
229
|
+
get(target, prop, receiver) {
|
|
230
|
+
const value = Reflect.get(target, prop, receiver);
|
|
231
|
+
if (typeof value !== "function") return value;
|
|
232
|
+
if (prop === "connect") {
|
|
233
|
+
return (token, url) => {
|
|
234
|
+
openConnection(url);
|
|
235
|
+
frame("system", "connect", { url: redactUrl(url), transport });
|
|
236
|
+
return value.call(target, token, url);
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (prop === "disconnect") {
|
|
240
|
+
return () => {
|
|
241
|
+
frame("system", "disconnect", null);
|
|
242
|
+
const result = value.call(target);
|
|
243
|
+
closeConnection("success", "client disconnect");
|
|
244
|
+
return result;
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (prop === "subscribe") {
|
|
248
|
+
return (channelName) => {
|
|
249
|
+
frame("out", `subscribe:${channelName}`, { channel: channelName });
|
|
250
|
+
return value.call(target, channelName);
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
if (prop === "onMessage") {
|
|
254
|
+
return (cb) => value.call(target, (payload) => {
|
|
255
|
+
var _a;
|
|
256
|
+
frame("in", (_a = payload == null ? void 0 : payload.event) != null ? _a : "message", payload == null ? void 0 : payload.data);
|
|
257
|
+
cb(payload);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
if (prop === "onPresenceUpdate") {
|
|
261
|
+
return (cb) => value.call(target, (status) => {
|
|
262
|
+
frame("system", `presence:${status}`, { status });
|
|
263
|
+
if (status === "offline") closeConnection("error", "transport offline");
|
|
264
|
+
cb(status);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
return value.bind(target);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
function redactUrl(url) {
|
|
272
|
+
try {
|
|
273
|
+
const parsed = new URL(url, "http://local");
|
|
274
|
+
for (const key of ["token", "access_token", "accessToken", "auth"]) {
|
|
275
|
+
if (parsed.searchParams.has(key)) parsed.searchParams.set(key, "\u2022\u2022\u2022");
|
|
276
|
+
}
|
|
277
|
+
return url.startsWith("/") ? parsed.pathname + parsed.search : parsed.toString();
|
|
278
|
+
} catch (e) {
|
|
279
|
+
return url.replace(/([?&](?:token|access_token|accessToken|auth)=)[^&]*/gi, "$1\u2022\u2022\u2022");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export {
|
|
284
|
+
attachHttpMonitor,
|
|
285
|
+
captureEncrypted,
|
|
286
|
+
tapRealtimeAdapter
|
|
287
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export { CacheLike, Corner, DiffOp, DockMode, EncryptedPayload, FrameDirection, InitiatorFrame, MiddlewareApiLike, MiddlewareLike, MonitorEntry, MonitorKind, MonitorPrefs, MonitorState, PersistedEntry, Pos, QueryClientLike, QueryMeta, RealtimeAdapterLike, ReduxActionMeta, ReduxCaptureOptions, Size, StateDiff, StateDiffEntry, TimingMarks, WsFrame, attachHttpMonitor, captureEncrypted, createReduxMonitorMiddleware, tapQueryClient, tapRealtimeAdapter, withInitiatorCapture } from './capture/index.js';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import 'axios';
|
|
4
|
+
|
|
5
|
+
/** Structural redux-store shape — only the subset the panel actually uses.
|
|
6
|
+
* Mirrors `MiddlewareApiLike` in `reduxCapture.ts` but adds `subscribe` and
|
|
7
|
+
* `dispatch` so the State tab and Re-dispatch action can work. */
|
|
8
|
+
interface StoreLike<S> {
|
|
9
|
+
getState(): S;
|
|
10
|
+
subscribe(listener: () => void): () => void;
|
|
11
|
+
dispatch(action: unknown): unknown;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The config Blix hands to `request()` when replaying an entry — exactly the
|
|
15
|
+
* eight fields `replayEntry` sets (`services/replayRequest.ts`), nothing more.
|
|
16
|
+
*
|
|
17
|
+
* Two deliberate choices here, both forced by making a genuine `AxiosInstance`
|
|
18
|
+
* assignable to `HttpClientLike` without a cast:
|
|
19
|
+
*
|
|
20
|
+
* 1. **`headers` is `unknown`, not `Record<string, unknown>`.** Axios types
|
|
21
|
+
* headers as `AxiosHeaders | (Partial<RawAxiosHeaders & …> & …)`, which a
|
|
22
|
+
* `Record<string, unknown>` is not assignable to. Since Blix only ever
|
|
23
|
+
* *writes* this field (a flat `Record<string, string>` built from the
|
|
24
|
+
* captured request), nothing here needs to read it back, so the widest type
|
|
25
|
+
* that still accepts what Blix passes is the correct one.
|
|
26
|
+
*
|
|
27
|
+
* 2. **No `[key: string]: unknown` index signature.** Method parameters are
|
|
28
|
+
* compared bivariantly, so it is enough for `AxiosRequestConfig` to be
|
|
29
|
+
* assignable to *this* type — but an interface never satisfies a target
|
|
30
|
+
* index signature (TypeScript only infers implicit index signatures for
|
|
31
|
+
* object-literal types), so the index signature was what actually blocked
|
|
32
|
+
* that direction. The three non-axios fields Blix passes are therefore
|
|
33
|
+
* named explicitly instead of being swept up by the index signature.
|
|
34
|
+
*
|
|
35
|
+
* Declared as a `type` alias rather than an `interface` on purpose: an
|
|
36
|
+
* object-literal type gets an implicit index signature, so this stays
|
|
37
|
+
* assignable to a client whose own parameter is declared as
|
|
38
|
+
* `Record<string, unknown>` — a shape that was valid in 0.2.1 and must remain
|
|
39
|
+
* valid.
|
|
40
|
+
*/
|
|
41
|
+
type HttpClientRequestConfig = {
|
|
42
|
+
url?: string;
|
|
43
|
+
method?: string;
|
|
44
|
+
baseURL?: string;
|
|
45
|
+
/** Written by Blix, never read — see note 1 above. */
|
|
46
|
+
headers?: unknown;
|
|
47
|
+
data?: unknown;
|
|
48
|
+
/** Host convention: opt this request out of the encryption pipeline. */
|
|
49
|
+
skipEncryption?: boolean;
|
|
50
|
+
/** Host convention: mark as already-retried, so auth interceptors don't loop. */
|
|
51
|
+
_retry?: boolean;
|
|
52
|
+
/** Blix internal: id of the entry this replay came from. */
|
|
53
|
+
__monitorReplayOf?: string;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Structural axios-instance shape — `request` is the only member the panel
|
|
57
|
+
* touches (`services/replayRequest.ts:90`), so it is the only one declared.
|
|
58
|
+
*
|
|
59
|
+
* Structural on purpose: Blix does not import from axios here and does not
|
|
60
|
+
* depend on it, so any client exposing a compatible `request` works.
|
|
61
|
+
*/
|
|
62
|
+
interface HttpClientLike {
|
|
63
|
+
request(config: HttpClientRequestConfig): Promise<unknown>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface BlixProps {
|
|
67
|
+
store?: StoreLike<unknown>;
|
|
68
|
+
apiClient?: HttpClientLike;
|
|
69
|
+
/** IndexedDB database name. Defaults to "nm-devtools". Useful when running
|
|
70
|
+
* multiple apps on the same origin that would otherwise share a log. */
|
|
71
|
+
dbName?: string;
|
|
72
|
+
}
|
|
73
|
+
declare function Blix({ store, apiClient, dbName }: BlixProps): react.JSX.Element | null;
|
|
74
|
+
|
|
75
|
+
export { Blix, type BlixProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
attachHttpMonitor,
|
|
4
|
+
captureEncrypted,
|
|
5
|
+
tapRealtimeAdapter
|
|
6
|
+
} from "./chunk-OQHKPRNI.js";
|
|
7
|
+
import {
|
|
8
|
+
BlixContext
|
|
9
|
+
} from "./chunk-PQIOIMAQ.js";
|
|
10
|
+
import {
|
|
11
|
+
configureDbName,
|
|
12
|
+
createReduxMonitorMiddleware,
|
|
13
|
+
tapQueryClient,
|
|
14
|
+
withInitiatorCapture
|
|
15
|
+
} from "./chunk-MRTSIXR7.js";
|
|
16
|
+
|
|
17
|
+
// src/ui/Blix.tsx
|
|
18
|
+
import { lazy, Suspense, useRef } from "react";
|
|
19
|
+
import { jsx } from "react/jsx-runtime";
|
|
20
|
+
function Blix({ store, apiClient, dbName }) {
|
|
21
|
+
const panelRef = useRef(null);
|
|
22
|
+
if (typeof window !== "undefined" && process.env.NODE_ENV === "development") {
|
|
23
|
+
if (!panelRef.current) {
|
|
24
|
+
panelRef.current = lazy(() => import("./DevToolsPanel-GBMCZRMW.js"));
|
|
25
|
+
}
|
|
26
|
+
const Panel = panelRef.current;
|
|
27
|
+
if (dbName) configureDbName(dbName);
|
|
28
|
+
return /* @__PURE__ */ jsx(BlixContext.Provider, { value: { store, apiClient }, children: /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(Panel, {}) }) });
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
Blix,
|
|
34
|
+
attachHttpMonitor,
|
|
35
|
+
captureEncrypted,
|
|
36
|
+
createReduxMonitorMiddleware,
|
|
37
|
+
tapQueryClient,
|
|
38
|
+
tapRealtimeAdapter,
|
|
39
|
+
withInitiatorCapture
|
|
40
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hakam-aldeen-kh/blix",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "Dev-tools panel for React apps — HTTP, Redux, Query and Realtime monitoring.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"devtools",
|
|
7
|
+
"dev-tools",
|
|
8
|
+
"debug",
|
|
9
|
+
"debugging",
|
|
10
|
+
"debug-panel",
|
|
11
|
+
"devtools-panel",
|
|
12
|
+
"inspector",
|
|
13
|
+
"monitoring",
|
|
14
|
+
"observability",
|
|
15
|
+
"logging",
|
|
16
|
+
"network-inspector",
|
|
17
|
+
"http",
|
|
18
|
+
"http-logger",
|
|
19
|
+
"request-logger",
|
|
20
|
+
"api-monitor",
|
|
21
|
+
"axios",
|
|
22
|
+
"axios-interceptor",
|
|
23
|
+
"redux",
|
|
24
|
+
"redux-devtools",
|
|
25
|
+
"redux-toolkit",
|
|
26
|
+
"state-inspector",
|
|
27
|
+
"react-query",
|
|
28
|
+
"tanstack-query",
|
|
29
|
+
"query-devtools",
|
|
30
|
+
"websocket",
|
|
31
|
+
"realtime",
|
|
32
|
+
"socket",
|
|
33
|
+
"react",
|
|
34
|
+
"react-devtools",
|
|
35
|
+
"nextjs",
|
|
36
|
+
"typescript",
|
|
37
|
+
"frontend",
|
|
38
|
+
"dx",
|
|
39
|
+
"in-app-devtools"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"author": "Hakam aldeen Alkhadraa",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/Hakam-aldeen-Kh/blix.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/Hakam-aldeen-Kh/blix/issues"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/Hakam-aldeen-Kh/blix#readme",
|
|
51
|
+
"type": "module",
|
|
52
|
+
"sideEffects": false,
|
|
53
|
+
"types": "./dist/index.d.ts",
|
|
54
|
+
"exports": {
|
|
55
|
+
".": {
|
|
56
|
+
"types": "./dist/index.d.ts",
|
|
57
|
+
"import": "./dist/index.js"
|
|
58
|
+
},
|
|
59
|
+
"./capture": {
|
|
60
|
+
"types": "./dist/capture/index.d.ts",
|
|
61
|
+
"import": "./dist/capture/index.js"
|
|
62
|
+
},
|
|
63
|
+
"./package.json": "./package.json"
|
|
64
|
+
},
|
|
65
|
+
"files": [
|
|
66
|
+
"dist"
|
|
67
|
+
],
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=18"
|
|
70
|
+
},
|
|
71
|
+
"peerDependencies": {
|
|
72
|
+
"react": "^19.0.0",
|
|
73
|
+
"react-dom": "^19.0.0",
|
|
74
|
+
"axios": "^1.0.0",
|
|
75
|
+
"@reduxjs/toolkit": "^2.0.0",
|
|
76
|
+
"@tanstack/react-query": "^5.0.0"
|
|
77
|
+
},
|
|
78
|
+
"peerDependenciesMeta": {
|
|
79
|
+
"axios": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"@reduxjs/toolkit": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"@tanstack/react-query": {
|
|
86
|
+
"optional": true
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@types/node": "^20.0.0",
|
|
91
|
+
"@types/react": "^19.0.0",
|
|
92
|
+
"@types/react-dom": "^19.0.0",
|
|
93
|
+
"react": "^19.0.0",
|
|
94
|
+
"react-dom": "^19.0.0",
|
|
95
|
+
"tsup": "^8.0.0",
|
|
96
|
+
"typescript": "^5.0.0"
|
|
97
|
+
},
|
|
98
|
+
"publishConfig": {
|
|
99
|
+
"registry": "https://registry.npmjs.org",
|
|
100
|
+
"access": "public"
|
|
101
|
+
},
|
|
102
|
+
"scripts": {
|
|
103
|
+
"build": "tsup",
|
|
104
|
+
"typecheck": "tsc --noEmit"
|
|
105
|
+
}
|
|
106
|
+
}
|