tarojs-plugin-chucker 1.0.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.
- package/README.md +155 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +206 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +14 -0
- package/dist/runtime/components/Chucker.d.ts +2 -0
- package/dist/runtime/components/Chucker.js +529 -0
- package/dist/runtime/components/icons.d.ts +13 -0
- package/dist/runtime/components/icons.js +61 -0
- package/dist/runtime/hooks/useVirtual.d.ts +71 -0
- package/dist/runtime/hooks/useVirtual.js +298 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/index.js +64 -0
- package/dist/runtime/interceptor.d.ts +15 -0
- package/dist/runtime/interceptor.js +491 -0
- package/dist/runtime/page.d.ts +2 -0
- package/dist/runtime/page.js +11 -0
- package/dist/runtime/store.d.ts +95 -0
- package/dist/runtime/store.js +172 -0
- package/dist/runtime/utils.d.ts +2 -0
- package/dist/runtime/utils.js +50 -0
- package/package.json +60 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initInterceptors = initInterceptors;
|
|
7
|
+
const taro_1 = __importDefault(require("@tarojs/taro"));
|
|
8
|
+
const store_1 = require("./store");
|
|
9
|
+
const completedIds = new Set();
|
|
10
|
+
function markCompleted(id) {
|
|
11
|
+
if (completedIds.has(id)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
completedIds.add(id);
|
|
15
|
+
// Clean up completed IDs list after 30 seconds to prevent leaks
|
|
16
|
+
setTimeout(() => completedIds.delete(id), 30000);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Chucker interceptor for Taro.addInterceptor.
|
|
21
|
+
* Uses the official onion-model chain to intercept Taro.request calls.
|
|
22
|
+
*/
|
|
23
|
+
const chuckerRequestInterceptor = (chain) => {
|
|
24
|
+
const requestParams = chain.requestParams;
|
|
25
|
+
const { method = "GET", url, header, data } = requestParams;
|
|
26
|
+
const id = "req_" + Math.random().toString(36).substring(2, 9);
|
|
27
|
+
const startTime = Date.now();
|
|
28
|
+
store_1.chuckerStore.handleRequestStart({
|
|
29
|
+
id,
|
|
30
|
+
type: "network",
|
|
31
|
+
method: method.toUpperCase(),
|
|
32
|
+
url,
|
|
33
|
+
requestHeaders: header || {},
|
|
34
|
+
requestData: data,
|
|
35
|
+
startTime,
|
|
36
|
+
});
|
|
37
|
+
return chain.proceed(requestParams).then((res) => {
|
|
38
|
+
if (markCompleted(id)) {
|
|
39
|
+
const duration = Date.now() - startTime;
|
|
40
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
41
|
+
id,
|
|
42
|
+
status: res.statusCode || 200,
|
|
43
|
+
responseHeaders: res.header || {},
|
|
44
|
+
responseData: res.data,
|
|
45
|
+
duration,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return res;
|
|
49
|
+
}, (err) => {
|
|
50
|
+
if (markCompleted(id)) {
|
|
51
|
+
const duration = Date.now() - startTime;
|
|
52
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
53
|
+
id,
|
|
54
|
+
status: "fail",
|
|
55
|
+
error: err ? err.errMsg || JSON.stringify(err) : "Request failed",
|
|
56
|
+
duration,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
throw err;
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
// Helper to proxy custom methods/properties (like abort, progress callbacks)
|
|
63
|
+
// from the original request/upload/download task to the hijacked Promise
|
|
64
|
+
function proxyTask(target, source) {
|
|
65
|
+
if (!source)
|
|
66
|
+
return target;
|
|
67
|
+
const keys = [
|
|
68
|
+
...Object.keys(source),
|
|
69
|
+
...Object.getOwnPropertyNames(Object.getPrototypeOf(source) || {}),
|
|
70
|
+
];
|
|
71
|
+
keys.forEach((key) => {
|
|
72
|
+
if (key === "constructor" || key === "then" || key === "catch" || key === "finally")
|
|
73
|
+
return;
|
|
74
|
+
try {
|
|
75
|
+
if (typeof source[key] === "function") {
|
|
76
|
+
target[key] = source[key].bind(source);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
Object.defineProperty(target, key, {
|
|
80
|
+
get: () => source[key],
|
|
81
|
+
set: (val) => {
|
|
82
|
+
source[key] = val;
|
|
83
|
+
},
|
|
84
|
+
configurable: true,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (e) { }
|
|
89
|
+
});
|
|
90
|
+
return target;
|
|
91
|
+
}
|
|
92
|
+
function initInterceptors() {
|
|
93
|
+
// 1. Intercept Taro.request via Taro.addInterceptor (official API)
|
|
94
|
+
taro_1.default.addInterceptor(chuckerRequestInterceptor);
|
|
95
|
+
// 2. Intercept Taro.uploadFile (addInterceptor doesn't cover uploadFile)
|
|
96
|
+
const originalUploadFile = taro_1.default.uploadFile;
|
|
97
|
+
if (typeof originalUploadFile === "function") {
|
|
98
|
+
taro_1.default.uploadFile = function (options) {
|
|
99
|
+
if (!options)
|
|
100
|
+
return originalUploadFile.apply(this, arguments);
|
|
101
|
+
const id = "upl_" + Math.random().toString(36).substring(2, 9);
|
|
102
|
+
const startTime = Date.now();
|
|
103
|
+
const { url, filePath, name, header, formData } = options;
|
|
104
|
+
store_1.chuckerStore.handleRequestStart({
|
|
105
|
+
id,
|
|
106
|
+
type: "network",
|
|
107
|
+
method: "UPLOAD",
|
|
108
|
+
url,
|
|
109
|
+
requestHeaders: header || {},
|
|
110
|
+
requestData: { filePath, name, formData },
|
|
111
|
+
startTime,
|
|
112
|
+
});
|
|
113
|
+
const clonedOptions = { ...options };
|
|
114
|
+
const originalSuccess = options.success;
|
|
115
|
+
const originalFail = options.fail;
|
|
116
|
+
clonedOptions.success = function (res) {
|
|
117
|
+
if (markCompleted(id)) {
|
|
118
|
+
const duration = Date.now() - startTime;
|
|
119
|
+
let responseData = res.data;
|
|
120
|
+
try {
|
|
121
|
+
if (typeof responseData === "string" && responseData.trim().startsWith("{")) {
|
|
122
|
+
responseData = JSON.parse(responseData);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (e) { }
|
|
126
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
127
|
+
id,
|
|
128
|
+
status: res.statusCode || 200,
|
|
129
|
+
responseHeaders: res.header || res.headers || {},
|
|
130
|
+
responseData,
|
|
131
|
+
duration,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (originalSuccess)
|
|
135
|
+
return originalSuccess.apply(this, arguments);
|
|
136
|
+
};
|
|
137
|
+
clonedOptions.fail = function (err) {
|
|
138
|
+
if (markCompleted(id)) {
|
|
139
|
+
const duration = Date.now() - startTime;
|
|
140
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
141
|
+
id,
|
|
142
|
+
status: "fail",
|
|
143
|
+
error: err ? err.errMsg || JSON.stringify(err) : "Upload failed",
|
|
144
|
+
duration,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (originalFail)
|
|
148
|
+
return originalFail.apply(this, arguments);
|
|
149
|
+
};
|
|
150
|
+
try {
|
|
151
|
+
const args = [clonedOptions, ...Array.prototype.slice.call(arguments, 1)];
|
|
152
|
+
const promise = originalUploadFile.apply(this, args);
|
|
153
|
+
if (promise && typeof promise.then === "function") {
|
|
154
|
+
const hijackedPromise = promise.then((res) => {
|
|
155
|
+
if (markCompleted(id)) {
|
|
156
|
+
const duration = Date.now() - startTime;
|
|
157
|
+
let responseData = res.data;
|
|
158
|
+
try {
|
|
159
|
+
if (typeof responseData === "string" && responseData.trim().startsWith("{")) {
|
|
160
|
+
responseData = JSON.parse(responseData);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (e) { }
|
|
164
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
165
|
+
id,
|
|
166
|
+
status: res.statusCode || 200,
|
|
167
|
+
responseHeaders: res.header || res.headers || {},
|
|
168
|
+
responseData,
|
|
169
|
+
duration,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return res;
|
|
173
|
+
}, (err) => {
|
|
174
|
+
if (markCompleted(id)) {
|
|
175
|
+
const duration = Date.now() - startTime;
|
|
176
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
177
|
+
id,
|
|
178
|
+
status: "fail",
|
|
179
|
+
error: err ? err.errMsg || JSON.stringify(err) : "Upload failed",
|
|
180
|
+
duration,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
throw err;
|
|
184
|
+
});
|
|
185
|
+
return proxyTask(hijackedPromise, promise);
|
|
186
|
+
}
|
|
187
|
+
return promise;
|
|
188
|
+
}
|
|
189
|
+
catch (e) {
|
|
190
|
+
if (markCompleted(id)) {
|
|
191
|
+
const duration = Date.now() - startTime;
|
|
192
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
193
|
+
id,
|
|
194
|
+
status: "fail",
|
|
195
|
+
error: e ? e.message || String(e) : "Upload error",
|
|
196
|
+
duration,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
throw e;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// 3. Intercept Taro.downloadFile (addInterceptor doesn't cover downloadFile)
|
|
204
|
+
const originalDownloadFile = taro_1.default.downloadFile;
|
|
205
|
+
if (typeof originalDownloadFile === "function") {
|
|
206
|
+
taro_1.default.downloadFile = function (options) {
|
|
207
|
+
if (!options)
|
|
208
|
+
return originalDownloadFile.apply(this, arguments);
|
|
209
|
+
const id = "dwl_" + Math.random().toString(36).substring(2, 9);
|
|
210
|
+
const startTime = Date.now();
|
|
211
|
+
const { url, header } = options;
|
|
212
|
+
store_1.chuckerStore.handleRequestStart({
|
|
213
|
+
id,
|
|
214
|
+
type: "network",
|
|
215
|
+
method: "DOWNLOAD",
|
|
216
|
+
url,
|
|
217
|
+
requestHeaders: header || {},
|
|
218
|
+
startTime,
|
|
219
|
+
});
|
|
220
|
+
const clonedOptions = { ...options };
|
|
221
|
+
const originalSuccess = options.success;
|
|
222
|
+
const originalFail = options.fail;
|
|
223
|
+
clonedOptions.success = function (res) {
|
|
224
|
+
if (markCompleted(id)) {
|
|
225
|
+
const duration = Date.now() - startTime;
|
|
226
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
227
|
+
id,
|
|
228
|
+
status: res.statusCode || 200,
|
|
229
|
+
responseHeaders: res.header || res.headers || {},
|
|
230
|
+
responseData: { tempFilePath: res.tempFilePath, apFilePath: res.apFilePath },
|
|
231
|
+
duration,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
if (originalSuccess)
|
|
235
|
+
return originalSuccess.apply(this, arguments);
|
|
236
|
+
};
|
|
237
|
+
clonedOptions.fail = function (err) {
|
|
238
|
+
if (markCompleted(id)) {
|
|
239
|
+
const duration = Date.now() - startTime;
|
|
240
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
241
|
+
id,
|
|
242
|
+
status: "fail",
|
|
243
|
+
error: err ? err.errMsg || JSON.stringify(err) : "Download failed",
|
|
244
|
+
duration,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (originalFail)
|
|
248
|
+
return originalFail.apply(this, arguments);
|
|
249
|
+
};
|
|
250
|
+
try {
|
|
251
|
+
const args = [clonedOptions, ...Array.prototype.slice.call(arguments, 1)];
|
|
252
|
+
const promise = originalDownloadFile.apply(this, args);
|
|
253
|
+
if (promise && typeof promise.then === "function") {
|
|
254
|
+
const hijackedPromise = promise.then((res) => {
|
|
255
|
+
if (markCompleted(id)) {
|
|
256
|
+
const duration = Date.now() - startTime;
|
|
257
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
258
|
+
id,
|
|
259
|
+
status: res.statusCode || 200,
|
|
260
|
+
responseHeaders: res.header || res.headers || {},
|
|
261
|
+
responseData: { tempFilePath: res.tempFilePath, apFilePath: res.apFilePath },
|
|
262
|
+
duration,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return res;
|
|
266
|
+
}, (err) => {
|
|
267
|
+
if (markCompleted(id)) {
|
|
268
|
+
const duration = Date.now() - startTime;
|
|
269
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
270
|
+
id,
|
|
271
|
+
status: "fail",
|
|
272
|
+
error: err ? err.errMsg || JSON.stringify(err) : "Download failed",
|
|
273
|
+
duration,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
throw err;
|
|
277
|
+
});
|
|
278
|
+
return proxyTask(hijackedPromise, promise);
|
|
279
|
+
}
|
|
280
|
+
return promise;
|
|
281
|
+
}
|
|
282
|
+
catch (e) {
|
|
283
|
+
if (markCompleted(id)) {
|
|
284
|
+
const duration = Date.now() - startTime;
|
|
285
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
286
|
+
id,
|
|
287
|
+
status: "fail",
|
|
288
|
+
error: e ? e.message || String(e) : "Download error",
|
|
289
|
+
duration,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
throw e;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
// 4. Intercept wx.invokeNativePlugin (not part of Taro's interceptor chain)
|
|
297
|
+
// @ts-ignore
|
|
298
|
+
const globalObj = typeof wx !== "undefined" ? wx : typeof my !== "undefined" ? my : null;
|
|
299
|
+
if (globalObj) {
|
|
300
|
+
const setupNativeInterceptor = (original) => {
|
|
301
|
+
if (typeof original !== "function" || original.isChuckerOverridden)
|
|
302
|
+
return original;
|
|
303
|
+
const fn = function (name, args, ...rest) {
|
|
304
|
+
const id = "nat_" + Math.random().toString(36).substring(2, 9);
|
|
305
|
+
const startTime = Date.now();
|
|
306
|
+
let actualName = "NATIVE_CALL";
|
|
307
|
+
let actualArgs = args;
|
|
308
|
+
let finalArgs = args;
|
|
309
|
+
if (typeof name === "string") {
|
|
310
|
+
actualName = name;
|
|
311
|
+
if (args && typeof args === "object") {
|
|
312
|
+
finalArgs = { ...args };
|
|
313
|
+
const originalSuccess = args.success;
|
|
314
|
+
const originalFail = args.fail;
|
|
315
|
+
finalArgs.success = function (res) {
|
|
316
|
+
if (markCompleted(id)) {
|
|
317
|
+
const duration = Date.now() - startTime;
|
|
318
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
319
|
+
id,
|
|
320
|
+
status: "success",
|
|
321
|
+
responseData: res,
|
|
322
|
+
duration,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (originalSuccess)
|
|
326
|
+
return originalSuccess.apply(this, arguments);
|
|
327
|
+
};
|
|
328
|
+
finalArgs.fail = function (err) {
|
|
329
|
+
if (markCompleted(id)) {
|
|
330
|
+
const duration = Date.now() - startTime;
|
|
331
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
332
|
+
id,
|
|
333
|
+
status: "fail",
|
|
334
|
+
error: err
|
|
335
|
+
? typeof err === "object"
|
|
336
|
+
? JSON.stringify(err)
|
|
337
|
+
: String(err)
|
|
338
|
+
: "Native call failed",
|
|
339
|
+
duration,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
if (originalFail)
|
|
343
|
+
return originalFail.apply(this, arguments);
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else if (name && typeof name === "object") {
|
|
348
|
+
actualName = name.api_name || "NATIVE_CALL";
|
|
349
|
+
actualArgs = name.data || name;
|
|
350
|
+
const clonedObj = { ...name };
|
|
351
|
+
const originalSuccess = name.success;
|
|
352
|
+
const originalFail = name.fail;
|
|
353
|
+
clonedObj.success = function (res) {
|
|
354
|
+
if (markCompleted(id)) {
|
|
355
|
+
const duration = Date.now() - startTime;
|
|
356
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
357
|
+
id,
|
|
358
|
+
status: "success",
|
|
359
|
+
responseData: res,
|
|
360
|
+
duration,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (originalSuccess)
|
|
364
|
+
return originalSuccess.apply(this, arguments);
|
|
365
|
+
};
|
|
366
|
+
clonedObj.fail = function (err) {
|
|
367
|
+
if (markCompleted(id)) {
|
|
368
|
+
const duration = Date.now() - startTime;
|
|
369
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
370
|
+
id,
|
|
371
|
+
status: "fail",
|
|
372
|
+
error: err
|
|
373
|
+
? typeof err === "object"
|
|
374
|
+
? JSON.stringify(err)
|
|
375
|
+
: String(err)
|
|
376
|
+
: "Native call failed",
|
|
377
|
+
duration,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
if (originalFail)
|
|
381
|
+
return originalFail.apply(this, arguments);
|
|
382
|
+
};
|
|
383
|
+
name = clonedObj;
|
|
384
|
+
}
|
|
385
|
+
store_1.chuckerStore.handleRequestStart({
|
|
386
|
+
id,
|
|
387
|
+
type: "native",
|
|
388
|
+
method: "NATIVE",
|
|
389
|
+
url: actualName,
|
|
390
|
+
requestData: actualArgs,
|
|
391
|
+
startTime,
|
|
392
|
+
});
|
|
393
|
+
// Hook callback function if passed directly as argument
|
|
394
|
+
const lastArg = rest[rest.length - 1];
|
|
395
|
+
if (typeof lastArg === "function") {
|
|
396
|
+
rest[rest.length - 1] = function (res) {
|
|
397
|
+
if (markCompleted(id)) {
|
|
398
|
+
const duration = Date.now() - startTime;
|
|
399
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
400
|
+
id,
|
|
401
|
+
status: res && (res.errCode === 0 || res.errorCode === 0 || !res.errCode)
|
|
402
|
+
? "success"
|
|
403
|
+
: "fail",
|
|
404
|
+
responseData: res,
|
|
405
|
+
duration,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
return lastArg.apply(this, arguments);
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
try {
|
|
412
|
+
const result = original.apply(this, [name, finalArgs, ...rest]);
|
|
413
|
+
if (result && typeof result.then === "function") {
|
|
414
|
+
return result.then((res) => {
|
|
415
|
+
if (markCompleted(id)) {
|
|
416
|
+
const duration = Date.now() - startTime;
|
|
417
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
418
|
+
id,
|
|
419
|
+
status: "success",
|
|
420
|
+
responseData: res,
|
|
421
|
+
duration,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return res;
|
|
425
|
+
}, (err) => {
|
|
426
|
+
if (markCompleted(id)) {
|
|
427
|
+
const duration = Date.now() - startTime;
|
|
428
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
429
|
+
id,
|
|
430
|
+
status: "fail",
|
|
431
|
+
error: err
|
|
432
|
+
? typeof err === "object"
|
|
433
|
+
? JSON.stringify(err)
|
|
434
|
+
: String(err)
|
|
435
|
+
: "Native call failed",
|
|
436
|
+
duration,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
throw err;
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
return result;
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
if (markCompleted(id)) {
|
|
446
|
+
const duration = Date.now() - startTime;
|
|
447
|
+
store_1.chuckerStore.handleRequestComplete({
|
|
448
|
+
id,
|
|
449
|
+
status: "fail",
|
|
450
|
+
error: error ? error.message || String(error) : "Synchronous native error",
|
|
451
|
+
duration,
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
throw error;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
fn.isChuckerOverridden = true;
|
|
458
|
+
return fn;
|
|
459
|
+
};
|
|
460
|
+
let currentVal = globalObj.invokeNativePlugin;
|
|
461
|
+
let interceptedVal = setupNativeInterceptor(currentVal);
|
|
462
|
+
if (currentVal) {
|
|
463
|
+
try {
|
|
464
|
+
Object.defineProperty(globalObj, "invokeNativePlugin", {
|
|
465
|
+
value: interceptedVal,
|
|
466
|
+
writable: true,
|
|
467
|
+
configurable: true,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
catch (e) {
|
|
471
|
+
try {
|
|
472
|
+
globalObj.invokeNativePlugin = interceptedVal;
|
|
473
|
+
}
|
|
474
|
+
catch (err) { }
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
try {
|
|
478
|
+
Object.defineProperty(globalObj, "invokeNativePlugin", {
|
|
479
|
+
get() {
|
|
480
|
+
return interceptedVal;
|
|
481
|
+
},
|
|
482
|
+
set(newVal) {
|
|
483
|
+
currentVal = newVal;
|
|
484
|
+
interceptedVal = setupNativeInterceptor(newVal);
|
|
485
|
+
},
|
|
486
|
+
configurable: true,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
catch (e) { }
|
|
490
|
+
}
|
|
491
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = ChuckerPage;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const Chucker_1 = require("./components/Chucker");
|
|
9
|
+
function ChuckerPage() {
|
|
10
|
+
return react_1.default.createElement(Chucker_1.Chucker, null);
|
|
11
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ChuckerLog } from "./interceptor";
|
|
2
|
+
export type Listener = (logs: ChuckerLog[]) => void;
|
|
3
|
+
/** Input type for user-created log entries. `id` and `startTime` are auto-generated if omitted. */
|
|
4
|
+
export interface CustomLogInput {
|
|
5
|
+
/** Custom identifier. Auto-generated if omitted. */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** Log category. Use built-in "network"/"native" or any custom string like "websocket", "graphql", etc. */
|
|
8
|
+
type: ChuckerLog["type"];
|
|
9
|
+
/** Label for the operation (e.g. "GET", "SUBSCRIBE", "QUERY"). */
|
|
10
|
+
method: string;
|
|
11
|
+
/** URL or identifier for the operation. */
|
|
12
|
+
url: string;
|
|
13
|
+
requestHeaders?: Record<string, string>;
|
|
14
|
+
requestData?: any;
|
|
15
|
+
status?: string | number;
|
|
16
|
+
responseHeaders?: Record<string, string>;
|
|
17
|
+
responseData?: any;
|
|
18
|
+
error?: string;
|
|
19
|
+
/** Epoch timestamp in ms. Defaults to Date.now(). */
|
|
20
|
+
startTime?: number;
|
|
21
|
+
duration?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Payload to finalize a tracked operation started with `startTracking()`. */
|
|
24
|
+
export interface TrackingCompleteInput {
|
|
25
|
+
status?: string | number;
|
|
26
|
+
responseHeaders?: Record<string, string>;
|
|
27
|
+
responseData?: any;
|
|
28
|
+
error?: string;
|
|
29
|
+
/** If omitted, duration is calculated from startTime automatically. */
|
|
30
|
+
duration?: number;
|
|
31
|
+
}
|
|
32
|
+
declare class ChuckerStore {
|
|
33
|
+
private logs;
|
|
34
|
+
private listeners;
|
|
35
|
+
private maxLogs;
|
|
36
|
+
private isInitialized;
|
|
37
|
+
private lastNotifyTime;
|
|
38
|
+
private notifyTimeout;
|
|
39
|
+
init(maxLogs?: number): void;
|
|
40
|
+
handleRequestStart(log: ChuckerLog): void;
|
|
41
|
+
handleRequestComplete(payload: Partial<ChuckerLog> & {
|
|
42
|
+
id: string;
|
|
43
|
+
}): void;
|
|
44
|
+
/**
|
|
45
|
+
* Add a complete log entry in one call.
|
|
46
|
+
* Useful for logging one-shot events that don't need async tracking.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* chuckerStore.log({
|
|
51
|
+
* type: "websocket",
|
|
52
|
+
* method: "MESSAGE",
|
|
53
|
+
* url: "wss://example.com/ws",
|
|
54
|
+
* requestData: { event: "ping" },
|
|
55
|
+
* status: "success",
|
|
56
|
+
* responseData: { event: "pong" },
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
log(input: CustomLogInput): string;
|
|
61
|
+
/**
|
|
62
|
+
* Start tracking an async operation. Returns the generated log `id`.
|
|
63
|
+
* Call `completeTracking(id, result)` when the operation finishes.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const id = chuckerStore.startTracking({
|
|
68
|
+
* type: "graphql",
|
|
69
|
+
* method: "QUERY",
|
|
70
|
+
* url: "https://api.example.com/graphql",
|
|
71
|
+
* requestData: { query: "{ users { id name } }" },
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* // ... later when response arrives
|
|
75
|
+
* chuckerStore.completeTracking(id, {
|
|
76
|
+
* status: 200,
|
|
77
|
+
* responseData: { users: [...] },
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
startTracking(input: CustomLogInput): string;
|
|
82
|
+
/**
|
|
83
|
+
* Complete a previously tracked operation.
|
|
84
|
+
* Duration is calculated automatically if not provided.
|
|
85
|
+
*/
|
|
86
|
+
completeTracking(id: string, result?: TrackingCompleteInput): void;
|
|
87
|
+
private trimLogs;
|
|
88
|
+
getLogs(): ChuckerLog[];
|
|
89
|
+
clear(): void;
|
|
90
|
+
subscribe(listener: Listener): () => void;
|
|
91
|
+
private executeNotify;
|
|
92
|
+
private notify;
|
|
93
|
+
}
|
|
94
|
+
export declare const chuckerStore: ChuckerStore;
|
|
95
|
+
export {};
|