@lofder/dsers-mcp-product 1.4.0 → 1.5.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/CHANGELOG.md +71 -0
- package/README.md +64 -7
- package/dist/auth/oauth.js +1 -1
- package/dist/auth/oauth.js.map +1 -1
- package/dist/cli.js +0 -0
- package/dist/dsers/auth.d.ts.map +1 -1
- package/dist/dsers/auth.js +17 -2
- package/dist/dsers/auth.js.map +1 -1
- package/dist/dsers/client.d.ts +9 -1
- package/dist/dsers/client.d.ts.map +1 -1
- package/dist/dsers/client.js +18 -2
- package/dist/dsers/client.js.map +1 -1
- package/dist/dsers/product.d.ts +56 -0
- package/dist/dsers/product.d.ts.map +1 -1
- package/dist/dsers/product.js +64 -0
- package/dist/dsers/product.js.map +1 -1
- package/dist/dsers/retry.d.ts +59 -0
- package/dist/dsers/retry.d.ts.map +1 -0
- package/dist/dsers/retry.js +214 -0
- package/dist/dsers/retry.js.map +1 -0
- package/dist/error-map.d.ts.map +1 -1
- package/dist/error-map.js +15 -3
- package/dist/error-map.js.map +1 -1
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +11 -1
- package/dist/instructions.js.map +1 -1
- package/dist/logger.d.ts +55 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +122 -0
- package/dist/logger.js.map +1 -0
- package/dist/provider/sku-matcher.d.ts +154 -0
- package/dist/provider/sku-matcher.d.ts.map +1 -0
- package/dist/provider/sku-matcher.js +1175 -0
- package/dist/provider/sku-matcher.js.map +1 -0
- package/dist/service/index.d.ts +2 -0
- package/dist/service/index.d.ts.map +1 -1
- package/dist/service/index.js +7 -0
- package/dist/service/index.js.map +1 -1
- package/dist/service/preview.d.ts +1 -1
- package/dist/service/preview.d.ts.map +1 -1
- package/dist/service/preview.js +48 -21
- package/dist/service/preview.js.map +1 -1
- package/dist/service/sku-mapping.d.ts +674 -0
- package/dist/service/sku-mapping.d.ts.map +1 -0
- package/dist/service/sku-mapping.js +1879 -0
- package/dist/service/sku-mapping.js.map +1 -0
- package/dist/tools.d.ts +3 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +322 -2
- package/dist/tools.js.map +1 -1
- package/package.json +5 -2
- package/dist/auth/cdp-session.d.ts +0 -6
- package/dist/auth/cdp-session.d.ts.map +0 -1
- package/dist/auth/cdp-session.js +0 -369
- package/dist/auth/cdp-session.js.map +0 -1
- package/dist/auth/safari-fallback.d.ts +0 -7
- package/dist/auth/safari-fallback.d.ts.map +0 -1
- package/dist/auth/safari-fallback.js +0 -73
- package/dist/auth/safari-fallback.js.map +0 -1
- package/dist/auth/terminal-prompt.d.ts +0 -6
- package/dist/auth/terminal-prompt.d.ts.map +0 -1
- package/dist/auth/terminal-prompt.js +0 -118
- package/dist/auth/terminal-prompt.js.map +0 -1
- package/dist/provider.d.ts +0 -90
- package/dist/provider.d.ts.map +0 -1
- package/dist/provider.js +0 -1577
- package/dist/provider.js.map +0 -1
- package/dist/service/browse.d.ts +0 -20
- package/dist/service/browse.d.ts.map +0 -1
- package/dist/service/browse.js +0 -159
- package/dist/service/browse.js.map +0 -1
- package/dist/service.d.ts +0 -27
- package/dist/service.d.ts.map +0 -1
- package/dist/service.js +0 -949
- package/dist/service.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.5.0 — 2026-04-10
|
|
4
|
+
|
|
5
|
+
大版本。这版终于把换供应商这件事搞定了。
|
|
6
|
+
|
|
7
|
+
### 新工具:`dsers_sku_remap`
|
|
8
|
+
|
|
9
|
+
背景是之前一直有一个绕不过去的场景 —— 老供应商涨价 / 断货 / 被封了,你想换一个新的。DSers 后台手动点也能换,但是每个变体每个变体点下去非常反人类,更不用说你要把 seller 的 variant 精确对应到新 supplier 的哪个 SKU。我之前做了一个单独的 sku-matcher 引擎(用 option 对齐 + 单位规范化 + 同义词表 + dHash 图像相似度做打分),原本是内部工具,这一版整个搬进 MCP 接口,让 AI agent 可以一句话完成整个替换。
|
|
10
|
+
|
|
11
|
+
用法:
|
|
12
|
+
|
|
13
|
+
- **STRICT 模式**: 你已经有了新供应商的 URL,直接传 `new_supplier_url`,工具用 sku-matcher 对齐两边的 variant,按 `auto_confidence` 阈值决定哪些自动换、哪些保留老的、哪些标记 unmatched 让你手动决定
|
|
14
|
+
- **DISCOVER 模式**: 你只知道"这个供应商不能用了,帮我找一个替代",不传 URL,工具反向图搜 DSers 池,按 `sku 分 + 图搜频次 + 商品评分 + 店铺评分 + 价格接近度 + 库存 + 订单数` 的多因子公式打分排序,自动挑最好的候选
|
|
15
|
+
|
|
16
|
+
两种模式都是两步走:永远先 `mode='preview'`(只读)看 `diffs` 和 `pool_additions`,确认没问题再 `mode='apply'` 真正写入。
|
|
17
|
+
|
|
18
|
+
几个关键设计决定:
|
|
19
|
+
|
|
20
|
+
- **老供应商会归档到 mapping.pool[] 历史池**,不是直接丢掉。万一新供应商有问题,`dsers_sku_remap` 下一次跑可以重新考虑老 supplier 作为候选
|
|
21
|
+
- **pool 只增不减**,有一个 validator 专门守着这条不变式
|
|
22
|
+
- **写入前做 6 条结构校验**,包括 supplyProductId 数字格式、supplyVariantId 格式、optionId/valueId 对应关系,防止把 DSers 写脏
|
|
23
|
+
- **自动识别 Basic vs Standard mapping type**,根据 variant 选项对齐情况决定用哪种 mapping schema。对齐不全时强制 degrade 到 Standard 并在 warnings 里说明原因
|
|
24
|
+
|
|
25
|
+
### 其它工具完善
|
|
26
|
+
|
|
27
|
+
顺手把之前零散的 3 个工具也正式加进 inputSchema / 描述里(之前 1.4.x 已经写过代码但 manifest / server.json 这些元数据文件没同步,这次补上):
|
|
28
|
+
|
|
29
|
+
- `dsers_import_list` — 浏览导入待推送列表,带成本 / 售价 / 库存 / 加价状态
|
|
30
|
+
- `dsers_my_products` — 查看已经推到店铺的商品(附供应商链接方便重新导入)
|
|
31
|
+
- `dsers_find_product` — DSers 商品池搜索,支持关键词和以图搜图,结果能直接导入
|
|
32
|
+
|
|
33
|
+
加上 `dsers_sku_remap`,这版从 9 个工具扩到 13 个。manifest.json 的 tools 数组之前漏了这 4 个,这版一起补齐。
|
|
34
|
+
|
|
35
|
+
### 稳定性修复
|
|
36
|
+
|
|
37
|
+
`dsers_sku_remap` 在 round-1 到 round-5.7.5 中一共发现并修了 15 个问题。按照发现轮次排列的关键几条:
|
|
38
|
+
|
|
39
|
+
- **F1 Path A 候选抓取加 pool-detail fallback** — 当用户传的 supplier URL 已经被账号里别的 product 占用时,DSers import-list 会直接报 "already exists" 但没给 importListId,导致原来的 Path A 走 5-26 秒的 timeout。现在会自动 fallback 到 `product-pool/product/detail` 直接查,几百 ms 返回
|
|
40
|
+
- **F2 入口加 store 归属校验** — shape 合法但不属于账号的 store_id 之前会一路走到 Path B rank_candidates 之后才报"no viable match",看不懂什么意思。现在先跑 `getMyProducts(page:1,size:100)` 做归属检查,几百 ms 内出干净的 `store_id_mismatch` envelope
|
|
41
|
+
- **F3 MCP 边界输入 shape 守卫** — 空字符串 / 字母 / 200 位长数字 / 特殊符号的 `dsers_product_id` 现在都在 MCP 层 0-1ms 被 refuse,不进 handler
|
|
42
|
+
- **F4 CODEC 文案收敛** — DSers 后端的 CODEC reason 码之前会透出到用户看到的错误里(内容是 Go map 的文字表示,不可读),现在统一包装成 `store_id_mismatch` envelope 带 `dsers_store_discover` 和 `dsers_my_products` 的明确修复指引
|
|
43
|
+
- **M1 int64 范围生产级收敛** — store_id / dsers_product_id 的 19 位数字现在不光用 regex 校验,MCP 层加了 BigInt `refine()` 检查 signed int64 上界(9223372036854775807)。超界值直接在 MCP 边界被拒,避免踩 DSers 后端的 int64 解析 bug
|
|
44
|
+
- **O1 URL scheme 大小写规范化** — `HTTPS://` / `HttP://` 这种混合大小写的 scheme 之前虽然运行时通过但回显给用户的 source_url 保留原样。现在在 SUPPLIER_URL_SCHEMA 的 `.transform()` 里统一 lowercase scheme 前缀,path / host / query 完全不动(RFC 3986 说 scheme case-insensitive 但 path case-sensitive,Alibaba 的 `Widget_ABC_1600123456789.html` 必须保真)
|
|
45
|
+
- **O3 hard error 文本清理** — Path A fetch failure 抛出的错误之前会带 DSers 原始 JSON blob / Go nil / map[] 这些 raw 文本。现在有一个 `sanitizePrimaryErrorForWarning` helper 剥掉 JSON 只保留人话,尾部统一附 `(DSers API HTTP NNN)` 标记上游状态码
|
|
46
|
+
- **O-R4-3 checkStoreOwnership 加直连快路径** — 之前 wrong dsers_product_id 要走 list-scan 扫一整页 100 个产品才能说"不存在",耗时 1.3s。新版先用 `getMyProductDetail` 直连查询,wrong-product 失败时间降到和 wrong-store 同数量级(< 500ms)
|
|
47
|
+
- **O-R5-3 validator 接受 DSers 单 SKU `<none>` 哨兵** — DSers 对"Default Title"单 SKU 产品的真实存储是 `supplyVariantId:"<none>"` 字面字符串,这不是 bug 是生产数据。validator 的 check 4 的 pattern `\d+:\d+[#...]` 之前会误拒这种数据,导致账号里**所有单 SKU 产品**(测试账号里有 9 个)的 apply 都会失败。现在 validator 接受 `<none>` 哨兵,前提是 candidate 也是单 SKU(防御性 guard:防止 matcher 把多 SKU candidate 硬塞到哨兵槽)
|
|
48
|
+
- **O-R55-2 / B-R57-1 sku-matcher 单 SKU seller 快路径** — matcher 的维度对齐路径对"seller 是单 SKU Default Title + candidate 是 1v 真实维度名(比如 `{Color, black}`)"这种退化场景会判 0 分 unmatched。新增一个 early-return 快路径: 当 seller 是 trivial 单 SKU(lean 或 Default Title 哨兵),candidate 不管什么形态,都按 `single_sku_seller_trivial` 策略配对,confidence 75。图像路径保留,candidate 多 SKU 时按 dHash 挑最接近的 variant,其它作为 alternatives 返回。**既有算法主体一行未动**(这点经过一周独立验证,不想动),shortcut 只是 early-return。fat-fat 场景(两边都是 Default Title 哨兵)还是走原算法的 exact 80 分,不被 shortcut 抢占
|
|
49
|
+
|
|
50
|
+
### 文件更新
|
|
51
|
+
|
|
52
|
+
- 修了 `app/dropshipping/[transport]/route.ts` 里硬编码的 `version: "1.3.8"`(遗留 bug,历次发版没同步到)
|
|
53
|
+
- `manifest.json` 补齐 4 个漏掉的 tool 描述
|
|
54
|
+
- README 里 `test count (343)` 同步到实际的 585
|
|
55
|
+
- 新增 `CHANGELOG.md`
|
|
56
|
+
|
|
57
|
+
### 没做的事(留给后续版本)
|
|
58
|
+
|
|
59
|
+
- `dsers_my_products` 的 `page` 分页参数现在实际不生效(DSers 后端行为,不是本工具的 bug),workaround 是用 `page_size:100` 一次拉完。账号产品超过 100 的用户会撞到这个,另开 issue 跟进
|
|
60
|
+
- DSers GET mapping 对多 supplier(MapAgc)产品返回的 `mappings[]` 数组顺序非确定(服务器行为,10 次里 9 次是顺序 A,1 次是顺序 B,值完全一样)。对做 byte-level diff 的工具链有影响,我们的 validator 不依赖 byte-level 所以不受影响,但使用者要注意
|
|
61
|
+
- `dsers_sku_remap` 的 discover 模式 Path B 对 vp* 虚拟产品(DSers 内部合成的)无效,因为 virtual product 没有 seed 图可以反搜。这是 DSers 侧的限制,不是我们能修的
|
|
62
|
+
|
|
63
|
+
### 回归验证
|
|
64
|
+
|
|
65
|
+
这一版从 round-1 做到 round-5.7.5,每轮都是独立 QA 会话(不读前面任何报告、HANDOFF、commit body、测试代码),跑完整 e2e 回归 + 真实 DSers 写入 + 字节级 rollback。585 个单元测试全过,最后一轮 0 Blocker / 0 Major / 0 Minor / 0 Observation。
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 1.4.x
|
|
70
|
+
|
|
71
|
+
之前的版本在 git history 里,主要是 OAuth 2.1 + 远程 MCP + Vercel 部署相关。没有集中的 changelog,看 `git log --oneline v1.4.0..v1.5.0` 或者各 commit message。
|
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ This works for both AliExpress and Alibaba products found on Accio.
|
|
|
78
78
|
|
|
79
79
|
- A [DSers](https://www.dsers.com/) account (free plan works)
|
|
80
80
|
- A Shopify or Wix store already connected in DSers
|
|
81
|
-
- An MCP-compatible AI client — [Cursor](https://cursor.sh/), [Claude Desktop](https://claude.ai/desktop), [Windsurf](https://codeium.com/windsurf), or any client that supports MCP
|
|
81
|
+
- An MCP-compatible AI client — [Cursor](https://cursor.sh/), [Claude Desktop](https://claude.ai/desktop), [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview), [Windsurf](https://codeium.com/windsurf), or any client that supports MCP
|
|
82
82
|
|
|
83
83
|
### Quick Start
|
|
84
84
|
|
|
@@ -121,6 +121,39 @@ If you don't want to install anything locally, you can connect directly to the h
|
|
|
121
121
|
|
|
122
122
|
Also listed on the official [MCP Registry](https://registry.modelcontextprotocol.io/servers/io.github.lofder/dsers-mcp-product).
|
|
123
123
|
|
|
124
|
+
**Claude Managed Agents ([docs](https://platform.claude.com/docs/en/managed-agents/overview)):**
|
|
125
|
+
|
|
126
|
+
Build autonomous dropshipping agents that run 24/7 in Anthropic's managed infrastructure. Connect this MCP server via the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/mcp):
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from claude_agent_sdk import query, ClaudeAgentOptions
|
|
130
|
+
|
|
131
|
+
async for message in query(
|
|
132
|
+
prompt="Find a cheaper supplier for product dp-123 in store st-456 and update the mapping",
|
|
133
|
+
options=ClaudeAgentOptions(
|
|
134
|
+
mcp_servers={
|
|
135
|
+
"dsers": {"command": "npx", "args": ["-y", "@lofder/dsers-mcp-product"]}
|
|
136
|
+
}
|
|
137
|
+
),
|
|
138
|
+
):
|
|
139
|
+
print(message)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
144
|
+
|
|
145
|
+
for await (const message of query({
|
|
146
|
+
prompt: "Find a cheaper supplier for product dp-123 in store st-456 and update the mapping",
|
|
147
|
+
options: {
|
|
148
|
+
mcpServers: {
|
|
149
|
+
dsers: { command: "npx", args: ["-y", "@lofder/dsers-mcp-product"] }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
})) {
|
|
153
|
+
console.log(message);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
124
157
|
### Authentication — OAuth 2.1
|
|
125
158
|
|
|
126
159
|
Your DSers password **never touches this tool**. Here's how login works:
|
|
@@ -142,6 +175,8 @@ npx @lofder/dsers-mcp-product login
|
|
|
142
175
|
|
|
143
176
|
> **For developers:** The server also accepts `DSERS_ACCESS_TOKEN` and `DSERS_REFRESH_TOKEN` env vars for headless/CI environments.
|
|
144
177
|
|
|
178
|
+
> **Working from source (not the published npm package)?** Use `node dist/cli.js login` instead of `npx @lofder/dsers-mcp-product login`. The `npx` form requires the `dsers-mcp-product` binary to resolve through your `PATH`, which only happens after `npm link` (or after a real npm install). In a fresh local clone the `npx` command exits with `command not found` (exit code 127). Run `npm run build` first so `dist/cli.js` exists.
|
|
179
|
+
|
|
145
180
|
### Usage Examples
|
|
146
181
|
|
|
147
182
|
Once set up, just talk to your AI agent in plain language:
|
|
@@ -190,7 +225,7 @@ dsers-mcp-product/
|
|
|
190
225
|
│ ├── cli.ts # npx entry — stdio transport, login/logout
|
|
191
226
|
│ ├── index.ts # MCP server init, tool registration
|
|
192
227
|
│ ├── instructions.ts # Server-level prompts (agent instructions)
|
|
193
|
-
│ ├── tools.ts #
|
|
228
|
+
│ ├── tools.ts # 13 MCP tools — schema + handler
|
|
194
229
|
│ ├── rules.ts # Rule validation & application engine
|
|
195
230
|
│ ├── push-guard.ts # Pre-push safety checks
|
|
196
231
|
│ ├── push-options.ts # Push option normalization
|
|
@@ -219,12 +254,12 @@ dsers-mcp-product/
|
|
|
219
254
|
│ │ ├── product.ts # Product & import APIs
|
|
220
255
|
│ │ └── settings.ts # Shipping, pricing, billing APIs
|
|
221
256
|
│ └── auth/ # Browser login (CDP)
|
|
222
|
-
├── test/ # Vitest unit tests (
|
|
257
|
+
├── test/ # Vitest unit tests (585 tests)
|
|
223
258
|
├── package.json
|
|
224
259
|
└── tsconfig.json
|
|
225
260
|
```
|
|
226
261
|
|
|
227
|
-
###
|
|
262
|
+
### Thirteen Tools
|
|
228
263
|
|
|
229
264
|
| # | Tool | What it does |
|
|
230
265
|
|---|------|-------------|
|
|
@@ -240,6 +275,7 @@ dsers-mcp-product/
|
|
|
240
275
|
| 10 | `dsers_import_list` | Browse your import staging list with cost & sell price, stock, markup status |
|
|
241
276
|
| 11 | `dsers_my_products` | See products already pushed to a store, with supplier links for re-import |
|
|
242
277
|
| 12 | `dsers_find_product` | Search the DSers product pool by keyword or image — results link directly to import |
|
|
278
|
+
| 13 | `dsers_sku_remap` | Replace the supplier on an existing store product at the SKU level. Two modes: provide `new_supplier_url` for a strict swap, or omit it to reverse-image-search the DSers pool and auto-pick the best replacement via multi-factor ranking. Always run `mode='preview'` first (read-only) and inspect `diffs` + `pool_additions` before `mode='apply'`. Requires the `product:mapping` OAuth scope. |
|
|
243
279
|
|
|
244
280
|
All tools return clear error messages so your AI agent knows what went wrong and what to do next.
|
|
245
281
|
|
|
@@ -302,7 +338,7 @@ Yes. The tool is open-source (MIT license) and completely free to use. You only
|
|
|
302
338
|
No passwords are stored or transmitted. Authentication uses a zero-password browser login — you log in on DSers's own website, and the tool picks up the session token. Your credentials never touch the MCP server. The project scored 92/100 on [SafeSkill](https://safeskill.dev/scan/@lofder/dsers-mcp-product) security scanning.
|
|
303
339
|
|
|
304
340
|
**What AI clients does it support?**
|
|
305
|
-
Cursor, Claude Desktop, Claude Code, Windsurf, and any MCP-compatible client that supports stdio transport.
|
|
341
|
+
Cursor, Claude Desktop, Claude Code, Claude Managed Agents, Windsurf, and any MCP-compatible client that supports stdio transport.
|
|
306
342
|
|
|
307
343
|
**How is this different from AliDropify, AutoDS, or other dropshipping tools?**
|
|
308
344
|
Most dropshipping tools have their own UI and require you to click through web interfaces. DSers MCP Product takes a fundamentally different approach — it connects directly to your AI agent, so you automate workflows through conversation instead of clicking buttons. It's also open-source and free, with no subscription tiers.
|
|
@@ -389,7 +425,7 @@ Accio 上搜出来的速卖通和阿里巴巴商品都能用。
|
|
|
389
425
|
|
|
390
426
|
- 一个 [DSers](https://www.dsers.com/) 账号(免费版就行)
|
|
391
427
|
- Shopify 或 Wix 店铺已经在 DSers 里绑定好了
|
|
392
|
-
- 一个支持 MCP 的 AI 客户端 — [Cursor](https://cursor.sh/)、[Claude Desktop](https://claude.ai/desktop)、[Windsurf](https://codeium.com/windsurf) 或其他支持 MCP 的工具
|
|
428
|
+
- 一个支持 MCP 的 AI 客户端 — [Cursor](https://cursor.sh/)、[Claude Desktop](https://claude.ai/desktop)、[Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview)、[Windsurf](https://codeium.com/windsurf) 或其他支持 MCP 的工具
|
|
393
429
|
|
|
394
430
|
### 快速开始
|
|
395
431
|
|
|
@@ -432,6 +468,24 @@ npx @lofder/dsers-mcp-product login
|
|
|
432
468
|
|
|
433
469
|
同时已收录到官方 [MCP Registry](https://registry.modelcontextprotocol.io/servers/io.github.lofder/dsers-mcp-product)。
|
|
434
470
|
|
|
471
|
+
**Claude Managed Agents ([文档](https://platform.claude.com/docs/en/managed-agents/overview)):**
|
|
472
|
+
|
|
473
|
+
通过 [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/mcp) 构建 7×24 自主运行的 dropshipping agent:
|
|
474
|
+
|
|
475
|
+
```python
|
|
476
|
+
from claude_agent_sdk import query, ClaudeAgentOptions
|
|
477
|
+
|
|
478
|
+
async for message in query(
|
|
479
|
+
prompt="帮商品 dp-123 在店铺 st-456 找个更便宜的供应商并更新映射",
|
|
480
|
+
options=ClaudeAgentOptions(
|
|
481
|
+
mcp_servers={
|
|
482
|
+
"dsers": {"command": "npx", "args": ["-y", "@lofder/dsers-mcp-product"]}
|
|
483
|
+
}
|
|
484
|
+
),
|
|
485
|
+
):
|
|
486
|
+
print(message)
|
|
487
|
+
```
|
|
488
|
+
|
|
435
489
|
### 授权认证 — OAuth 2.1
|
|
436
490
|
|
|
437
491
|
你的 DSers 密码**完全不经过本工具**。登录过程是这样的:
|
|
@@ -453,6 +507,8 @@ npx @lofder/dsers-mcp-product login
|
|
|
453
507
|
|
|
454
508
|
> **开发者注:** headless / CI 环境支持通过 `DSERS_ACCESS_TOKEN` 和 `DSERS_REFRESH_TOKEN` 环境变量传入凭据。
|
|
455
509
|
|
|
510
|
+
> **从源码工作(不是从 npm 包跑)?** 登录用 `node dist/cli.js login`,**不是** `npx @lofder/dsers-mcp-product login`。后者要求 `dsers-mcp-product` binary 解析到 PATH,本地 workspace 没 `npm link`(或者没真正 npm install)的话会 `command not found` 直接退出码 127。先 `npm run build` 让 `dist/cli.js` 存在再跑。
|
|
511
|
+
|
|
456
512
|
### 使用示例
|
|
457
513
|
|
|
458
514
|
装好之后,直接用自然语言跟 AI 助手说就行:
|
|
@@ -493,7 +549,7 @@ npm run build
|
|
|
493
549
|
npm test
|
|
494
550
|
```
|
|
495
551
|
|
|
496
|
-
###
|
|
552
|
+
### 十三个工具
|
|
497
553
|
|
|
498
554
|
| # | 工具 | 干什么的 |
|
|
499
555
|
|---|------|---------|
|
|
@@ -509,6 +565,7 @@ npm test
|
|
|
509
565
|
| 10 | `dsers_import_list` | 浏览导入待推送列表,含成本价、售价、库存、加价状态 |
|
|
510
566
|
| 11 | `dsers_my_products` | 查看已推到店铺的商品,带供应商链接方便重新导入 |
|
|
511
567
|
| 12 | `dsers_find_product` | 在 DSers 商品池搜索,支持关键词和以图搜图,结果可直接导入 |
|
|
568
|
+
| 13 | `dsers_sku_remap` | SKU 级别替换已上架商品的供应商。两种模式:传 `new_supplier_url` 走精确替换,不传则反向图搜 DSers 池 + 多因子打分自动挑最佳替代。务必先用 `mode='preview'`(只读)看 `diffs` 和 `pool_additions`,确认无误后再 `mode='apply'`。需要 `product:mapping` OAuth scope。 |
|
|
512
569
|
|
|
513
570
|
报错时会返回清晰的消息,AI 助手能看懂出了什么问题、该怎么办。
|
|
514
571
|
|
package/dist/auth/oauth.js
CHANGED
|
@@ -18,7 +18,7 @@ const DEFAULT_BFF_BASE = "https://bff-api-gw.dsers.com";
|
|
|
18
18
|
const CB_PORT = 3001;
|
|
19
19
|
const REDIRECT_URI = `http://localhost:${CB_PORT}/callback`;
|
|
20
20
|
const OAUTH_SCOPES = "user:read store:read store:write staff:read supplier:read " +
|
|
21
|
-
"product:read product:import product:push " +
|
|
21
|
+
"product:read product:import product:push product:mapping " +
|
|
22
22
|
"settings:read billing:read plan:read order:read";
|
|
23
23
|
// ── PKCE helpers ──
|
|
24
24
|
function generateVerifier() {
|
package/dist/auth/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,kBAAkB,GAAG,oCAAoC,CAAC;AAChE,MAAM,gBAAgB,GAAG,8BAA8B,CAAC;AACxD,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,MAAM,YAAY,GAAG,oBAAoB,OAAO,WAAW,CAAC;AAC5D,MAAM,YAAY,GAChB,4DAA4D;IAC5D,
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
File without changes
|
package/dist/dsers/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/dsers/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/dsers/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,SAAS,CAAuB;gBAE5B,MAAM,EAAE,WAAW;IAezB,UAAU,IAAI,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IA8E7C,UAAU,IAAI,IAAI;CAInB"}
|
package/dist/dsers/auth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { refreshAccessToken } from "../auth/oauth.js";
|
|
2
2
|
import { saveToken } from "../auth/token-store.js";
|
|
3
|
+
import { log } from "../logger.js";
|
|
3
4
|
export class DSersAuth {
|
|
4
5
|
config;
|
|
5
6
|
accessToken = null;
|
|
@@ -55,10 +56,24 @@ export class DSersAuth {
|
|
|
55
56
|
base_url: this.config.baseUrl,
|
|
56
57
|
ts: Date.now(),
|
|
57
58
|
});
|
|
59
|
+
log.info("oauth refresh succeeded", {
|
|
60
|
+
clientId: this.clientId,
|
|
61
|
+
expiresInSec: Math.round((this.expiresAt - Date.now()) / 1000),
|
|
62
|
+
});
|
|
58
63
|
return [this.accessToken, ""];
|
|
59
64
|
}
|
|
60
|
-
catch (
|
|
61
|
-
// Refresh failed —
|
|
65
|
+
catch (refreshErr) {
|
|
66
|
+
// Refresh failed — surface the concrete reason to the log tail
|
|
67
|
+
// before falling through to the "session expired" error. This
|
|
68
|
+
// pays down the diagnostic debt flagged during #6: the old
|
|
69
|
+
// `catch (_refreshErr) { /* fall through */ }` silently dropped
|
|
70
|
+
// the root cause, making "re-login loops" hard to root-cause.
|
|
71
|
+
// The throw still happens below with the same user-facing
|
|
72
|
+
// message, so CLI UX is unchanged — this is a pure add.
|
|
73
|
+
log.warn("oauth refresh failed", {
|
|
74
|
+
clientId: this.clientId,
|
|
75
|
+
errorMessage: refreshErr instanceof Error ? refreshErr.message : String(refreshErr),
|
|
76
|
+
});
|
|
62
77
|
}
|
|
63
78
|
}
|
|
64
79
|
if (!this.accessToken) {
|
package/dist/dsers/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/dsers/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAa,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/dsers/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/dsers/client.d.ts
CHANGED
|
@@ -2,7 +2,15 @@ import type { DSersConfig } from "./config.js";
|
|
|
2
2
|
export declare class DSersAPIError extends Error {
|
|
3
3
|
status: number;
|
|
4
4
|
body: string;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Response headers captured at the time the error was constructed.
|
|
7
|
+
* Populated by `DSersClient.request()` as a lowercased-key map so callers
|
|
8
|
+
* (primarily `src/dsers/retry.ts`) can read `retry-after` without caring
|
|
9
|
+
* about case. Undefined on errors constructed outside the client (tests,
|
|
10
|
+
* fabricated failures, pre-#6 call-sites).
|
|
11
|
+
*/
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
constructor(status: number, body: string, headers?: Record<string, string>);
|
|
6
14
|
}
|
|
7
15
|
export declare class DSersClient {
|
|
8
16
|
private config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/dsers/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,qBAAa,aAAc,SAAQ,KAAK;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/dsers/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,qBAAa,aAAc,SAAQ,KAAK;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACrB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAM3E;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,IAAI,CAAY;IACxB,OAAO,CAAC,iBAAiB,CAAgB;gBAE7B,MAAM,EAAE,WAAW;YAKjB,QAAQ;IAWhB,OAAO,CACX,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC5B,EACD,OAAO,UAAQ,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAoDzB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAI7E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAI1G,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAIzG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAIvF"}
|
package/dist/dsers/client.js
CHANGED
|
@@ -5,10 +5,20 @@ const RATE_LIMIT_MAX_REQUESTS = 20;
|
|
|
5
5
|
export class DSersAPIError extends Error {
|
|
6
6
|
status;
|
|
7
7
|
body;
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Response headers captured at the time the error was constructed.
|
|
10
|
+
* Populated by `DSersClient.request()` as a lowercased-key map so callers
|
|
11
|
+
* (primarily `src/dsers/retry.ts`) can read `retry-after` without caring
|
|
12
|
+
* about case. Undefined on errors constructed outside the client (tests,
|
|
13
|
+
* fabricated failures, pre-#6 call-sites).
|
|
14
|
+
*/
|
|
15
|
+
headers;
|
|
16
|
+
constructor(status, body, headers) {
|
|
9
17
|
super(`DSers API ${status}: ${body.slice(0, 500)}`);
|
|
10
18
|
this.status = status;
|
|
11
19
|
this.body = body;
|
|
20
|
+
if (headers)
|
|
21
|
+
this.headers = headers;
|
|
12
22
|
}
|
|
13
23
|
}
|
|
14
24
|
export class DSersClient {
|
|
@@ -66,7 +76,13 @@ export class DSersClient {
|
|
|
66
76
|
}
|
|
67
77
|
}
|
|
68
78
|
if (resp.status >= 400) {
|
|
69
|
-
|
|
79
|
+
// Capture response headers as a lowercased-key map so retry helpers
|
|
80
|
+
// can read `retry-after` without case games.
|
|
81
|
+
const headerMap = {};
|
|
82
|
+
resp.headers.forEach((value, key) => {
|
|
83
|
+
headerMap[key.toLowerCase()] = value;
|
|
84
|
+
});
|
|
85
|
+
throw new DSersAPIError(resp.status, bodyText, headerMap);
|
|
70
86
|
}
|
|
71
87
|
return JSON.parse(bodyText);
|
|
72
88
|
}
|
package/dist/dsers/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/dsers/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;AAEzG,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAEnC,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,MAAM,CAAS;IACf,IAAI,CAAS;IACb,YAAY,MAAc,EAAE,IAAY;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/dsers/client.ts"],"names":[],"mappings":"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"}
|
package/dist/dsers/product.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* DSers Product API — BFF wrappers and push-flow utilities for dsers-product-bff.
|
|
3
3
|
*/
|
|
4
4
|
import type { DSersClient } from "./client.js";
|
|
5
|
+
import { type RetryOptions } from "./retry.js";
|
|
5
6
|
export declare function cleanNone(value: unknown): unknown;
|
|
6
7
|
export declare function coerceIntId(value: unknown): unknown;
|
|
7
8
|
export declare function mergeLegacyPushSettings(target: Record<string, unknown>, source: unknown): void;
|
|
@@ -32,6 +33,49 @@ export declare function getShopifyShippingProfiles(client: DSersClient): Promise
|
|
|
32
33
|
export declare function listImportTags(client: DSersClient): Promise<Record<string, unknown>>;
|
|
33
34
|
export declare function getMyProducts(client: DSersClient, params: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
34
35
|
export declare function getMapping(client: DSersClient, dsersProductId: string): Promise<Record<string, unknown>>;
|
|
36
|
+
/**
|
|
37
|
+
* Fetch the Shopify-side product detail for a DSers-managed product. Returns
|
|
38
|
+
* the store product's `medias[]` (array of Shopify CDN URLs) and
|
|
39
|
+
* `variants[].imgUrl` — i.e. the images the seller sees on their storefront,
|
|
40
|
+
* not supplier-side images. Used by the Path B image-search flow when the
|
|
41
|
+
* product has no active supplier mapping and supplier-side seed images
|
|
42
|
+
* therefore aren't available.
|
|
43
|
+
*
|
|
44
|
+
* storeId is a query param and must be a string (same int64 precision issue
|
|
45
|
+
* as saveMapping). Omitting it falls back to whichever store DSers infers
|
|
46
|
+
* from the product id, but it's safer to pass it explicitly.
|
|
47
|
+
*/
|
|
48
|
+
export declare function getMyProductDetail(client: DSersClient, dsersProductId: string, storeId?: string): Promise<Record<string, unknown>>;
|
|
49
|
+
export interface SaveMappingBody {
|
|
50
|
+
storeId: string;
|
|
51
|
+
mappingType: string;
|
|
52
|
+
mapping: unknown[];
|
|
53
|
+
pool?: unknown[];
|
|
54
|
+
[extra: string]: unknown;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Save the variant mapping for a product. Wrapped with the #6 retry helper
|
|
58
|
+
* because transient 5xx / network failures mid-write are recoverable: the
|
|
59
|
+
* POST is byte-level idempotent (D6 verified), so a second attempt with
|
|
60
|
+
* the same payload lands the server in the same state as one successful
|
|
61
|
+
* attempt. 401 is NOT retried here — `DSersClient.request()` already
|
|
62
|
+
* handles refresh-and-recurse for auth failures.
|
|
63
|
+
*
|
|
64
|
+
* `retryOptions` is an optional pass-through to `withRetry`. Production
|
|
65
|
+
* callers omit it to use the module defaults (4 attempts, exp-jitter,
|
|
66
|
+
* 30s total timeout). Tests inject `sleep: async () => {}` to keep the
|
|
67
|
+
* suite deterministic and fast.
|
|
68
|
+
*/
|
|
69
|
+
export declare function saveMapping(client: DSersClient, dsersProductId: string, body: SaveMappingBody, retryOptions?: RetryOptions): Promise<Record<string, unknown>>;
|
|
70
|
+
/**
|
|
71
|
+
* Poll the DSers post-write processing status for a product. Wrapped with
|
|
72
|
+
* the #6 retry helper because it's a pure GET and also sits on the apply
|
|
73
|
+
* path — if saveMapping succeeded but the first poll hits a transient 502,
|
|
74
|
+
* we want to recover without exploding the whole skuRemap apply.
|
|
75
|
+
*
|
|
76
|
+
* `retryOptions` pass-through: see `saveMapping` above.
|
|
77
|
+
*/
|
|
78
|
+
export declare function getMappingProcessStatus(client: DSersClient, dsersProductId: string, retryOptions?: RetryOptions): Promise<Record<string, unknown>>;
|
|
35
79
|
export declare function findSuppliers(client: DSersClient, params: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
36
80
|
export declare function parseProductUrl(client: DSersClient, url: string, appId: string | number): Promise<Record<string, unknown>>;
|
|
37
81
|
export declare function getPoolProductDetail(client: DSersClient, params: {
|
|
@@ -39,4 +83,16 @@ export declare function getPoolProductDetail(client: DSersClient, params: {
|
|
|
39
83
|
appId: number;
|
|
40
84
|
shipTo: string;
|
|
41
85
|
}): Promise<Record<string, unknown>>;
|
|
86
|
+
/**
|
|
87
|
+
* Reverse image search against the DSers supplier pool. Returns summary-level
|
|
88
|
+
* ProductPoolData[] (no medias[] or variants[] — those require a follow-up
|
|
89
|
+
* call to getPoolProductDetail).
|
|
90
|
+
*/
|
|
91
|
+
export declare function findSuppliersByImage(client: DSersClient, params: {
|
|
92
|
+
imgUrl: string;
|
|
93
|
+
supplyAppId?: number | string;
|
|
94
|
+
shipTo?: string;
|
|
95
|
+
limit?: number;
|
|
96
|
+
searchAfter?: string;
|
|
97
|
+
}): Promise<Record<string, unknown>>;
|
|
42
98
|
//# sourceMappingURL=product.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product.d.ts","sourceRoot":"","sources":["../../src/dsers/product.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"product.d.ts","sourceRoot":"","sources":["../../src/dsers/product.ts"],"names":[],"mappings":"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"}
|
package/dist/dsers/product.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withRetry } from "./retry.js";
|
|
1
2
|
export function cleanNone(value) {
|
|
2
3
|
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
3
4
|
const obj = value;
|
|
@@ -276,6 +277,49 @@ export async function getMyProducts(client, params) {
|
|
|
276
277
|
export async function getMapping(client, dsersProductId) {
|
|
277
278
|
return client.get(`/dsers-product-bff/mapping/${dsersProductId}`);
|
|
278
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* Fetch the Shopify-side product detail for a DSers-managed product. Returns
|
|
282
|
+
* the store product's `medias[]` (array of Shopify CDN URLs) and
|
|
283
|
+
* `variants[].imgUrl` — i.e. the images the seller sees on their storefront,
|
|
284
|
+
* not supplier-side images. Used by the Path B image-search flow when the
|
|
285
|
+
* product has no active supplier mapping and supplier-side seed images
|
|
286
|
+
* therefore aren't available.
|
|
287
|
+
*
|
|
288
|
+
* storeId is a query param and must be a string (same int64 precision issue
|
|
289
|
+
* as saveMapping). Omitting it falls back to whichever store DSers infers
|
|
290
|
+
* from the product id, but it's safer to pass it explicitly.
|
|
291
|
+
*/
|
|
292
|
+
export async function getMyProductDetail(client, dsersProductId, storeId) {
|
|
293
|
+
const params = storeId != null ? { storeId } : undefined;
|
|
294
|
+
return client.get(`/dsers-product-bff/my-product/detail/${dsersProductId}`, params);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Save the variant mapping for a product. Wrapped with the #6 retry helper
|
|
298
|
+
* because transient 5xx / network failures mid-write are recoverable: the
|
|
299
|
+
* POST is byte-level idempotent (D6 verified), so a second attempt with
|
|
300
|
+
* the same payload lands the server in the same state as one successful
|
|
301
|
+
* attempt. 401 is NOT retried here — `DSersClient.request()` already
|
|
302
|
+
* handles refresh-and-recurse for auth failures.
|
|
303
|
+
*
|
|
304
|
+
* `retryOptions` is an optional pass-through to `withRetry`. Production
|
|
305
|
+
* callers omit it to use the module defaults (4 attempts, exp-jitter,
|
|
306
|
+
* 30s total timeout). Tests inject `sleep: async () => {}` to keep the
|
|
307
|
+
* suite deterministic and fast.
|
|
308
|
+
*/
|
|
309
|
+
export async function saveMapping(client, dsersProductId, body, retryOptions) {
|
|
310
|
+
return withRetry(() => client.post(`/dsers-product-bff/mapping/${dsersProductId}`, body), retryOptions);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Poll the DSers post-write processing status for a product. Wrapped with
|
|
314
|
+
* the #6 retry helper because it's a pure GET and also sits on the apply
|
|
315
|
+
* path — if saveMapping succeeded but the first poll hits a transient 502,
|
|
316
|
+
* we want to recover without exploding the whole skuRemap apply.
|
|
317
|
+
*
|
|
318
|
+
* `retryOptions` pass-through: see `saveMapping` above.
|
|
319
|
+
*/
|
|
320
|
+
export async function getMappingProcessStatus(client, dsersProductId, retryOptions) {
|
|
321
|
+
return withRetry(() => client.get(`/dsers-product-bff/mapping/check-process-status/${dsersProductId}`), retryOptions);
|
|
322
|
+
}
|
|
279
323
|
export async function findSuppliers(client, params) {
|
|
280
324
|
return client.get("/dsers-product-bff/find-suppliers/products", params);
|
|
281
325
|
}
|
|
@@ -288,4 +332,24 @@ export async function parseProductUrl(client, url, appId) {
|
|
|
288
332
|
export async function getPoolProductDetail(client, params) {
|
|
289
333
|
return client.get("/dsers-product-bff/product-pool/product/detail", params);
|
|
290
334
|
}
|
|
335
|
+
/**
|
|
336
|
+
* Reverse image search against the DSers supplier pool. Returns summary-level
|
|
337
|
+
* ProductPoolData[] (no medias[] or variants[] — those require a follow-up
|
|
338
|
+
* call to getPoolProductDetail).
|
|
339
|
+
*/
|
|
340
|
+
export async function findSuppliersByImage(client, params) {
|
|
341
|
+
const query = {
|
|
342
|
+
imgUrl: params.imgUrl,
|
|
343
|
+
supplyAppId: params.supplyAppId ?? "159831080", // AliExpress default
|
|
344
|
+
language: "en-US",
|
|
345
|
+
sort: 0,
|
|
346
|
+
};
|
|
347
|
+
if (params.shipTo)
|
|
348
|
+
query.shipTo = params.shipTo;
|
|
349
|
+
if (params.limit != null)
|
|
350
|
+
query.limit = params.limit;
|
|
351
|
+
if (params.searchAfter != null)
|
|
352
|
+
query.searchAfter = params.searchAfter;
|
|
353
|
+
return client.get("/dsers-product-bff/find-suppliers/products", query);
|
|
354
|
+
}
|
|
291
355
|
//# sourceMappingURL=product.js.map
|