1688-cli 0.1.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/AGENTS.md +118 -0
- package/README.md +48 -0
- package/dist/auth/cookies.js +31 -0
- package/dist/auth/cookies.js.map +1 -0
- package/dist/auth/verify.js +25 -0
- package/dist/auth/verify.js.map +1 -0
- package/dist/cli.js +373 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/cart-add.js +199 -0
- package/dist/commands/cart-add.js.map +1 -0
- package/dist/commands/cart-list.js +168 -0
- package/dist/commands/cart-list.js.map +1 -0
- package/dist/commands/cart-remove.js +119 -0
- package/dist/commands/cart-remove.js.map +1 -0
- package/dist/commands/checkout-confirm.js +407 -0
- package/dist/commands/checkout-confirm.js.map +1 -0
- package/dist/commands/checkout-prepare.js +244 -0
- package/dist/commands/checkout-prepare.js.map +1 -0
- package/dist/commands/doctor.js +246 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/image-search.js +210 -0
- package/dist/commands/image-search.js.map +1 -0
- package/dist/commands/login.js +209 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.js +59 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/offer.js +185 -0
- package/dist/commands/offer.js.map +1 -0
- package/dist/commands/order-get.js +76 -0
- package/dist/commands/order-get.js.map +1 -0
- package/dist/commands/order-list.js +176 -0
- package/dist/commands/order-list.js.map +1 -0
- package/dist/commands/order-logistics.js +152 -0
- package/dist/commands/order-logistics.js.map +1 -0
- package/dist/commands/search.js +250 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/seller-chat.js +213 -0
- package/dist/commands/seller-chat.js.map +1 -0
- package/dist/commands/seller-inquire.js +110 -0
- package/dist/commands/seller-inquire.js.map +1 -0
- package/dist/commands/seller-lookup-ww.js +6 -0
- package/dist/commands/seller-lookup-ww.js.map +1 -0
- package/dist/commands/seller-messages.js +181 -0
- package/dist/commands/seller-messages.js.map +1 -0
- package/dist/commands/whoami.js +53 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/commands/workflows.js +264 -0
- package/dist/commands/workflows.js.map +1 -0
- package/dist/daemon/client.js +75 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/manager.js +128 -0
- package/dist/daemon/manager.js.map +1 -0
- package/dist/daemon/protocol.js +5 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/server.js +197 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/throttle.js +17 -0
- package/dist/daemon/throttle.js.map +1 -0
- package/dist/io/errors.js +10 -0
- package/dist/io/errors.js.map +1 -0
- package/dist/io/output.js +17 -0
- package/dist/io/output.js.map +1 -0
- package/dist/io/prompt.js +17 -0
- package/dist/io/prompt.js.map +1 -0
- package/dist/session/context.js +91 -0
- package/dist/session/context.js.map +1 -0
- package/dist/session/dispatch.js +50 -0
- package/dist/session/dispatch.js.map +1 -0
- package/dist/session/lock.js +23 -0
- package/dist/session/lock.js.map +1 -0
- package/dist/session/paths.js +31 -0
- package/dist/session/paths.js.map +1 -0
- package/dist/session/shared.js +104 -0
- package/dist/session/shared.js.map +1 -0
- package/dist/session/state.js +27 -0
- package/dist/session/state.js.map +1 -0
- package/dist/util/time.js +17 -0
- package/dist/util/time.js.map +1 -0
- package/package.json +44 -0
- package/scripts/postinstall.mjs +49 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import iconv from 'iconv-lite';
|
|
2
|
+
import { dispatch } from '../session/dispatch.js';
|
|
3
|
+
import { emit, info } from '../io/output.js';
|
|
4
|
+
import { CliError } from '../io/errors.js';
|
|
5
|
+
export async function execute(ctx, args) {
|
|
6
|
+
const offers = await fetchSearch(ctx, args.keyword, args.headed === true);
|
|
7
|
+
const slice = offers.slice(0, args.max);
|
|
8
|
+
return { keyword: args.keyword, total: slice.length, offers: slice };
|
|
9
|
+
}
|
|
10
|
+
export async function run(keyword, opts) {
|
|
11
|
+
const kw = (keyword ?? '').trim();
|
|
12
|
+
if (!kw) {
|
|
13
|
+
throw new CliError(2, 'BAD_INPUT', 'Search keyword is required.');
|
|
14
|
+
}
|
|
15
|
+
const max = Math.max(1, parseInt(opts.max ?? '20', 10));
|
|
16
|
+
const data = await dispatch('search', { keyword: kw, max, headed: opts.headed }, { headed: opts.headed, profile: opts.profile });
|
|
17
|
+
emit({
|
|
18
|
+
human: () => printOffers(data.offers, data.keyword),
|
|
19
|
+
data,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
async function fetchSearch(ctx, keyword, headed) {
|
|
23
|
+
const page = await ctx.newPage();
|
|
24
|
+
// s.1688.com is GBK-encoded — UTF-8 percent-encoding makes the server
|
|
25
|
+
// search for mojibake. Encode the keyword as GBK bytes first.
|
|
26
|
+
const gbkBytes = iconv.encode(keyword, 'gbk');
|
|
27
|
+
const gbkQs = Array.from(gbkBytes)
|
|
28
|
+
.map((b) => '%' + b.toString(16).padStart(2, '0').toUpperCase())
|
|
29
|
+
.join('');
|
|
30
|
+
const url = `https://s.1688.com/selloffer/offer_search.htm?keywords=${gbkQs}`;
|
|
31
|
+
info(`Searching 1688 for "${keyword}"...`);
|
|
32
|
+
if (headed) {
|
|
33
|
+
info('A Chrome window has opened — switch focus to it now.');
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
throw new CliError(9, 'NETWORK_ERROR', `Failed to load search page: ${e.message}`);
|
|
40
|
+
}
|
|
41
|
+
// Risk-control gate with retry. Headed: let user solve.
|
|
42
|
+
if (await waitPastBlocking(page, headed)) {
|
|
43
|
+
/* passed */
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
throw riskControlError(headed);
|
|
47
|
+
}
|
|
48
|
+
await detectLoginRedirect(page);
|
|
49
|
+
try {
|
|
50
|
+
await page.waitForSelector('.search-offer-item a[href*="detail.m.1688.com"]', { timeout: headed ? 180000 : 15000 });
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
if (await isBlocked(page))
|
|
54
|
+
throw riskControlError(headed);
|
|
55
|
+
}
|
|
56
|
+
// Scroll to trigger lazy-loaded cards.
|
|
57
|
+
await page.evaluate(() => window.scrollBy(0, 2000));
|
|
58
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
59
|
+
await page.evaluate(() => window.scrollBy(0, 2000));
|
|
60
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
61
|
+
const offers = await extractOffers(page);
|
|
62
|
+
if (process.env.BB1688_DEBUG === '1') {
|
|
63
|
+
const stats = await page.evaluate(() => ({
|
|
64
|
+
cards: document.querySelectorAll('.search-offer-item').length,
|
|
65
|
+
linksToDetail: document.querySelectorAll('.search-offer-item a[href*="detail.m.1688.com"]').length,
|
|
66
|
+
totalDetailLinks: document.querySelectorAll('a[href*="detail.m.1688.com"], a[href*="detail.1688.com"]').length,
|
|
67
|
+
title: document.title,
|
|
68
|
+
bodyHead: (document.body?.innerText ?? '').slice(0, 120),
|
|
69
|
+
}));
|
|
70
|
+
process.stderr.write(`[debug] url=${page.url()}\n` +
|
|
71
|
+
`[debug] title=${stats.title}\n` +
|
|
72
|
+
`[debug] cards=${stats.cards} linksToDetail=${stats.linksToDetail} totalDetailLinks=${stats.totalDetailLinks} extracted=${offers.length}\n` +
|
|
73
|
+
`[debug] body=${stats.bodyHead}\n`);
|
|
74
|
+
}
|
|
75
|
+
return offers;
|
|
76
|
+
}
|
|
77
|
+
async function isBlocked(page, retries = 3) {
|
|
78
|
+
for (let i = 0; i < retries; i++) {
|
|
79
|
+
try {
|
|
80
|
+
if (/\/punish|x5secdata=/.test(page.url()))
|
|
81
|
+
return true;
|
|
82
|
+
const sig = await page.evaluate(() => ({
|
|
83
|
+
title: document.title ?? '',
|
|
84
|
+
body: (document.body?.innerText ?? '').slice(0, 500),
|
|
85
|
+
}));
|
|
86
|
+
if (/验证码拦截|拖动.*滑块|滑动.*验证/.test(sig.title + ' ' + sig.body)) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (i < retries - 1)
|
|
94
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Returns true once the page is past any risk-control gate.
|
|
100
|
+
* Primary success signal: search result cards have rendered.
|
|
101
|
+
* Headless: short timeout, fail fast. Headed: long timeout, user solves.
|
|
102
|
+
*/
|
|
103
|
+
async function waitPastBlocking(page, headed) {
|
|
104
|
+
const timeoutMs = headed ? 180000 : 5000;
|
|
105
|
+
const deadline = Date.now() + timeoutMs;
|
|
106
|
+
let announced = false;
|
|
107
|
+
let lastProgressAt = Date.now();
|
|
108
|
+
while (Date.now() < deadline) {
|
|
109
|
+
if (page.isClosed()) {
|
|
110
|
+
throw new CliError(130, 'CANCELED', 'Browser closed.');
|
|
111
|
+
}
|
|
112
|
+
// Strongest success signal: results are rendered.
|
|
113
|
+
const hasCards = await page
|
|
114
|
+
.evaluate(() => document.querySelectorAll('.search-offer-item').length > 0)
|
|
115
|
+
.catch(() => false);
|
|
116
|
+
if (hasCards)
|
|
117
|
+
return true;
|
|
118
|
+
if (process.env.BB1688_DEBUG === '1') {
|
|
119
|
+
const sig = await page
|
|
120
|
+
.evaluate(() => ({
|
|
121
|
+
url: location.href,
|
|
122
|
+
title: document.title ?? '',
|
|
123
|
+
body: (document.body?.innerText ?? '').slice(0, 80),
|
|
124
|
+
}))
|
|
125
|
+
.catch(() => null);
|
|
126
|
+
if (sig) {
|
|
127
|
+
process.stderr.write(`[debug] url=${sig.url}\n[debug] title=${sig.title} body=${sig.body}\n`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const blocked = await isBlocked(page, 1);
|
|
131
|
+
if (!blocked) {
|
|
132
|
+
// Not blocked, no cards yet — page is loading/transitioning. Keep polling.
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
if (!headed)
|
|
136
|
+
return false;
|
|
137
|
+
if (!announced) {
|
|
138
|
+
info('Verification page detected — drag the slider in the window.');
|
|
139
|
+
announced = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (Date.now() - lastProgressAt > 10000) {
|
|
143
|
+
info(`Still waiting (${Math.round((deadline - Date.now()) / 1000)}s left)...`);
|
|
144
|
+
lastProgressAt = Date.now();
|
|
145
|
+
}
|
|
146
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
function riskControlError(triedHeaded) {
|
|
151
|
+
const msg = triedHeaded
|
|
152
|
+
? 'Slider verification not solved in time. Try again:\n' +
|
|
153
|
+
' 1688 search "<keyword>" --headed'
|
|
154
|
+
: 'Aliyun risk control triggered (slider verification). ' +
|
|
155
|
+
'Run once with --headed to solve it manually; subsequent headless calls work for hours:\n' +
|
|
156
|
+
' 1688 search "<keyword>" --headed';
|
|
157
|
+
return new CliError(4, 'RISK_CONTROL', msg);
|
|
158
|
+
}
|
|
159
|
+
async function detectLoginRedirect(page) {
|
|
160
|
+
if (/login\.1688\.com|login\.taobao\.com/.test(page.url())) {
|
|
161
|
+
throw new CliError(3, 'NOT_LOGGED_IN', 'Session expired. Run `1688 login`.');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
export async function extractOffers(page) {
|
|
165
|
+
return page.evaluate(() => {
|
|
166
|
+
const cards = document.querySelectorAll('.search-offer-item');
|
|
167
|
+
const seen = new Set();
|
|
168
|
+
const out = [];
|
|
169
|
+
for (const card of Array.from(cards)) {
|
|
170
|
+
let link = card.closest('a[href*="detail.m.1688.com"]') ??
|
|
171
|
+
card.querySelector('a[href*="detail.m.1688.com"]');
|
|
172
|
+
if (!link)
|
|
173
|
+
continue;
|
|
174
|
+
const m = link.href.match(/[?&]offerId=(\d+)/);
|
|
175
|
+
if (!m)
|
|
176
|
+
continue;
|
|
177
|
+
const offerId = m[1];
|
|
178
|
+
if (seen.has(offerId))
|
|
179
|
+
continue;
|
|
180
|
+
seen.add(offerId);
|
|
181
|
+
const titleEl = card.querySelector('.offer-title-row .title-text') ??
|
|
182
|
+
card.querySelector('.offer-title-row');
|
|
183
|
+
const title = (titleEl?.textContent ?? '').replace(/\s+/g, ' ').trim();
|
|
184
|
+
const priceItem = card.querySelector('.price-item');
|
|
185
|
+
const priceText = priceItem
|
|
186
|
+
? (priceItem.textContent ?? '').replace(/\s+/g, '')
|
|
187
|
+
: '';
|
|
188
|
+
const pm = priceText.match(/([¥¥])?\s*([\d.]+)(?:\s*[~\-–]\s*([\d.]+))?/);
|
|
189
|
+
const priceMin = pm ? parseFloat(pm[2]) : null;
|
|
190
|
+
const priceMax = pm && pm[3] ? parseFloat(pm[3]) : priceMin;
|
|
191
|
+
const img = card.querySelector('img.main-img') ??
|
|
192
|
+
card.querySelector('img');
|
|
193
|
+
const image = img?.getAttribute('src') ??
|
|
194
|
+
img?.getAttribute('data-src') ??
|
|
195
|
+
null;
|
|
196
|
+
const shopRow = card.querySelector('.offer-shop-row');
|
|
197
|
+
const supplierLink = shopRow?.querySelector('a[href*=".1688.com"]');
|
|
198
|
+
const supplierName = shopRow?.querySelector('.desc-text')?.textContent?.trim() ?? null;
|
|
199
|
+
const shopUrl = supplierLink?.href ?? null;
|
|
200
|
+
const cardText = (card.textContent ?? '').replace(/\s+/g, ' ');
|
|
201
|
+
const yearMatch = cardText.match(/(\d{1,2})\s*年/);
|
|
202
|
+
const years = yearMatch ? parseInt(yearMatch[1], 10) : null;
|
|
203
|
+
const turnover = card.querySelector('.col-desc_after .desc-text')?.textContent?.trim() ??
|
|
204
|
+
null;
|
|
205
|
+
out.push({
|
|
206
|
+
offerId,
|
|
207
|
+
title,
|
|
208
|
+
price: {
|
|
209
|
+
text: priceText.replace(/[¥¥]/g, '¥'),
|
|
210
|
+
min: priceMin,
|
|
211
|
+
max: priceMax,
|
|
212
|
+
},
|
|
213
|
+
supplier: { name: supplierName, shopUrl, years },
|
|
214
|
+
turnover,
|
|
215
|
+
url: `https://detail.m.1688.com/page/index.html?offerId=${offerId}`,
|
|
216
|
+
image,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return out;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
function printOffers(offers, keyword) {
|
|
223
|
+
if (offers.length === 0) {
|
|
224
|
+
process.stdout.write(`No offers found for "${keyword}".\n`);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const w = String(offers.length).length;
|
|
228
|
+
offers.forEach((o, i) => {
|
|
229
|
+
const idx = String(i + 1).padStart(w, ' ');
|
|
230
|
+
const price = o.price.text || '(n/a)';
|
|
231
|
+
process.stdout.write(`${idx}. ${o.title}\n`);
|
|
232
|
+
const pad = ' '.repeat(w + 2);
|
|
233
|
+
process.stdout.write(`${pad}${price}`);
|
|
234
|
+
if (o.turnover)
|
|
235
|
+
process.stdout.write(` · ${o.turnover}`);
|
|
236
|
+
process.stdout.write('\n');
|
|
237
|
+
const supBits = [
|
|
238
|
+
o.supplier.name,
|
|
239
|
+
o.supplier.years ? `${o.supplier.years}年` : null,
|
|
240
|
+
]
|
|
241
|
+
.filter(Boolean)
|
|
242
|
+
.join(' · ');
|
|
243
|
+
if (supBits)
|
|
244
|
+
process.stdout.write(`${pad}${supBits}\n`);
|
|
245
|
+
process.stdout.write(`${pad}${o.url}\n`);
|
|
246
|
+
if (i < offers.length - 1)
|
|
247
|
+
process.stdout.write('\n');
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { dispatch } from '../session/dispatch.js';
|
|
2
|
+
import { emit, info } from '../io/output.js';
|
|
3
|
+
import { CliError } from '../io/errors.js';
|
|
4
|
+
import { readState } from '../session/state.js';
|
|
5
|
+
const IM_BASE = 'https://air.1688.com/app/ocms-fusion-components-1688/def_cbu_web_im/index.html';
|
|
6
|
+
export async function execute(ctx, args) {
|
|
7
|
+
if (!args.message || !args.myLoginId || !args.searchNames?.length) {
|
|
8
|
+
throw new CliError(2, 'BAD_INPUT', 'myLoginId, searchNames, and message are required.');
|
|
9
|
+
}
|
|
10
|
+
if (args.message.length > 500) {
|
|
11
|
+
throw new CliError(2, 'BAD_INPUT', 'Message too long (max 500 chars).');
|
|
12
|
+
}
|
|
13
|
+
const page = await ctx.newPage();
|
|
14
|
+
try {
|
|
15
|
+
// Build URL using 1688's "联系卖家" pattern:
|
|
16
|
+
// touid=cnalichn<loginId> (cnalichn prefix is required)
|
|
17
|
+
// siteid=cnalichn
|
|
18
|
+
// status=1
|
|
19
|
+
// orderId / offerId (server uses these to scope/create conversation)
|
|
20
|
+
// #/
|
|
21
|
+
//
|
|
22
|
+
// Without proper scope params, 1688 won't create the conversation
|
|
23
|
+
// server-side and the chat shows "您尚未选择联系人".
|
|
24
|
+
let url;
|
|
25
|
+
if (args.sellerLoginId && (args.orderId || args.offerId)) {
|
|
26
|
+
url =
|
|
27
|
+
`${IM_BASE}?` +
|
|
28
|
+
`touid=cnalichn${encodeURIComponent(args.sellerLoginId)}` +
|
|
29
|
+
`&siteid=cnalichn` +
|
|
30
|
+
`&status=1` +
|
|
31
|
+
`&portalId=` +
|
|
32
|
+
`&gid=` +
|
|
33
|
+
`&offerId=${args.offerId ? encodeURIComponent(args.offerId) : ''}` +
|
|
34
|
+
`&itemsId=` +
|
|
35
|
+
`&orderId=${args.orderId ? encodeURIComponent(args.orderId) : ''}` +
|
|
36
|
+
`#/`;
|
|
37
|
+
const scope = args.orderId
|
|
38
|
+
? `orderId=${args.orderId}`
|
|
39
|
+
: `offerId=${args.offerId}`;
|
|
40
|
+
info(`Opening 旺旺 (scoped: ${scope})...`);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
url = `${IM_BASE}?fromid=cnalichn${encodeURIComponent(args.myLoginId)}`;
|
|
44
|
+
info('Opening 旺旺 IM (sidebar mode)...');
|
|
45
|
+
}
|
|
46
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
47
|
+
if (/login\.1688\.com|login\.taobao\.com/.test(page.url())) {
|
|
48
|
+
throw new CliError(3, 'NOT_LOGGED_IN', 'Session expired. Run `1688 login`.');
|
|
49
|
+
}
|
|
50
|
+
const imFrame = page.frameLocator('iframe[src*="def_cbu_web_im_core"]');
|
|
51
|
+
const input = imFrame.locator('pre.edit[contenteditable="true"]').first();
|
|
52
|
+
try {
|
|
53
|
+
await input.waitFor({ state: 'visible', timeout: 20000 });
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
throw new CliError(22, 'CHAT_NOT_LOADED', 'Failed to open 旺旺 IM (page never loaded chat input).');
|
|
57
|
+
}
|
|
58
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
59
|
+
// If scoped URL (order/offer) was used, conversation should auto-activate.
|
|
60
|
+
// Otherwise (sidebar mode), find + click the seller in sidebar.
|
|
61
|
+
let matchedName = null;
|
|
62
|
+
if (args.sellerLoginId && (args.orderId || args.offerId)) {
|
|
63
|
+
// Scoped — wait for auto-activation
|
|
64
|
+
matchedName = args.searchNames[0] ?? args.sellerLoginId;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
info(`Searching sidebar for: ${args.searchNames.join(' / ')}`);
|
|
68
|
+
for (const name of args.searchNames) {
|
|
69
|
+
if (!name)
|
|
70
|
+
continue;
|
|
71
|
+
const item = imFrame.locator(`text=${name}`).first();
|
|
72
|
+
const visible = await item
|
|
73
|
+
.isVisible({ timeout: 2000 })
|
|
74
|
+
.catch(() => false);
|
|
75
|
+
if (visible) {
|
|
76
|
+
info(`Found "${name}" in sidebar; clicking...`);
|
|
77
|
+
await item.click({ force: true });
|
|
78
|
+
matchedName = name;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!matchedName) {
|
|
83
|
+
throw new CliError(29, 'SELLER_NOT_IN_SIDEBAR', `Seller not found in 旺旺 conversation list (tried: ${args.searchNames
|
|
84
|
+
.filter(Boolean)
|
|
85
|
+
.join(', ')}). Use an orderId-based call so we can pass orderId to ` +
|
|
86
|
+
'auto-activate the conversation.');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Wait for the conversation to actually activate (right pane no longer empty).
|
|
90
|
+
const activated = await page
|
|
91
|
+
.waitForFunction(() => {
|
|
92
|
+
const iframe = document.querySelector('iframe[src*="def_cbu_web_im_core"]');
|
|
93
|
+
const body = iframe?.contentDocument?.body?.innerText ?? '';
|
|
94
|
+
return !/您尚未选择联系人/.test(body) && body.length > 50;
|
|
95
|
+
}, { timeout: 25000 })
|
|
96
|
+
.then(() => true)
|
|
97
|
+
.catch(() => false);
|
|
98
|
+
if (!activated) {
|
|
99
|
+
throw new CliError(26, 'CONVERSATION_NOT_SELECTED', `Conversation panel did not activate for ${matchedName}. ` +
|
|
100
|
+
(args.orderId
|
|
101
|
+
? `OrderId ${args.orderId} was passed but conversation never opened.`
|
|
102
|
+
: 'Sidebar click did not switch to conversation.'));
|
|
103
|
+
}
|
|
104
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
105
|
+
// 4. Type the message and send.
|
|
106
|
+
info(`Typing message (${args.message.length} chars)...`);
|
|
107
|
+
await input.click({ force: true });
|
|
108
|
+
await input.fill('');
|
|
109
|
+
await page.keyboard.type(args.message, { delay: 20 });
|
|
110
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
111
|
+
info('Sending...');
|
|
112
|
+
await imFrame
|
|
113
|
+
.locator('button.send-btn:has-text("发送")')
|
|
114
|
+
.first()
|
|
115
|
+
.click({ force: true });
|
|
116
|
+
// 5. Verify: input clears OR message appears in chat body
|
|
117
|
+
const sentAt = new Date().toISOString();
|
|
118
|
+
const sent = await page
|
|
119
|
+
.waitForFunction((msg) => {
|
|
120
|
+
const iframe = document.querySelector('iframe[src*="def_cbu_web_im_core"]');
|
|
121
|
+
const doc = iframe?.contentDocument;
|
|
122
|
+
if (!doc)
|
|
123
|
+
return false;
|
|
124
|
+
const edit = doc.querySelector('pre.edit[contenteditable="true"]');
|
|
125
|
+
const editText = (edit?.innerText ?? '').replace(/\s+/g, '');
|
|
126
|
+
if (editText.length === 0)
|
|
127
|
+
return true;
|
|
128
|
+
const body = doc.body?.innerText ?? '';
|
|
129
|
+
return body.includes(msg);
|
|
130
|
+
}, args.message, { timeout: 10000 })
|
|
131
|
+
.then(() => true)
|
|
132
|
+
.catch(() => false);
|
|
133
|
+
if (!sent) {
|
|
134
|
+
throw new CliError(24, 'SEND_UNCONFIRMED', 'Send clicked but neither input cleared nor message appeared in scrollback.');
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
ok: true,
|
|
138
|
+
sentTo: matchedName,
|
|
139
|
+
message: args.message,
|
|
140
|
+
sentAt,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
await page.close().catch(() => { });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export async function run(opts) {
|
|
148
|
+
if (!opts.message) {
|
|
149
|
+
throw new CliError(2, 'BAD_INPUT', 'Message is required.');
|
|
150
|
+
}
|
|
151
|
+
if (!opts.message.trim()) {
|
|
152
|
+
throw new CliError(2, 'BAD_INPUT', 'Message cannot be empty.');
|
|
153
|
+
}
|
|
154
|
+
if (!opts.target) {
|
|
155
|
+
throw new CliError(2, 'BAD_INPUT', 'Provide an orderId or seller name as target.');
|
|
156
|
+
}
|
|
157
|
+
const state = await readState();
|
|
158
|
+
if (!state.nick) {
|
|
159
|
+
throw new CliError(3, 'NOT_LOGGED_IN', 'Cannot determine your loginId. Run `1688 whoami` first.');
|
|
160
|
+
}
|
|
161
|
+
const myLoginId = state.nick;
|
|
162
|
+
// For orderId target: look up seller; by default also send the order detail
|
|
163
|
+
// URL as a first message (1688 IM auto-renders it as an order card).
|
|
164
|
+
// --no-card skips the card (use for follow-up replies).
|
|
165
|
+
// For loginId target: just send the text (sidebar mode).
|
|
166
|
+
let baseArgs;
|
|
167
|
+
let sendCard = false;
|
|
168
|
+
let finalMessage = opts.message;
|
|
169
|
+
if (/^\d+$/.test(opts.target)) {
|
|
170
|
+
info(`Looking up seller for order ${opts.target}...`);
|
|
171
|
+
const order = await dispatch('order-get', { orderId: opts.target, maxScanPages: 5 }, { headed: opts.headed, profile: opts.profile });
|
|
172
|
+
if (!order.seller.loginId) {
|
|
173
|
+
throw new CliError(12, 'SELLER_NOT_FOUND', `Order ${opts.target} has no seller loginId.`);
|
|
174
|
+
}
|
|
175
|
+
baseArgs = {
|
|
176
|
+
searchNames: [order.seller.loginId, order.seller.name].filter(Boolean),
|
|
177
|
+
sellerLoginId: order.seller.loginId,
|
|
178
|
+
orderId: opts.target,
|
|
179
|
+
myLoginId,
|
|
180
|
+
};
|
|
181
|
+
sendCard = !opts.noCard;
|
|
182
|
+
// Optional: --prefix adds 【订单 XXX】 in text (redundant if card sent)
|
|
183
|
+
if (opts.prefix && !finalMessage.includes(opts.target)) {
|
|
184
|
+
finalMessage = `【订单 ${opts.target}】${finalMessage}`;
|
|
185
|
+
}
|
|
186
|
+
info(`Will message: ${order.seller.name ?? order.seller.loginId}`);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
baseArgs = {
|
|
190
|
+
searchNames: [opts.target],
|
|
191
|
+
myLoginId,
|
|
192
|
+
};
|
|
193
|
+
info(`Will message: ${opts.target} (sidebar mode — requires existing chat)`);
|
|
194
|
+
}
|
|
195
|
+
// First, send the order URL as a separate message (auto-rendered as card).
|
|
196
|
+
if (sendCard) {
|
|
197
|
+
const orderUrl = `https://trade.1688.com/order/new_step_order_detail.htm?orderId=${opts.target}`;
|
|
198
|
+
info(`Sending message 1/2: order link card`);
|
|
199
|
+
await dispatch('seller-chat', { ...baseArgs, message: orderUrl }, { headed: opts.headed, profile: opts.profile });
|
|
200
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
201
|
+
info(`Sending message 2/2: question`);
|
|
202
|
+
}
|
|
203
|
+
const data = await dispatch('seller-chat', { ...baseArgs, message: finalMessage }, { headed: opts.headed, profile: opts.profile });
|
|
204
|
+
emit({
|
|
205
|
+
human: () => {
|
|
206
|
+
process.stdout.write(`✓ Message sent to ${data.sentTo}\n`);
|
|
207
|
+
process.stdout.write(` at: ${data.sentAt}\n`);
|
|
208
|
+
process.stdout.write(` >> ${data.message}\n`);
|
|
209
|
+
},
|
|
210
|
+
data,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=seller-chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seller-chat.js","sourceRoot":"","sources":["../../src/commands/seller-chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { dispatch } from '../session/dispatch.js';
|
|
2
|
+
import { emit, info } from '../io/output.js';
|
|
3
|
+
import { CliError } from '../io/errors.js';
|
|
4
|
+
import { readState } from '../session/state.js';
|
|
5
|
+
const PRODUCT_URL = (id) => `https://detail.1688.com/offer/${id}.html`;
|
|
6
|
+
export async function run(opts) {
|
|
7
|
+
if (!opts.offerId || !/^\d+$/.test(opts.offerId)) {
|
|
8
|
+
throw new CliError(2, 'BAD_INPUT', 'Valid offerId required.');
|
|
9
|
+
}
|
|
10
|
+
if (!opts.message?.trim()) {
|
|
11
|
+
throw new CliError(2, 'BAD_INPUT', 'Message cannot be empty.');
|
|
12
|
+
}
|
|
13
|
+
const state = await readState();
|
|
14
|
+
if (!state.nick) {
|
|
15
|
+
throw new CliError(3, 'NOT_LOGGED_IN', 'Cannot determine your loginId. Run `1688 whoami` first.');
|
|
16
|
+
}
|
|
17
|
+
// 1. Resolve seller loginId
|
|
18
|
+
let sellerLoginId = opts.to ?? null;
|
|
19
|
+
let sellerName = null;
|
|
20
|
+
if (!sellerLoginId) {
|
|
21
|
+
sellerLoginId = await tryFindSeller(opts.offerId, opts);
|
|
22
|
+
if (!sellerLoginId) {
|
|
23
|
+
throw new CliError(30, 'SELLER_UNKNOWN', `Cannot find seller for offer ${opts.offerId}. ` +
|
|
24
|
+
'Pass --to <sellerLoginId> explicitly, OR add the item to cart first ' +
|
|
25
|
+
`(1688 cart add ${opts.offerId} --sku ... --qty 1) so 1688 can ` +
|
|
26
|
+
'identify the seller.');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
info(`Seller: ${sellerLoginId}${sellerName ? ` (${sellerName})` : ''}`);
|
|
30
|
+
// 2. Send TWO messages — URL first (so 1688 IM can auto-render product card
|
|
31
|
+
// if it supports that for standalone links), then the question text.
|
|
32
|
+
// Pass sellerLoginId + offerId so seller-chat uses offer-scoped URL that
|
|
33
|
+
// creates the conversation server-side (works for never-chatted sellers).
|
|
34
|
+
const productUrl = PRODUCT_URL(opts.offerId);
|
|
35
|
+
const searchNames = [sellerLoginId, sellerName].filter(Boolean);
|
|
36
|
+
const chatBaseArgs = {
|
|
37
|
+
searchNames,
|
|
38
|
+
sellerLoginId,
|
|
39
|
+
offerId: opts.offerId,
|
|
40
|
+
myLoginId: state.nick,
|
|
41
|
+
};
|
|
42
|
+
info(`Sending message 1/2: product link`);
|
|
43
|
+
await dispatch('seller-chat', { ...chatBaseArgs, message: productUrl }, { headed: opts.headed, profile: opts.profile });
|
|
44
|
+
// Small pause so the 2 sends look natural (and avoid hammering)
|
|
45
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
46
|
+
info(`Sending message 2/2: question`);
|
|
47
|
+
const data = await dispatch('seller-chat', { ...chatBaseArgs, message: opts.message }, { headed: opts.headed, profile: opts.profile });
|
|
48
|
+
emit({
|
|
49
|
+
human: () => {
|
|
50
|
+
process.stdout.write(`✓ Inquiry sent to ${data.sentTo}\n`);
|
|
51
|
+
process.stdout.write(` msg 1 (link): ${productUrl}\n`);
|
|
52
|
+
process.stdout.write(` msg 2 (question): ${opts.message}\n`);
|
|
53
|
+
process.stdout.write(` at: ${data.sentAt}\n`);
|
|
54
|
+
},
|
|
55
|
+
data: { ok: true, sentTo: data.sentTo, productUrl, question: opts.message, sentAt: data.sentAt },
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Find seller's loginId for an offerId. Strategy:
|
|
60
|
+
* 1) Read window.FE_GLOBALS.offerLoginId from the product detail page (works
|
|
61
|
+
* for ALL offers — best path)
|
|
62
|
+
* 2) Fallback: cart match (if for some reason the page lookup fails)
|
|
63
|
+
*/
|
|
64
|
+
async function tryFindSeller(offerId, opts) {
|
|
65
|
+
// Primary: scrape window.FE_GLOBALS.offerLoginId from detail page
|
|
66
|
+
info(`Reading seller loginId from detail page...`);
|
|
67
|
+
try {
|
|
68
|
+
const loginId = await dispatch('detail-feglobals', { offerId }, { headed: opts.headed, profile: opts.profile });
|
|
69
|
+
if (loginId.offerLoginId) {
|
|
70
|
+
info(`Found from FE_GLOBALS: seller=${loginId.offerLoginId}`);
|
|
71
|
+
return loginId.offerLoginId;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
/* fall through */
|
|
76
|
+
}
|
|
77
|
+
// Fallback: check cart
|
|
78
|
+
info(`Looking up offer ${offerId} in cart...`);
|
|
79
|
+
try {
|
|
80
|
+
const cart = await dispatch('cart-list', {}, { headed: opts.headed, profile: opts.profile });
|
|
81
|
+
const item = cart.items.find((i) => i.offerId === offerId);
|
|
82
|
+
if (item?.seller.loginId) {
|
|
83
|
+
info(`Found in cart: seller=${item.seller.loginId}`);
|
|
84
|
+
return item.seller.loginId;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
/* ignore */
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
// Standalone executor: scrape FE_GLOBALS from offer detail page
|
|
93
|
+
export async function scrapeFeGlobals(ctx, args) {
|
|
94
|
+
const page = await ctx.newPage();
|
|
95
|
+
try {
|
|
96
|
+
await page.goto(`https://detail.1688.com/offer/${args.offerId}.html`, { waitUntil: 'domcontentloaded', timeout: 25000 });
|
|
97
|
+
// The script tag containing FE_GLOBALS is in the initial HTML, so we don't
|
|
98
|
+
// need to wait for JS to run — but a small delay helps if redirects happen.
|
|
99
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
100
|
+
const result = await page.evaluate(() => {
|
|
101
|
+
const w = window;
|
|
102
|
+
return { offerLoginId: w.FE_GLOBALS?.offerLoginId ?? null };
|
|
103
|
+
});
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
await page.close().catch(() => { });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=seller-inquire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seller-inquire.js","sourceRoot":"","sources":["../../src/commands/seller-inquire.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seller-lookup-ww.js","sourceRoot":"","sources":["../../src/commands/seller-lookup-ww.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAUtD,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAmB,EACnB,IAAwB;IAExB,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACzD,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC"}
|