@seasonkoh/webaz 0.1.12 → 0.1.14
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.
|
@@ -49,7 +49,10 @@ export function transition(db, orderId, toStatus, actorId, evidenceIds = [], not
|
|
|
49
49
|
if (rule.requiresEvidence && evidenceIds.length === 0) {
|
|
50
50
|
return {
|
|
51
51
|
success: false,
|
|
52
|
-
error:
|
|
52
|
+
error: `此操作需要证据。可任选一种方式提供:\n` +
|
|
53
|
+
`(A) 传 evidence_description(文字描述,如 "物流单号: SF1234567 / 顺丰" / "已揽收 GPS:31.2,121.5") — agent 最方便\n` +
|
|
54
|
+
`(B) 上传文件作为证据 — 提示:${rule.evidenceHint ?? '相关证明文件'}\n` +
|
|
55
|
+
`两种都会写入 evidence 表,效力等同。`
|
|
53
56
|
};
|
|
54
57
|
}
|
|
55
58
|
// 5. 执行转移(数据库事务,保证原子性)
|
|
@@ -351,7 +354,7 @@ function getActiveDeadline(order, db) {
|
|
|
351
354
|
// QA 轮 7 P1:旧表 picked_up 状态没 deadline → agent 不知道下一步多久前要做完
|
|
352
355
|
// 修:picked_up 状态视为"已揽收,等运输/投递",下一个 deadline 是 delivery_deadline
|
|
353
356
|
// QA 轮 7 P1(另一条):disputed 状态下没读 dispute_cases 的 arbitrate_deadline → agent 不知道仲裁还有多久
|
|
354
|
-
const
|
|
357
|
+
const deadlineMapMarket = {
|
|
355
358
|
created: 'pay_deadline',
|
|
356
359
|
paid: 'accept_deadline',
|
|
357
360
|
accepted: 'ship_deadline',
|
|
@@ -360,6 +363,18 @@ function getActiveDeadline(order, db) {
|
|
|
360
363
|
in_transit: 'delivery_deadline',
|
|
361
364
|
delivered: 'confirm_deadline',
|
|
362
365
|
};
|
|
366
|
+
// 2026-05-31 修:self-fulfill(logistics_id 空)无三方揽收环节,shipped/picked_up/in_transit
|
|
367
|
+
// 全部直接走 delivery_deadline,跟 CURRENT_RESPONSIBLE_SELF_FULFILL 对齐(都归 seller)。
|
|
368
|
+
// 之前 deadlineMap 单表导致 self-fulfill shipped 显示 pickup_deadline + responsible=seller,
|
|
369
|
+
// agent 看到矛盾不知道下一步(pickup 是物流的事,seller 又没物流可揽收)。
|
|
370
|
+
const deadlineMapSelfFulfill = {
|
|
371
|
+
...deadlineMapMarket,
|
|
372
|
+
shipped: 'delivery_deadline',
|
|
373
|
+
picked_up: 'delivery_deadline',
|
|
374
|
+
in_transit: 'delivery_deadline',
|
|
375
|
+
};
|
|
376
|
+
const isSelfFulfill = !order.logistics_id;
|
|
377
|
+
const deadlineMap = isSelfFulfill ? deadlineMapSelfFulfill : deadlineMapMarket;
|
|
363
378
|
// disputed 状态:从 `disputes` 表(active dispute, not the `dispute_cases` archive)查 deadline
|
|
364
379
|
// 优先返 arbitrate_deadline(仲裁总截止);如果还在 respond 窗口(被诉方未回应)返 respond_deadline
|
|
365
380
|
if (order.status === 'disputed' && db) {
|
|
@@ -214,9 +214,15 @@ Roles:
|
|
|
214
214
|
name: 'webaz_search',
|
|
215
215
|
description: `Search WebAZ marketplace + cross-platform anchor lookup. No auth required.
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
⚠️ **STRICT MATCH ONLY** — query 永远是精准匹配(等于 title / 等于 external_title / 包含 ≥6 字符 alias)。
|
|
218
|
+
不做 fuzzy LIKE 模糊降级。短查询(如 "钱包" "iphone")很大概率 0 命中,这是设计如此,不是 bug。
|
|
219
|
+
0 命中时,**不要**自己拼短词 retry,也**不要**调别的工具假装搜索;应**引导用户访问 https://webaz.xyz/#discover**
|
|
220
|
+
在搜索框输入关键词浏览(那里有 fuzzy LIKE)。模糊搜索是用户主动行为,不是 agent 代办。
|
|
221
|
+
|
|
222
|
+
USE THIS when:
|
|
223
|
+
- 用户给出 **完整商品标题 / SKU / 精准描述**(典型 strict match,如 "AirPods Pro 2 USB-C 港行"), OR
|
|
224
|
+
- 用户给出 **筛选条件**(category / max_price / min_return_days / max_handling_hours / sort), OR
|
|
225
|
+
- 用户粘贴 ANY external product URL/share-text from Taobao / Tmall / JD / PDD / 1688 / Douyin / Xiaohongshu
|
|
220
226
|
→ WebAZ exact-matches against its anchor registry (canonical product fingerprints across
|
|
221
227
|
platforms). matched_by='none' means truly not indexed — do NOT silently fall back to keyword,
|
|
222
228
|
and do NOT guess similar products.
|
|
@@ -225,7 +231,8 @@ USE THIS when the user:
|
|
|
225
231
|
NOT a separate browser-fetch capability. Returns structured specs + logistics + after-sales +
|
|
226
232
|
agent_summary (one-line decision hint).
|
|
227
233
|
|
|
228
|
-
【Keyword search】Pass query / category / max_price / min_return_days / max_handling_hours.
|
|
234
|
+
【Keyword search — STRICT】Pass query / category / max_price / min_return_days / max_handling_hours.
|
|
235
|
+
query 命中 = (1) 完全等于 product.title OR (2) 完全等于任一 external_title OR (3) 用户文本包含任一卖家声明 alias_value (≥6 字符)。模糊关键词请引导用户去 PWA #discover。
|
|
229
236
|
|
|
230
237
|
【External-link paste search】When user pastes share text from Taobao/Tmall/JD/Pinduoduo/1688/Douyin/Xiaohongshu
|
|
231
238
|
(e.g. '【淘宝】「Product Name」 https://e.tb.cn/xxx ...'), do:
|
|
@@ -279,10 +286,15 @@ Note: paste-link matching hits webaz.xyz production data, not your local webaz.d
|
|
|
279
286
|
},
|
|
280
287
|
{
|
|
281
288
|
name: 'webaz_verify_price',
|
|
282
|
-
description: `Lock product price
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
289
|
+
description: `Lock product price + reserve stock window BEFORE webaz_place_order — returns session_token.
|
|
290
|
+
|
|
291
|
+
USE THIS for EVERY purchase, not just price-sensitive ones. Reasons:
|
|
292
|
+
(1) order price matches displayed (defeats flash-sale / hidden-fee races)
|
|
293
|
+
(2) caller is alerted if price changed between view and order
|
|
294
|
+
(3) protocol only liable for T0 price
|
|
295
|
+
(4) reduces stock-depletion race on hot items (session_token is single-use within 10min)
|
|
296
|
+
|
|
297
|
+
Skipping this is allowed but the agent then carries the price/stock-race risk itself. session_token: 10-minute TTL, single-use, pass it to webaz_place_order.
|
|
286
298
|
|
|
287
299
|
──
|
|
288
300
|
中文:下单前锁价 — 10 分钟一次性 session_token;agent 应先调此再调 place_order。`,
|
|
@@ -298,8 +310,14 @@ session_token: 10-minute TTL, single-use.
|
|
|
298
310
|
},
|
|
299
311
|
{
|
|
300
312
|
name: 'webaz_list_product',
|
|
301
|
-
description:
|
|
302
|
-
|
|
313
|
+
description: `⚠️ "list" = PUBLISH (verb), NOT "list out" (noun). Seller-only product catalog publishing & management.
|
|
314
|
+
|
|
315
|
+
USE THIS when SELLER wants to:
|
|
316
|
+
- publish a NEW product to their catalog, OR
|
|
317
|
+
- update / delist / relist / trash / delete an existing product they own, OR
|
|
318
|
+
- view their OWN listings (action=mine)
|
|
319
|
+
|
|
320
|
+
NOT for browsing the marketplace — for that use webaz_search (anyone, no auth). Requires seller-role api_key. On create, system auto-suggests stake (~15% of price) to secure buyer protection.
|
|
303
321
|
|
|
304
322
|
Fill fields completely — better agent_summary helps buyer agents make comparison decisions (brand / return / handling / warranty).
|
|
305
323
|
Note: for "exclusive price vs external link" listing, use PWA Web only — link claim needs crowd-verification.
|
|
@@ -429,7 +447,9 @@ Missing any deadline auto-judges fault against the responsible party and trigger
|
|
|
429
447
|
},
|
|
430
448
|
{
|
|
431
449
|
name: 'webaz_update_order',
|
|
432
|
-
description: `
|
|
450
|
+
description: `STATUS TRANSITIONS on an order (accept / ship / pickup / deliver / confirm / dispute) — NOT for editing order content (price/quantity/address are immutable after creation).
|
|
451
|
+
|
|
452
|
+
USE THIS to advance an order through its lifecycle. Each role can only perform their own actions (see action list).
|
|
433
453
|
|
|
434
454
|
Seller actions:
|
|
435
455
|
- accept: accept order (within 24h of payment)
|
|
@@ -486,7 +506,9 @@ Returns: current status, status history (who did what when), next responsible ac
|
|
|
486
506
|
},
|
|
487
507
|
{
|
|
488
508
|
name: 'webaz_wallet',
|
|
489
|
-
description: `Wallet query (balance + earnings stats + deposit/withdrawal/income history).
|
|
509
|
+
description: `Wallet READ-ONLY query (balance + earnings stats + deposit/withdrawal/income history).
|
|
510
|
+
|
|
511
|
+
⚠️ Iron-Rule (must read before use): actual withdrawals / deposits / whitelist management require Passkey + email OTP via PWA Web only. This tool CANNOT move money — only query state. If user asks "send/withdraw/deposit WAZ", do NOT promise it via MCP; instead direct them to PWA Web.
|
|
490
512
|
|
|
491
513
|
Actions:
|
|
492
514
|
- view available balance + staked + in-escrow + total earnings + reputation tier (default)
|
|
@@ -494,9 +516,6 @@ Actions:
|
|
|
494
516
|
- withdrawals last 10 withdrawal requests (with status / tx_hash)
|
|
495
517
|
- income income breakdown: referral L1/L2/L3 + binary PV matching + sales net
|
|
496
518
|
|
|
497
|
-
NOTE: actual withdrawals / deposits / whitelist management require Passkey + email OTP via PWA Web only.
|
|
498
|
-
This is a security boundary — agents CANNOT bypass it. Use this tool for read-only queries only.
|
|
499
|
-
|
|
500
519
|
──
|
|
501
520
|
中文:钱包查询(余额/收益/充提历史)。仅查询用,实际充提需 PWA Web + Passkey + 邮件 OTP,agent 不可绕过。`,
|
|
502
521
|
inputSchema: {
|
|
@@ -532,7 +551,12 @@ Every status change (new order / ship / dispute / etc.) notifies relevant partic
|
|
|
532
551
|
},
|
|
533
552
|
{
|
|
534
553
|
name: 'webaz_dispute',
|
|
535
|
-
description: `Manage dispute lifecycle (L3 dispute system).
|
|
554
|
+
description: `Manage ORDER-DELIVERY dispute lifecycle (L3 dispute system, central arbitrator).
|
|
555
|
+
|
|
556
|
+
⚠️ Different from webaz_claim_verify:
|
|
557
|
+
- webaz_dispute = order delivery problem (didn't arrive / wrong / damaged in transit / seller fraud) → central arbitrator + 120h ruling
|
|
558
|
+
- webaz_claim_verify = challenge a product CLAIM (brand / spec / ship time) → 3 crowd verifiers vote
|
|
559
|
+
Pick based on the actual problem: delivery/receiving = dispute; marketing-claim accuracy = claim_verify.
|
|
536
560
|
|
|
537
561
|
When buyer claims item-not-as-described / damaged / seller fraud, first raise dispute via webaz_update_order action=dispute,
|
|
538
562
|
then use this tool for follow-ups.
|
|
@@ -601,7 +625,12 @@ view / list_open / respond / add_evidence can be agent-proxied; only arbitrate n
|
|
|
601
625
|
},
|
|
602
626
|
{
|
|
603
627
|
name: 'webaz_claim_verify',
|
|
604
|
-
description: `Crowd-sourced
|
|
628
|
+
description: `Crowd-sourced PRODUCT-CLAIM verification — challenge seller's marketing claims (brand / spec / ship time / authenticity); 3 eligible verifiers reach consensus by vote.
|
|
629
|
+
|
|
630
|
+
⚠️ Different from webaz_dispute:
|
|
631
|
+
- webaz_claim_verify = challenge a CLAIM about the product itself ("seller said 24h ship but didn't" / "said brand new but used")
|
|
632
|
+
- webaz_dispute = order-delivery problem (didn't arrive / arrived broken / wrong item) → central arbitrator
|
|
633
|
+
If unsure: did the buyer GET the item? If yes + problem with item itself → claim_verify. If no/damaged in transit → dispute.
|
|
605
634
|
|
|
606
635
|
When to use:
|
|
607
636
|
- Buyer: suspects a seller's product claim (e.g. "brand new sealed", "ships within 24h") → wants decentralized verification
|
|
@@ -670,12 +699,14 @@ Other actions (create / view / mine / available / eligibility / apply / appeal e
|
|
|
670
699
|
},
|
|
671
700
|
{
|
|
672
701
|
name: 'webaz_skill',
|
|
673
|
-
description: `L4-4 Skill marketplace — sellers publish reusable seller-side
|
|
702
|
+
description: `L4-4 Skill marketplace — sellers publish reusable seller-side BEHAVIOUR configs; buyer Agents subscribe with one click.
|
|
674
703
|
|
|
675
704
|
USE THIS when:
|
|
676
705
|
- seller wants to install reusable selling behavior (auto-accept / catalog-sync / price-haggling / etc.), OR
|
|
677
706
|
- buyer agent wants to subscribe to seller's behaviour to enable priority discovery / auto-deal flows.
|
|
678
|
-
|
|
707
|
+
|
|
708
|
+
NOT a product search — for "find me X" use webaz_search.
|
|
709
|
+
NOT a KNOWLEDGE-content marketplace — for buying/selling templates / prompts / guides / checklists use webaz_skill_market (totally separate system, independent revenue flow).
|
|
679
710
|
|
|
680
711
|
⚠️ Important — Skill is NOT executable code distribution. There are exactly 5 typed Skill kinds (below), each accepts only **structured config parameters** (numbers / enums / amounts). There is NO path for an Agent to download and run arbitrary third-party code via this marketplace. Subscribing = setting a flag + data binding, not installing a plugin. (Common Web2 "plugin marketplace" risk model does NOT apply here.)
|
|
681
712
|
|
|
@@ -731,7 +762,9 @@ Actions:
|
|
|
731
762
|
},
|
|
732
763
|
{
|
|
733
764
|
name: 'webaz_mykey',
|
|
734
|
-
description: `
|
|
765
|
+
description: `Account RECOVERY check — confirm account existence by handle + permanent_code when user has lost their api_key but still remembers handle + 6-char recovery code from registration. Returns redacted api_key hint only — full api_key disclosure requires PWA + Passkey verification (Iron-Rule).
|
|
766
|
+
|
|
767
|
+
USE THIS ONLY when user has lost api_key and provides handle + permanent_code. NOT for "show me my api_key" (you already have it if you're authenticated). NOT for looking up other users (use webaz_profile).
|
|
735
768
|
|
|
736
769
|
Rate-limited: 5 attempts per handle per hour. Excessive failures lock the handle for 1 hour.
|
|
737
770
|
|
|
@@ -798,13 +831,15 @@ Public-profile actions:
|
|
|
798
831
|
},
|
|
799
832
|
{
|
|
800
833
|
name: 'webaz_revoke_key',
|
|
801
|
-
description: `Initiate api_key revocation. Iron-Rule: actual revocation requires PWA + Passkey confirmation — MCP only registers the intent and returns the PWA URL where you finish the action.
|
|
834
|
+
description: `Initiate api_key revocation (NO REPLACEMENT — old key dies, no new one issued). Iron-Rule: actual revocation requires PWA + Passkey confirmation — MCP only registers the intent and returns the PWA URL where you finish the action.
|
|
802
835
|
|
|
803
|
-
|
|
804
|
-
- Your api_key was leaked or you suspect unauthorized access
|
|
805
|
-
- You are decommissioning an agent / device
|
|
836
|
+
⚠️ STRONG RECOMMENDATION: use webaz_rotate_key instead unless you intentionally want zero replacement (e.g. fully decommissioning the agent / device). Rotate = atomic swap (no access gap). Revoke = death + you re-register from scratch.
|
|
806
837
|
|
|
807
|
-
|
|
838
|
+
Use revoke (not rotate) when:
|
|
839
|
+
- You are PERMANENTLY decommissioning this agent / device, OR
|
|
840
|
+
- You want all access to die NOW with no fallback
|
|
841
|
+
|
|
842
|
+
After PWA confirmation, the old api_key returns 401 on all tools.
|
|
808
843
|
|
|
809
844
|
──
|
|
810
845
|
中文:发起 api_key 吊销。Iron-Rule:真正吊销必须 PWA + Passkey 二次确认(agent 不能单方面执行不可逆操作)。MCP 仅登记意图,返回 PWA 确认 URL。`,
|
|
@@ -943,7 +978,16 @@ to my address" — use webaz_search ship_to filter.`,
|
|
|
943
978
|
},
|
|
944
979
|
{
|
|
945
980
|
name: 'webaz_shareables',
|
|
946
|
-
description:
|
|
981
|
+
description: `Bind your EXTERNAL content (YouTube / TikTok / 小红书 / B站 / IG / Twitter posts) to a WebAZ product — turns your content into a referral-earning channel. WebAZ indexes only the URL, never the content bytes.
|
|
982
|
+
|
|
983
|
+
USE THIS when:
|
|
984
|
+
- creator/user wants to "anchor" their existing review/unboxing/recommendation video/post to a WebAZ product (or anchor) so future buyers clicking that content → registration / purchase counts toward THEIR referral commission, OR
|
|
985
|
+
- agent wants to look up "what external content is associated with this product / this anchor"
|
|
986
|
+
|
|
987
|
+
Differs from webaz_share_link (which generates a NEW short link for sharing) — shareables register your EXISTING content as the discovery surface.
|
|
988
|
+
|
|
989
|
+
──
|
|
990
|
+
中文:把你在 YouTube/TikTok/小红书/B站/IG/Twitter 已发的内容(测评/开箱/推荐)锚定到 WebAZ 商品 —— 让你的外部内容变成赚 referral 佣金的入口。WebAZ 只锚 URL,不取内容。区别于 webaz_share_link(那个是生成新短链)。`,
|
|
947
991
|
inputSchema: {
|
|
948
992
|
type: 'object',
|
|
949
993
|
properties: {
|
|
@@ -1016,7 +1060,10 @@ Shipping address: if omitted, falls back to webaz_default_address (set via that
|
|
|
1016
1060
|
},
|
|
1017
1061
|
{
|
|
1018
1062
|
name: 'webaz_bid',
|
|
1019
|
-
description: `Bid on RFQs (seller-side).
|
|
1063
|
+
description: `Bid on RFQs (seller-side, Request-for-Quotation).
|
|
1064
|
+
|
|
1065
|
+
USE THIS ONLY for RFQ bidding (when a buyer posted demand via webaz_rfq and you want to quote). For AUCTION bidding (English forward auction on a listed item) use webaz_auction action=bid — they are separate systems with different economics (RFQ has bid stake; auction has min_increment + sniper extension).
|
|
1066
|
+
|
|
1020
1067
|
Actions:
|
|
1021
1068
|
- submit: new bid; needs rfq_id + price + qty_offered + fulfillment_type; optional eta_hours/note
|
|
1022
1069
|
- patch: edit price/ETA/fulfillment/note (only active; stake delta auto-settled)
|
|
@@ -1044,7 +1091,9 @@ Actions:
|
|
|
1044
1091
|
},
|
|
1045
1092
|
{
|
|
1046
1093
|
name: 'webaz_chat',
|
|
1047
|
-
description: `
|
|
1094
|
+
description: `Relay buyer↔seller (or RFQ partner) MESSAGES — context-bound DM, no open DM. Only order / rfq / listing_qa contexts allowed.
|
|
1095
|
+
|
|
1096
|
+
USE THIS when the user wants to communicate with the OTHER PARTY of a trade (e.g. "ask seller about return", "tell buyer about shipping delay", "answer Q&A on my listing"). NOT a general LLM chat — every message attaches to an order/rfq/listing_qa context. If the user just wants to chat with YOU (the agent), don't call this tool.
|
|
1048
1097
|
Actions:
|
|
1049
1098
|
- start: open conversation — needs kind + context_id (for rfq, also recipient_id)
|
|
1050
1099
|
- list: my conversation list
|
|
@@ -1108,7 +1157,14 @@ Returns insufficient_data:true when data sparse.
|
|
|
1108
1157
|
},
|
|
1109
1158
|
{
|
|
1110
1159
|
name: 'webaz_charity',
|
|
1111
|
-
description: `Charity
|
|
1160
|
+
description: `Charity WISH POOL + repayment + community FUND — double-anonymous + dual-signed anchoring + isolated prestige.
|
|
1161
|
+
|
|
1162
|
+
USE THIS when:
|
|
1163
|
+
- user wants to publish a "wish" (need help with money/service) for community fulfillment, OR
|
|
1164
|
+
- user wants to claim/fulfill someone else's wish, OR
|
|
1165
|
+
- user wants to donate to / browse the community charity fund (separate from per-order donation).
|
|
1166
|
+
|
|
1167
|
+
NOT for per-order charity donation — that's handled by webaz_place_order's donation_pct param (0.5% / 1% / 2% / 5% sent to charity_fund at order time). This tool is for the standalone wish-fulfillment economy.
|
|
1112
1168
|
Actions:
|
|
1113
1169
|
- list: browse public wishes (filter by category/target_kind; anonymous accessible)
|
|
1114
1170
|
- detail: single wish details (commit_hash + fulfillment + repayments)
|
|
@@ -1273,6 +1329,8 @@ Actions:
|
|
|
1273
1329
|
{
|
|
1274
1330
|
name: 'webaz_auto_bid',
|
|
1275
1331
|
description: `Seller auto_bid Skill config — auto-quote on RFQ creation instantly.
|
|
1332
|
+
|
|
1333
|
+
USE THIS as a shortcut equivalent to webaz_skill install kind=auto_bid + ongoing config edits. Dedicated tool because auto_bid is the most-used Skill and needs frequent param tuning (max_eta_h / undercut_pct / daily_cap). For other Skill kinds use webaz_skill directly.
|
|
1276
1334
|
Actions:
|
|
1277
1335
|
- get: read current Skill config
|
|
1278
1336
|
- set: create/update Skill (needs categories[] / regions[] / max_eta_h / bid_strategy etc.)
|
|
@@ -1738,7 +1796,12 @@ async function handleSearch(args) {
|
|
|
1738
1796
|
params.push(Math.min(limit * 3, 500)); // 取更多候选,便于 trending 排序
|
|
1739
1797
|
const products = db.prepare(sql).all(...params);
|
|
1740
1798
|
if (products.length === 0) {
|
|
1741
|
-
|
|
1799
|
+
// query 模式 0 命中 = strict 精准匹配未命中。**不做 fuzzy fallback**(协议精准承诺)。
|
|
1800
|
+
// 引导用户去 PWA 发现页做模糊搜索;agent 不应自己 LIKE 降级,那会污染精准 trust。
|
|
1801
|
+
const hint = query
|
|
1802
|
+
? `精准匹配 0 命中(query='${String(query).slice(0, 40)}')。webaz_search 是协议精准接口,不做模糊降级。要做模糊搜索请引导用户访问 https://webaz.xyz/#discover ,在搜索框输入关键词浏览 — 这是用户主动操作,不是 agent 代办。`
|
|
1803
|
+
: '没有找到匹配的商品';
|
|
1804
|
+
return { found: 0, message: hint, products: [], matched_by: 'strict_no_match' };
|
|
1742
1805
|
}
|
|
1743
1806
|
const enriched = products.map((p) => {
|
|
1744
1807
|
const boost = getSearchBoost(db, p.seller_id);
|
package/dist/pwa/public/app.js
CHANGED
|
@@ -420,6 +420,10 @@ async function apiWithStatus(method, path, body) {
|
|
|
420
420
|
const opts = {
|
|
421
421
|
method,
|
|
422
422
|
headers: { 'Content-Type': 'application/json', ...(state.apiKey ? { Authorization: `Bearer ${state.apiKey}` } : {}) },
|
|
423
|
+
// 2026-05-31 修:boot 阶段 fetch 必须有 timeout,否则服务挂时 render 永远 await,
|
|
424
|
+
// skeleton "正在恢复登录..." 永不替换 = PWA 刷新卡死。10s 后强制 abort → catch → status=0 →
|
|
425
|
+
// 命中已有的"无法连接+重试"兜底 UI(render 530-548)。
|
|
426
|
+
signal: AbortSignal.timeout(10000),
|
|
423
427
|
}
|
|
424
428
|
if (body) opts.body = JSON.stringify(body)
|
|
425
429
|
try {
|
|
@@ -427,7 +431,7 @@ async function apiWithStatus(method, path, body) {
|
|
|
427
431
|
const json = await res.json().catch(() => ({}))
|
|
428
432
|
return { status: res.status, body: json }
|
|
429
433
|
} catch {
|
|
430
|
-
return { status: 0, body: { error: 'network' } } // 0 =
|
|
434
|
+
return { status: 0, body: { error: 'network' } } // 0 = 网络不可达或超时,保留 key 等下次
|
|
431
435
|
}
|
|
432
436
|
}
|
|
433
437
|
|
|
@@ -10600,22 +10604,25 @@ async function initShareCtx() {
|
|
|
10600
10604
|
}
|
|
10601
10605
|
|
|
10602
10606
|
// Enrich:并发 fetch sponsor 公开卡 + target 预览(阻塞返回,确保 banner 渲染时数据齐)
|
|
10607
|
+
// 2026-05-31 修:每个 fetch 加 AbortSignal.timeout(5000),防 boot 阶段任一 fetch hang
|
|
10608
|
+
// 把 render 卡死在"正在恢复登录..."
|
|
10609
|
+
const sig = () => ({ signal: AbortSignal.timeout(5000) })
|
|
10603
10610
|
const fetches = []
|
|
10604
10611
|
if (ctx.sponsor_id && !ctx.sponsor_name) {
|
|
10605
|
-
fetches.push(fetch(`/api/users/${ctx.sponsor_id}/public-card
|
|
10612
|
+
fetches.push(fetch(`/api/users/${ctx.sponsor_id}/public-card`, sig()).then(r => r.json()).then(card => {
|
|
10606
10613
|
if (card?.name) writeShareCtx({ sponsor_name: card.name, sponsor_bio: card.bio, sponsor_joined_days_ago: card.joined_days_ago })
|
|
10607
10614
|
}).catch(() => {}))
|
|
10608
10615
|
}
|
|
10609
10616
|
if (ctx.target_hash && !ctx.target_preview) {
|
|
10610
10617
|
const m = ctx.target_hash.match(/^#order-product\/(.+)$/)
|
|
10611
10618
|
if (m) {
|
|
10612
|
-
fetches.push(fetch(`/api/products/${m[1]}/preview
|
|
10619
|
+
fetches.push(fetch(`/api/products/${m[1]}/preview`, sig()).then(r => r.json()).then(p => {
|
|
10613
10620
|
if (p?.id) writeShareCtx({ target_kind: 'product', target_preview: p })
|
|
10614
10621
|
}).catch(() => {}))
|
|
10615
10622
|
} else if (ctx.target_hash.startsWith('#u/')) {
|
|
10616
10623
|
const uid = ctx.target_hash.slice(3)
|
|
10617
10624
|
if (/^usr_[A-Za-z0-9_]+$/.test(uid)) {
|
|
10618
|
-
fetches.push(fetch(`/api/users/${uid}/public-card
|
|
10625
|
+
fetches.push(fetch(`/api/users/${uid}/public-card`, sig()).then(r => r.json()).then(p => {
|
|
10619
10626
|
if (p?.id) writeShareCtx({ target_kind: 'user', target_preview: p })
|
|
10620
10627
|
}).catch(() => {}))
|
|
10621
10628
|
}
|
package/dist/pwa/public/sw.js
CHANGED
package/dist/pwa/server.js
CHANGED
|
@@ -126,6 +126,8 @@ import { registerExternalAnchorsRoutes } from './routes/external-anchors.js';
|
|
|
126
126
|
import { registerAnchorsRoutes } from './routes/anchors.js';
|
|
127
127
|
// 仲裁员申请 (#1013 Phase 44) — 4 user + 3 admin endpoints
|
|
128
128
|
import { registerArbitratorRoutes } from './routes/arbitrator.js';
|
|
129
|
+
// 卖家配额 + 数据中心 (#1013 Phase 45) — 4 user + 3 admin
|
|
130
|
+
import { registerSellerQuotaRoutes } from './routes/seller-quota.js';
|
|
129
131
|
// 验证员用户侧 (#1013 Phase 46) — 5 endpoints
|
|
130
132
|
import { registerVerifierUserRoutes } from './routes/verifier-user.js';
|
|
131
133
|
// 公开用户主页 (#1013 Phase 47) — 6 endpoints
|
|
@@ -7257,6 +7259,13 @@ registerOrdersCreateRoutes(app, {
|
|
|
7257
7259
|
signPassport: (message) => privateKeyToAccount(derivePrivKey('platform-hot-wallet')).signMessage({ message }),
|
|
7258
7260
|
issuerAddress: () => privateKeyToAddress(derivePrivKey('platform-hot-wallet')),
|
|
7259
7261
|
});
|
|
7262
|
+
// #1013 Phase 45: 卖家配额 + 数据中心 7 endpoints — 2026-05-31 修补:之前 import 了但忘了 register,
|
|
7263
|
+
// 导致 /api/seller/quota-status + /api/seller/insights 落入 SPA fallback 返回 HTML,前端 JSON.parse 死循环
|
|
7264
|
+
registerSellerQuotaRoutes(app, {
|
|
7265
|
+
db, generateId, auth,
|
|
7266
|
+
requireUsersAdmin: (req, res) => requireAdminPermission(req, res, 'users'),
|
|
7267
|
+
safeRoles, checkSellerCanList, adminCanOperateOn, logAdminAction, QUOTA_TIERS,
|
|
7268
|
+
});
|
|
7260
7269
|
// #1013 Phase 86: 5 disputes 读端点已迁出
|
|
7261
7270
|
registerDisputesReadRoutes(app, {
|
|
7262
7271
|
db, auth, errorRes,
|
package/package.json
CHANGED