1688-cli 0.1.39 → 0.1.41
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/CHANGELOG.md +142 -0
- package/dist/cli.js +79 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/cart-add.js +15 -11
- package/dist/commands/cart-add.js.map +1 -1
- package/dist/commands/cart-list.js +11 -10
- package/dist/commands/cart-list.js.map +1 -1
- package/dist/commands/debug.js +101 -0
- package/dist/commands/debug.js.map +1 -0
- package/dist/commands/doctor.js +90 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/image-search.js +2 -6
- package/dist/commands/image-search.js.map +1 -1
- package/dist/commands/inbox.js +289 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/profile.js +84 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/search.js +98 -93
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/similar.js +2 -6
- package/dist/commands/similar.js.map +1 -1
- package/dist/daemon/client.js +2 -2
- package/dist/daemon/client.js.map +1 -1
- package/dist/io/output.js +31 -2
- package/dist/io/output.js.map +1 -1
- package/dist/session/config.js +82 -0
- package/dist/session/config.js.map +1 -0
- package/dist/session/dispatch.js +25 -3
- package/dist/session/dispatch.js.map +1 -1
- package/dist/session/events.js +151 -0
- package/dist/session/events.js.map +1 -0
- package/dist/session/im-cards.js +183 -0
- package/dist/session/im-cards.js.map +1 -0
- package/dist/session/im-ws.js +97 -0
- package/dist/session/im-ws.js.map +1 -0
- package/dist/session/navigation-guard.js +65 -0
- package/dist/session/navigation-guard.js.map +1 -0
- package/dist/session/paths.js +6 -0
- package/dist/session/paths.js.map +1 -1
- package/dist/session/search-capture.js +56 -6
- package/dist/session/search-capture.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { CliError } from '../io/errors.js';
|
|
3
|
+
import { configFile } from './paths.js';
|
|
4
|
+
const OBJECT_KEYS = new Set([
|
|
5
|
+
'defaultProfile',
|
|
6
|
+
'timeouts',
|
|
7
|
+
'artifacts',
|
|
8
|
+
'daemon',
|
|
9
|
+
'writeActions',
|
|
10
|
+
]);
|
|
11
|
+
export async function readConfig() {
|
|
12
|
+
let text;
|
|
13
|
+
try {
|
|
14
|
+
text = await fs.readFile(configFile(), 'utf8');
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
if (e.code === 'ENOENT')
|
|
18
|
+
return {};
|
|
19
|
+
throw new CliError(2, 'CONFIG_ERROR', `Cannot read config: ${e.message}`);
|
|
20
|
+
}
|
|
21
|
+
let value;
|
|
22
|
+
try {
|
|
23
|
+
value = JSON.parse(text);
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
throw new CliError(2, 'CONFIG_ERROR', `Invalid JSON in config: ${e.message}`);
|
|
27
|
+
}
|
|
28
|
+
return validateConfig(value);
|
|
29
|
+
}
|
|
30
|
+
export function validateConfig(value) {
|
|
31
|
+
if (!isRecord(value)) {
|
|
32
|
+
throw new CliError(2, 'CONFIG_ERROR', 'Config must be a JSON object.');
|
|
33
|
+
}
|
|
34
|
+
for (const key of Object.keys(value)) {
|
|
35
|
+
if (!OBJECT_KEYS.has(key)) {
|
|
36
|
+
throw new CliError(2, 'CONFIG_ERROR', `Unknown config key: ${key}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const cfg = value;
|
|
40
|
+
if (cfg.defaultProfile !== undefined && typeof cfg.defaultProfile !== 'string') {
|
|
41
|
+
throw new CliError(2, 'CONFIG_ERROR', 'defaultProfile must be a string.');
|
|
42
|
+
}
|
|
43
|
+
validateNumberObject(cfg.timeouts, 'timeouts', [
|
|
44
|
+
'searchMtopMs',
|
|
45
|
+
'headedVerificationMs',
|
|
46
|
+
'navigationMs',
|
|
47
|
+
]);
|
|
48
|
+
validateNumberObject(cfg.artifacts, 'artifacts', ['retentionDays']);
|
|
49
|
+
validateBooleanObject(cfg.daemon, 'daemon', ['headed']);
|
|
50
|
+
validateBooleanObject(cfg.writeActions, 'writeActions', ['confirmBeforeCheckout']);
|
|
51
|
+
return cfg;
|
|
52
|
+
}
|
|
53
|
+
function validateNumberObject(value, name, keys) {
|
|
54
|
+
if (value === undefined)
|
|
55
|
+
return;
|
|
56
|
+
if (!isRecord(value))
|
|
57
|
+
throw new CliError(2, 'CONFIG_ERROR', `${name} must be an object.`);
|
|
58
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
59
|
+
if (!keys.includes(key))
|
|
60
|
+
throw new CliError(2, 'CONFIG_ERROR', `Unknown config key: ${name}.${key}`);
|
|
61
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw) || raw < 0) {
|
|
62
|
+
throw new CliError(2, 'CONFIG_ERROR', `${name}.${key} must be a non-negative number.`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function validateBooleanObject(value, name, keys) {
|
|
67
|
+
if (value === undefined)
|
|
68
|
+
return;
|
|
69
|
+
if (!isRecord(value))
|
|
70
|
+
throw new CliError(2, 'CONFIG_ERROR', `${name} must be an object.`);
|
|
71
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
72
|
+
if (!keys.includes(key))
|
|
73
|
+
throw new CliError(2, 'CONFIG_ERROR', `Unknown config key: ${name}.${key}`);
|
|
74
|
+
if (typeof raw !== 'boolean') {
|
|
75
|
+
throw new CliError(2, 'CONFIG_ERROR', `${name}.${key} must be a boolean.`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function isRecord(value) {
|
|
80
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/session/config.ts"],"names":[],"mappings":"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"}
|
package/dist/session/dispatch.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// self-contained). Headed mode and explicit `--profile` always go inline.
|
|
3
3
|
import { withSession } from './context.js';
|
|
4
4
|
import { isDaemonReachable, daemonCall } from '../daemon/client.js';
|
|
5
|
+
import { makeRequestId } from '../daemon/protocol.js';
|
|
5
6
|
import { info } from '../io/output.js';
|
|
7
|
+
import { appendEventBestEffort, endEvent, eventFromError, startEvent, } from './events.js';
|
|
6
8
|
// Lazy-imported registry of command executors. Each entry must export `execute`.
|
|
7
9
|
// login/logout are deliberately omitted — they have interactive flows (QR render,
|
|
8
10
|
// stdin confirmation) that don't transit cleanly through a socket; they stay inline.
|
|
@@ -20,6 +22,7 @@ const REGISTRY = {
|
|
|
20
22
|
'checkout-prepare': () => import('../commands/checkout-prepare.js').then((m) => m.execute),
|
|
21
23
|
'seller-chat': () => import('../commands/seller-chat.js').then((m) => m.execute),
|
|
22
24
|
'seller-messages': () => import('../commands/seller-messages.js').then((m) => m.execute),
|
|
25
|
+
inbox: () => import('../commands/inbox.js').then((m) => m.execute),
|
|
23
26
|
'detail-feglobals': () => import('../commands/seller-inquire.js').then((m) => m.scrapeFeGlobals),
|
|
24
27
|
similar: () => import('../commands/similar.js').then((m) => m.execute),
|
|
25
28
|
};
|
|
@@ -30,6 +33,15 @@ export async function loadExecutor(name) {
|
|
|
30
33
|
return (await loader());
|
|
31
34
|
}
|
|
32
35
|
export async function dispatch(name, args, opts = {}) {
|
|
36
|
+
const requestId = makeRequestId();
|
|
37
|
+
const startedAt = Date.now();
|
|
38
|
+
await appendEventBestEffort(startEvent({ requestId, cmd: name, profile: opts.profile }));
|
|
39
|
+
const finishOk = async () => {
|
|
40
|
+
await appendEventBestEffort(endEvent({ requestId, cmd: name, startedAt, profile: opts.profile }));
|
|
41
|
+
};
|
|
42
|
+
const finishError = async (error) => {
|
|
43
|
+
await appendEventBestEffort(eventFromError({ requestId, cmd: name, startedAt, profile: opts.profile, error }));
|
|
44
|
+
};
|
|
33
45
|
const skipDaemon = opts.headed === true ||
|
|
34
46
|
!!opts.profile ||
|
|
35
47
|
opts.noDaemon === true ||
|
|
@@ -62,12 +74,16 @@ export async function dispatch(name, args, opts = {}) {
|
|
|
62
74
|
}
|
|
63
75
|
if (await isDaemonReachable()) {
|
|
64
76
|
try {
|
|
65
|
-
|
|
77
|
+
const data = await daemonCall(name, args, requestId);
|
|
78
|
+
await finishOk();
|
|
79
|
+
return data;
|
|
66
80
|
}
|
|
67
81
|
catch (e) {
|
|
68
82
|
const code = e.code;
|
|
69
|
-
if (code && code !== 'ECONNREFUSED' && code !== 'ENOENT')
|
|
83
|
+
if (code && code !== 'ECONNREFUSED' && code !== 'ENOENT') {
|
|
84
|
+
await finishError(e);
|
|
70
85
|
throw e;
|
|
86
|
+
}
|
|
71
87
|
}
|
|
72
88
|
}
|
|
73
89
|
}
|
|
@@ -77,7 +93,13 @@ export async function dispatch(name, args, opts = {}) {
|
|
|
77
93
|
const daemonMgr = await maybePauseDaemon();
|
|
78
94
|
try {
|
|
79
95
|
const fn = await loadExecutor(name);
|
|
80
|
-
|
|
96
|
+
const data = await withSession({ headless: !opts.headed, profile: opts.profile }, (ctx) => fn(ctx, args), { requestId, cmd: name, args });
|
|
97
|
+
await finishOk();
|
|
98
|
+
return data;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
await finishError(error);
|
|
102
|
+
throw error;
|
|
81
103
|
}
|
|
82
104
|
finally {
|
|
83
105
|
await daemonMgr.resume();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/session/dispatch.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,0EAA0E;AAG1E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/session/dispatch.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,0EAA0E;AAG1E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EACL,qBAAqB,EACrB,QAAQ,EACR,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC;AAarB,iFAAiF;AACjF,kFAAkF;AAClF,qFAAqF;AACrF,MAAM,QAAQ,GAA8D;IAC1E,MAAM,EAAE,GAAG,EAAE,CACX,MAAM,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAAC;IACtF,MAAM,EAAE,GAAG,EAAE,CACX,MAAM,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAAC;IACtF,YAAY,EAAE,GAAG,EAAE,CACjB,MAAM,CAAC,2BAA2B,CAAC,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,WAAW,EAAE,GAAG,EAAE,CAChB,MAAM,CAAC,0BAA0B,CAAC,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,iBAAiB,EAAE,GAAG,EAAE,CACtB,MAAM,CAAC,gCAAgC,CAAC,CAAC,IAAI,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,KAAK,EAAE,GAAG,EAAE,CACV,MAAM,CAAC,sBAAsB,CAAC,CAAC,IAAI,CACjC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,cAAc,EAAE,GAAG,EAAE,CACnB,MAAM,CAAC,6BAA6B,CAAC,CAAC,IAAI,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,WAAW,EAAE,GAAG,EAAE,CAChB,MAAM,CAAC,0BAA0B,CAAC,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,aAAa,EAAE,GAAG,EAAE,CAClB,MAAM,CAAC,4BAA4B,CAAC,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,UAAU,EAAE,GAAG,EAAE,CACf,MAAM,CAAC,yBAAyB,CAAC,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,kBAAkB,EAAE,GAAG,EAAE,CACvB,MAAM,CAAC,iCAAiC,CAAC,CAAC,IAAI,CAC5C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,aAAa,EAAE,GAAG,EAAE,CAClB,MAAM,CAAC,4BAA4B,CAAC,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,iBAAiB,EAAE,GAAG,EAAE,CACtB,MAAM,CAAC,gCAAgC,CAAC,CAAC,IAAI,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,KAAK,EAAE,GAAG,EAAE,CACV,MAAM,CAAC,sBAAsB,CAAC,CAAC,IAAI,CACjC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;IACH,kBAAkB,EAAE,GAAG,EAAE,CACvB,MAAM,CAAC,+BAA+B,CAAC,CAAC,IAAI,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAA6C,CACvD;IACH,OAAO,EAAE,GAAG,EAAE,CACZ,MAAM,CAAC,wBAAwB,CAAC,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqC,CAC/C;CACJ,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAY;IAEZ,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,MAAM,MAAM,EAAE,CAA2B,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAY,EACZ,IAAW,EACX,OAAqB,EAAE;IAEvB,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,qBAAqB,CACzB,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAC5D,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,qBAAqB,CACzB,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CACrE,CAAC;IACJ,CAAC,CAAC;IACF,MAAM,WAAW,GAAG,KAAK,EAAE,KAAc,EAAE,EAAE;QAC3C,MAAM,qBAAqB,CACzB,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAClF,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,UAAU,GACd,IAAI,CAAC,MAAM,KAAK,IAAI;QACpB,CAAC,CAAC,IAAI,CAAC,OAAO;QACd,IAAI,CAAC,QAAQ,KAAK,IAAI;QACtB,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC;IAEvC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,qEAAqE;QACrE,wEAAwE;QACxE,0DAA0D;QAC1D,IAAI,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;gBACnE,IAAI,CAAC,+BAA+B,CAAC,CAAC;gBACtC,MAAM,iBAAiB,EAAE,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,2CAA2C;YAC7C,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBACH,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;gBACnE,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,CAAC;gBACzC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBACrB,IAAI,CAAC,gDAAgD,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,qEAAqE;YACvE,CAAC;QACH,CAAC;QACD,IAAI,MAAM,iBAAiB,EAAE,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,UAAU,CAAQ,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;gBAC5D,MAAM,QAAQ,EAAE,CAAC;gBACjB,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,GAAI,CAAuB,CAAC,IAAI,CAAC;gBAC3C,IAAI,IAAI,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACzD,MAAM,WAAW,CAAC,CAAC,CAAC,CAAC;oBACrB,MAAM,CAAC,CAAC;gBACV,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,0DAA0D;IAC1D,MAAM,SAAS,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,YAAY,CAAe,IAAI,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,WAAW,CAC5B,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EACjD,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,EACtB,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAC/B,CAAC;QACF,MAAM,QAAQ,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;QACzB,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,gBAAgB;IAC7B,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;QACrE,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,CAAC;QAC1B,IAAI,CAAC,EAAE,CAAC,OAAO;YAAE,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,kCAAkC,CAAC,CAAC;QACzC,MAAM,IAAI,EAAE,CAAC;QACb,OAAO;YACL,MAAM,EAAE,KAAK,IAAI,EAAE;gBACjB,IAAI,CAAC;oBACH,IAAI,CAAC,oBAAoB,CAAC,CAAC;oBAC3B,MAAM,KAAK,EAAE,CAAC;gBAChB,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAI,CAAC,0BAA2B,CAAW,CAAC,OAAO,GAAG,CAAC,CAAC;gBAC1D,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAC;IACpC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { eventsFile } from './paths.js';
|
|
4
|
+
const SENSITIVE_KEY_RE = /cookie|token|password|passwd|secret|authorization|headers|body|message/i;
|
|
5
|
+
export function sanitizeForEvent(value) {
|
|
6
|
+
if (value === null || value === undefined)
|
|
7
|
+
return value;
|
|
8
|
+
if (typeof value !== 'object')
|
|
9
|
+
return value;
|
|
10
|
+
if (Array.isArray(value))
|
|
11
|
+
return value.map(sanitizeForEvent);
|
|
12
|
+
const out = {};
|
|
13
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
14
|
+
if (SENSITIVE_KEY_RE.test(key)) {
|
|
15
|
+
out[key] = '[redacted]';
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
out[key] = sanitizeForEvent(raw);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
export function eventFromError(input) {
|
|
24
|
+
const err = input.error;
|
|
25
|
+
const details = err?.details;
|
|
26
|
+
return {
|
|
27
|
+
ts: new Date().toISOString(),
|
|
28
|
+
requestId: input.requestId,
|
|
29
|
+
cmd: input.cmd,
|
|
30
|
+
phase: 'error',
|
|
31
|
+
status: 'error',
|
|
32
|
+
durationMs: Date.now() - input.startedAt,
|
|
33
|
+
profile: input.profile,
|
|
34
|
+
artifactDir: details?.artifactDir,
|
|
35
|
+
errorCode: err?.code,
|
|
36
|
+
pageState: details?.pageState,
|
|
37
|
+
verification: verificationFromDetails(details),
|
|
38
|
+
retryable: details?.retryable,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function startEvent(input) {
|
|
42
|
+
return {
|
|
43
|
+
ts: new Date().toISOString(),
|
|
44
|
+
requestId: input.requestId,
|
|
45
|
+
cmd: input.cmd,
|
|
46
|
+
phase: 'start',
|
|
47
|
+
status: 'running',
|
|
48
|
+
profile: input.profile,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function endEvent(input) {
|
|
52
|
+
return {
|
|
53
|
+
ts: new Date().toISOString(),
|
|
54
|
+
requestId: input.requestId,
|
|
55
|
+
cmd: input.cmd,
|
|
56
|
+
phase: 'end',
|
|
57
|
+
status: 'ok',
|
|
58
|
+
durationMs: Date.now() - input.startedAt,
|
|
59
|
+
profile: input.profile,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export async function appendEvent(event) {
|
|
63
|
+
const file = eventsFile();
|
|
64
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
65
|
+
await fs.appendFile(file, JSON.stringify(sanitizeForEvent(event)) + '\n');
|
|
66
|
+
}
|
|
67
|
+
export async function appendEventBestEffort(event) {
|
|
68
|
+
await appendEvent(event).catch(() => { });
|
|
69
|
+
}
|
|
70
|
+
export async function readRecentEvents(limit = 100) {
|
|
71
|
+
const events = await readAllEvents();
|
|
72
|
+
return events.slice(-Math.max(1, limit));
|
|
73
|
+
}
|
|
74
|
+
export async function readAllEvents() {
|
|
75
|
+
const file = eventsFile();
|
|
76
|
+
let text = '';
|
|
77
|
+
try {
|
|
78
|
+
text = await fs.readFile(file, 'utf8');
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const events = [];
|
|
84
|
+
for (const line of text.split('\n').filter(Boolean)) {
|
|
85
|
+
try {
|
|
86
|
+
events.push(JSON.parse(line));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
/* skip malformed historical line */
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return events;
|
|
93
|
+
}
|
|
94
|
+
export function summarizeEvents(events) {
|
|
95
|
+
const byRequest = new Map();
|
|
96
|
+
for (const event of events) {
|
|
97
|
+
const list = byRequest.get(event.requestId) ?? [];
|
|
98
|
+
list.push(event);
|
|
99
|
+
byRequest.set(event.requestId, list);
|
|
100
|
+
}
|
|
101
|
+
return [...byRequest.entries()].map(([requestId, list]) => {
|
|
102
|
+
const sorted = [...list].sort((a, b) => a.ts.localeCompare(b.ts));
|
|
103
|
+
const first = sorted[0];
|
|
104
|
+
const last = sorted.at(-1);
|
|
105
|
+
return {
|
|
106
|
+
requestId,
|
|
107
|
+
cmd: last.cmd || first.cmd,
|
|
108
|
+
status: last.status,
|
|
109
|
+
startedAt: sorted.find((e) => e.phase === 'start')?.ts ?? first.ts,
|
|
110
|
+
endedAt: last.phase === 'start' ? undefined : last.ts,
|
|
111
|
+
durationMs: last.durationMs,
|
|
112
|
+
profile: last.profile ?? first.profile,
|
|
113
|
+
artifactDir: last.artifactDir,
|
|
114
|
+
errorCode: last.errorCode,
|
|
115
|
+
pageState: last.pageState,
|
|
116
|
+
verification: last.verification,
|
|
117
|
+
warnings: last.warnings,
|
|
118
|
+
events: sorted,
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
export async function readRecentEventSummaries(limit = 20) {
|
|
123
|
+
const summaries = summarizeEvents(await readAllEvents());
|
|
124
|
+
return summaries.slice(-Math.max(1, limit));
|
|
125
|
+
}
|
|
126
|
+
function verificationFromDetails(details) {
|
|
127
|
+
if (!details)
|
|
128
|
+
return undefined;
|
|
129
|
+
if (details.pageState === 'not_logged_in') {
|
|
130
|
+
return {
|
|
131
|
+
state: 'login_required',
|
|
132
|
+
currentUrl: details.currentUrl,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (details.category === 'risk_control' || details.pageState === 'rate_limited') {
|
|
136
|
+
return {
|
|
137
|
+
state: 'risk_control',
|
|
138
|
+
reason: details.pageState,
|
|
139
|
+
currentUrl: details.currentUrl,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (details.currentUrl || details.pageState) {
|
|
143
|
+
return {
|
|
144
|
+
state: 'unknown',
|
|
145
|
+
reason: details.pageState,
|
|
146
|
+
currentUrl: details.currentUrl,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/session/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// Decoder for 1688 IM "last message" payloads as they arrive in the
|
|
2
|
+
// `/r/Conversation/listNewestPagination` response.
|
|
3
|
+
//
|
|
4
|
+
// 1688 IM messages come in four practical shapes:
|
|
5
|
+
// contentType === 1 → plain text
|
|
6
|
+
// contentType === 2 → image (rare in CBU)
|
|
7
|
+
// contentType === 101 → custom card (orders, offers, refunds, notices…)
|
|
8
|
+
// contentType missing → server stripped content (old messages, ~12+ months)
|
|
9
|
+
//
|
|
10
|
+
// For card messages, the human-readable preview AND structured fields
|
|
11
|
+
// (orderId / offerId / link / image / amount) live in TWO places:
|
|
12
|
+
// 1. `content.custom.data` — base64-encoded JSON
|
|
13
|
+
// 2. `message.extension.dynamic_msg_content` — JSON-string template
|
|
14
|
+
// The two are independent: some cards populate only one, some both, some
|
|
15
|
+
// neither (those degrade to the bare `[卡片消息]` summary).
|
|
16
|
+
//
|
|
17
|
+
// The card *template* itself is identified by a 6-digit code inside
|
|
18
|
+
// `extension.biMsgType` (e.g. `bc_0_170002_<tplInstanceId>` → `170002`).
|
|
19
|
+
// Codes seen in production map to known semantic categories; unmapped
|
|
20
|
+
// codes still surface the raw code so agents can filter on it.
|
|
21
|
+
// Card template code → semantic name. Source: probe of 2400+ live
|
|
22
|
+
// conversations on a real buyer account; codes not in this map fall back
|
|
23
|
+
// to `'unknown'` but the raw `cardCode` is still emitted so callers can
|
|
24
|
+
// branch on it.
|
|
25
|
+
const TEMPLATE_BY_CODE = {
|
|
26
|
+
'170002': 'order_followup', // 催发货卡片
|
|
27
|
+
'527001': 'order_fulfillment', // 少发漏发反馈
|
|
28
|
+
'339001': 'order_status', // 我在看这笔订单
|
|
29
|
+
'362001': 'order_payment_reminder', // 未付款提醒
|
|
30
|
+
'367004': 'order_payment_reminder', // 订单已改价完成 — 请确认
|
|
31
|
+
'381001': 'address_changed', // 订单地址已修改
|
|
32
|
+
'247001': 'refund', // 订单待退货提醒
|
|
33
|
+
'467001': 'offer', // 首发/趋势新品推荐
|
|
34
|
+
'390001': 'offer', // 商品推荐 v2
|
|
35
|
+
'487002': 'offer', // 商品推荐 v3
|
|
36
|
+
'494001': 'coupon', // 老客券待领取
|
|
37
|
+
'338001': 'evaluation_invite', // 客服评价邀请
|
|
38
|
+
'364002': 'session_ended', // 会话已结束
|
|
39
|
+
'352003': 'misc', // 延期必赔
|
|
40
|
+
'280002': 'misc', // 推荐换供
|
|
41
|
+
'293003': 'misc',
|
|
42
|
+
'318002': 'misc',
|
|
43
|
+
'356001': 'misc',
|
|
44
|
+
'360001': 'misc',
|
|
45
|
+
'399002': 'misc',
|
|
46
|
+
'453005': 'misc',
|
|
47
|
+
};
|
|
48
|
+
export function decodeLastMessage(msg) {
|
|
49
|
+
const ct = msg?.content?.contentType;
|
|
50
|
+
if (ct === 1) {
|
|
51
|
+
const text = msg?.content?.text?.content ?? '';
|
|
52
|
+
return { kind: 'text', preview: text.slice(0, 200) };
|
|
53
|
+
}
|
|
54
|
+
if (ct === 2) {
|
|
55
|
+
return { kind: 'image', preview: '[图片]' };
|
|
56
|
+
}
|
|
57
|
+
if (ct == null) {
|
|
58
|
+
// Server returns a populated lastMessage envelope but with no `content`
|
|
59
|
+
// for conversations whose last activity is older than ~12 months.
|
|
60
|
+
return { kind: 'archived', preview: '[历史会话 — 内容已归档]' };
|
|
61
|
+
}
|
|
62
|
+
if (ct !== 101) {
|
|
63
|
+
return { kind: 'other', preview: `[未知消息 ct=${ct}]` };
|
|
64
|
+
}
|
|
65
|
+
return decodeCard(msg ?? {});
|
|
66
|
+
}
|
|
67
|
+
function decodeCard(msg) {
|
|
68
|
+
const ext = msg.extension ?? {};
|
|
69
|
+
const custom = msg.content?.custom ?? {};
|
|
70
|
+
const dataObj = decodeBase64Json(custom.data);
|
|
71
|
+
const dynObj = decodeDynamicMsgContent(ext.dynamic_msg_content);
|
|
72
|
+
const cardCode = ext.biMsgType?.match(/bc_\d+_(\d{6})_/)?.[1];
|
|
73
|
+
const cardTemplate = (cardCode && TEMPLATE_BY_CODE[cardCode]) || 'unknown';
|
|
74
|
+
const preview = pickPreview(custom.summary, dataObj, dynObj);
|
|
75
|
+
const extras = extractExtras(dataObj, dynObj);
|
|
76
|
+
const out = {
|
|
77
|
+
kind: 'card',
|
|
78
|
+
preview,
|
|
79
|
+
cardTemplate,
|
|
80
|
+
};
|
|
81
|
+
if (cardCode)
|
|
82
|
+
out.cardCode = cardCode;
|
|
83
|
+
if (Object.keys(extras).length > 0)
|
|
84
|
+
out.extras = extras;
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
function decodeBase64Json(data) {
|
|
88
|
+
if (!data)
|
|
89
|
+
return null;
|
|
90
|
+
try {
|
|
91
|
+
const decoded = Buffer.from(data, 'base64').toString('utf8');
|
|
92
|
+
const parsed = JSON.parse(decoded);
|
|
93
|
+
return typeof parsed === 'object' && parsed !== null
|
|
94
|
+
? parsed
|
|
95
|
+
: null;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function decodeDynamicMsgContent(raw) {
|
|
102
|
+
if (!raw)
|
|
103
|
+
return null;
|
|
104
|
+
try {
|
|
105
|
+
const arr = JSON.parse(raw);
|
|
106
|
+
if (Array.isArray(arr) && arr[0] && typeof arr[0] === 'object') {
|
|
107
|
+
const td = arr[0].templateData;
|
|
108
|
+
return td && typeof td === 'object'
|
|
109
|
+
? td
|
|
110
|
+
: null;
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function pickPreview(summary, dataObj, dynObj) {
|
|
119
|
+
// Order: prefer rich title fields > fall back to bare summary > generic.
|
|
120
|
+
// `summary === '[卡片消息]'` is the SDK's degraded placeholder; only use
|
|
121
|
+
// it as last resort.
|
|
122
|
+
const isMeaningfulSummary = typeof summary === 'string' &&
|
|
123
|
+
summary.length > 0 &&
|
|
124
|
+
summary !== '[卡片消息]';
|
|
125
|
+
const candidates = [
|
|
126
|
+
isMeaningfulSummary ? summary : null,
|
|
127
|
+
dataObj?.productTitle,
|
|
128
|
+
dataObj?.title,
|
|
129
|
+
dataObj?.refundTitle,
|
|
130
|
+
dataObj?.refundContent,
|
|
131
|
+
dynObj?.title,
|
|
132
|
+
dynObj?.offerSubTitle,
|
|
133
|
+
dynObj?.grayText,
|
|
134
|
+
summary, // last resort — may be '[卡片消息]'
|
|
135
|
+
];
|
|
136
|
+
for (const c of candidates) {
|
|
137
|
+
if (typeof c === 'string' && c.length > 0)
|
|
138
|
+
return c.slice(0, 200);
|
|
139
|
+
}
|
|
140
|
+
return '[卡片消息]';
|
|
141
|
+
}
|
|
142
|
+
function extractExtras(dataObj, dynObj) {
|
|
143
|
+
const extras = {};
|
|
144
|
+
const linkUrl = asString(dataObj?.linkUrl) ??
|
|
145
|
+
asString(dynObj?.pcJumpUrl) ??
|
|
146
|
+
asString(dynObj?.actionJumpUrl);
|
|
147
|
+
if (linkUrl)
|
|
148
|
+
extras.linkUrl = linkUrl;
|
|
149
|
+
// orderId: present in either base64 data (`linkUrl` query) or template
|
|
150
|
+
// data (`actionJumpUrl`). Match either `order_id=` or `orderId=`.
|
|
151
|
+
const orderId = linkUrl?.match(/order[_ ]?id=(\d+)/i)?.[1];
|
|
152
|
+
if (orderId)
|
|
153
|
+
extras.orderId = orderId;
|
|
154
|
+
// offerId: 1688 product page URL form is `…/offer/<digits>.html`
|
|
155
|
+
const offerSource = asString(dynObj?.pcJumpUrl) ?? asString(dynObj?.actionJumpUrl) ?? linkUrl;
|
|
156
|
+
const offerId = offerSource?.match(/offer\/(\d+)/)?.[1];
|
|
157
|
+
if (offerId)
|
|
158
|
+
extras.offerId = offerId;
|
|
159
|
+
// refundId from refund detail link
|
|
160
|
+
const refundId = linkUrl?.match(/refundId=([A-Z0-9]+)/)?.[1];
|
|
161
|
+
if (refundId)
|
|
162
|
+
extras.refundId = refundId;
|
|
163
|
+
const imgUrl = asString(dataObj?.imgUrl) ?? asString(dynObj?.offerPic);
|
|
164
|
+
if (imgUrl)
|
|
165
|
+
extras.imgUrl = imgUrl;
|
|
166
|
+
// amount: order cards put it in `refundAmt` (display-ready string);
|
|
167
|
+
// offer cards split price into firstPart/secondPart (yuan / cents).
|
|
168
|
+
const amount = asString(dataObj?.refundAmt) ?? buildOfferAmount(dynObj);
|
|
169
|
+
if (amount)
|
|
170
|
+
extras.amount = amount;
|
|
171
|
+
return extras;
|
|
172
|
+
}
|
|
173
|
+
function buildOfferAmount(dynObj) {
|
|
174
|
+
const first = asString(dynObj?.firstPartPrice);
|
|
175
|
+
if (!first)
|
|
176
|
+
return null;
|
|
177
|
+
const second = asString(dynObj?.secondPartPrice) ?? '00';
|
|
178
|
+
return `¥${first}.${second}`;
|
|
179
|
+
}
|
|
180
|
+
function asString(v) {
|
|
181
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=im-cards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"im-cards.js","sourceRoot":"","sources":["../../src/session/im-cards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs';
|
|
2
|
+
import { waitUntil } from './wait.js';
|
|
3
|
+
export const IM_BASE = 'https://air.1688.com/app/ocms-fusion-components-1688/def_cbu_web_im/index.html';
|
|
4
|
+
export function collectWsFrames(page) {
|
|
5
|
+
const frames = [];
|
|
6
|
+
page.on('websocket', (ws) => {
|
|
7
|
+
const record = (type, payloadRaw) => {
|
|
8
|
+
const payload = typeof payloadRaw === 'string' ? payloadRaw : payloadRaw.toString();
|
|
9
|
+
let method = '';
|
|
10
|
+
let mid = null;
|
|
11
|
+
try {
|
|
12
|
+
const j = JSON.parse(payload);
|
|
13
|
+
method = j?.lwp ?? '';
|
|
14
|
+
mid = j?.headers?.mid ?? null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
/* not JSON — skip */
|
|
18
|
+
}
|
|
19
|
+
frames.push({ type, method, mid, payloadLen: payload.length, payload });
|
|
20
|
+
};
|
|
21
|
+
ws.on('framesent', (frame) => record('sent', frame.payload));
|
|
22
|
+
ws.on('framereceived', (frame) => record('recv', frame.payload));
|
|
23
|
+
});
|
|
24
|
+
return frames;
|
|
25
|
+
}
|
|
26
|
+
function midToMethodMap(frames) {
|
|
27
|
+
const m = new Map();
|
|
28
|
+
for (const f of frames) {
|
|
29
|
+
if (f.type === 'sent' && f.mid && f.method)
|
|
30
|
+
m.set(f.mid, f.method);
|
|
31
|
+
}
|
|
32
|
+
return m;
|
|
33
|
+
}
|
|
34
|
+
export function findLwpResponses(frames, method) {
|
|
35
|
+
const midToMethod = midToMethodMap(frames);
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const f of frames) {
|
|
38
|
+
if (f.type !== 'recv')
|
|
39
|
+
continue;
|
|
40
|
+
if (!f.mid)
|
|
41
|
+
continue;
|
|
42
|
+
if (midToMethod.get(f.mid) !== method)
|
|
43
|
+
continue;
|
|
44
|
+
try {
|
|
45
|
+
const env = JSON.parse(f.payload);
|
|
46
|
+
if (env.code !== 200)
|
|
47
|
+
continue;
|
|
48
|
+
if (env.body !== undefined)
|
|
49
|
+
out.push(env.body);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
/* skip */
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
export async function waitForLwpResponse(frames, method, timeoutMs) {
|
|
58
|
+
return waitUntil(() => {
|
|
59
|
+
const midToMethod = midToMethodMap(frames);
|
|
60
|
+
return frames.some((f) => f.type === 'recv' && f.mid && midToMethod.get(f.mid) === method);
|
|
61
|
+
}, { timeoutMs, intervalMs: 200 });
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Probe support: synchronously dump WS frames to /tmp/1688-ws-*.json.
|
|
65
|
+
*
|
|
66
|
+
* Call from inside the command's `try` block (NOT from `page.on('close', ...)`)
|
|
67
|
+
* so the dump runs before process exit. Headless `page.close()` does not
|
|
68
|
+
* always flush close-event listeners before the process exits.
|
|
69
|
+
*/
|
|
70
|
+
export function dumpWsFramesForProbe(frames, interestingPattern = /Message|Conversation|SingleChat/i, payloadHints = /msgId|messageId|cardType|offerId|orderId|conversationCode|userConvs|listMessage/i) {
|
|
71
|
+
if (process.env.BB1688_PROBE !== '1')
|
|
72
|
+
return;
|
|
73
|
+
const midToMethod = midToMethodMap(frames);
|
|
74
|
+
const enriched = frames.map((f) => ({
|
|
75
|
+
...f,
|
|
76
|
+
reqMethod: f.type === 'recv' && f.mid ? midToMethod.get(f.mid) ?? null : null,
|
|
77
|
+
}));
|
|
78
|
+
const interesting = enriched.filter((f) => {
|
|
79
|
+
if (f.type === 'sent')
|
|
80
|
+
return interestingPattern.test(f.method);
|
|
81
|
+
if (f.reqMethod && interestingPattern.test(f.reqMethod))
|
|
82
|
+
return true;
|
|
83
|
+
return payloadHints.test(f.payload);
|
|
84
|
+
});
|
|
85
|
+
try {
|
|
86
|
+
writeFileSync('/tmp/1688-ws-frames.json', JSON.stringify(enriched, null, 2));
|
|
87
|
+
writeFileSync('/tmp/1688-ws-interesting.json', JSON.stringify(interesting, null, 2));
|
|
88
|
+
process.stderr.write(`[ws-frames] total=${frames.length} interesting=${interesting.length}\n` +
|
|
89
|
+
`methods seen: ${[...new Set(frames.map((f) => f.method).filter(Boolean))].join(', ')}\n` +
|
|
90
|
+
`full dump → /tmp/1688-ws-frames.json (${enriched.length} frames)\n` +
|
|
91
|
+
`interesting dump → /tmp/1688-ws-interesting.json (${interesting.length} frames)\n`);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
process.stderr.write(`[ws-frames] write failed: ${String(e)}\n`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=im-ws.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"im-ws.js","sourceRoot":"","sources":["../../src/session/im-ws.ts"],"names":[],"mappings":"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"}
|