@optima-chat/tiktok-cli 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.js +18 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ tiktok <domain> <verb> --shop <shopId> [--flags]
|
|
|
13
13
|
- `--shop` **必填**(多店显式路由,对应 A 轨「多店必须显式选店」教训;`auth link` 除外)
|
|
14
14
|
- 默认 **JSON 输出**,统一信封 `{ ok, data?, error?, meta? }`
|
|
15
15
|
- `TIKTOK_BACKEND_URL` 解析顺序:显式环境变量 > `OPTIMA_ENV` 映射(`cn-stage` → `https://tiktok-api.stage.optima.chat`;`cn-prod` → `https://tiktok-api.yzsgo.com`)> 本地默认 `http://127.0.0.1:3000`
|
|
16
|
+
- `OPTIMA_TRACE`(可选,COO 会话设为 `coo/<taskId>`):非空(trim 后)时每个打 backend 的请求都带 `X-Optima-Trace: <值>`,供用量按任务归因(Optima-Chat/optima-coo#645);没设 / 空白则不带。只发 backend,CLI 本就不直连第三方
|
|
16
17
|
|
|
17
18
|
## 命令(v1 只读)
|
|
18
19
|
|
package/dist/index.js
CHANGED
|
@@ -129,6 +129,15 @@ function authHeaders() {
|
|
|
129
129
|
}
|
|
130
130
|
return {};
|
|
131
131
|
}
|
|
132
|
+
function traceHeaders(env2 = process.env) {
|
|
133
|
+
const v = env2.OPTIMA_TRACE?.trim();
|
|
134
|
+
return v ? { "X-Optima-Trace": v } : {};
|
|
135
|
+
}
|
|
136
|
+
function backendFetch(url, init = {}) {
|
|
137
|
+
const headers = new Headers(init.headers);
|
|
138
|
+
for (const [k, v] of Object.entries(traceHeaders())) headers.set(k, v);
|
|
139
|
+
return fetch(url, { ...init, headers });
|
|
140
|
+
}
|
|
132
141
|
function classify(status, body, shop) {
|
|
133
142
|
const meta = { shop, tiktok_request_id: body?.request_id, http_status: status };
|
|
134
143
|
if (status === 0 || body?.code === 0) {
|
|
@@ -148,7 +157,7 @@ async function proxy(method, shop, path, opts = {}) {
|
|
|
148
157
|
const qs = opts.query ? "?" + new URLSearchParams(opts.query) : "";
|
|
149
158
|
const url = `${BACKEND}/proxy/${shop}${path}${qs}`;
|
|
150
159
|
try {
|
|
151
|
-
const r = await
|
|
160
|
+
const r = await backendFetch(url, {
|
|
152
161
|
method,
|
|
153
162
|
headers: {
|
|
154
163
|
"Content-Type": "application/json",
|
|
@@ -165,7 +174,7 @@ async function proxy(method, shop, path, opts = {}) {
|
|
|
165
174
|
}
|
|
166
175
|
async function listShops() {
|
|
167
176
|
try {
|
|
168
|
-
const r = await
|
|
177
|
+
const r = await backendFetch(`${BACKEND}/auth/shops`, { headers: authHeaders() });
|
|
169
178
|
if (r.status === 401) return { ok: false, error: { code: "AUTH_EXPIRED", message: "\u672A\u767B\u5F55\u6216 token \u5931\u6548", retryable: false } };
|
|
170
179
|
const body = await r.json();
|
|
171
180
|
return { ok: true, data: body.shops };
|
|
@@ -176,7 +185,7 @@ async function listShops() {
|
|
|
176
185
|
async function setShopApp(shopId, serviceId, note) {
|
|
177
186
|
const token = process.env.TIKTOK_ADMIN_TOKEN;
|
|
178
187
|
try {
|
|
179
|
-
const r = await
|
|
188
|
+
const r = await backendFetch(`${BACKEND}/admin/apps/shop-map`, {
|
|
180
189
|
method: "PUT",
|
|
181
190
|
headers: { "Content-Type": "application/json", ...token ? { "x-admin-token": token } : {} },
|
|
182
191
|
body: JSON.stringify({ shopId, serviceId, note })
|
|
@@ -190,7 +199,7 @@ async function setShopApp(shopId, serviceId, note) {
|
|
|
190
199
|
}
|
|
191
200
|
async function availableApps() {
|
|
192
201
|
try {
|
|
193
|
-
const r = await
|
|
202
|
+
const r = await backendFetch(`${BACKEND}/auth/apps`, { headers: authHeaders() });
|
|
194
203
|
if (r.status === 401) return { ok: false, error: { code: "AUTH_EXPIRED", message: "\u672A\u767B\u5F55\u6216 token \u5931\u6548", retryable: false } };
|
|
195
204
|
const body = await r.json().catch(() => ({}));
|
|
196
205
|
if (!r.ok || body?.error) {
|
|
@@ -203,7 +212,7 @@ async function availableApps() {
|
|
|
203
212
|
}
|
|
204
213
|
async function authLink(opts) {
|
|
205
214
|
try {
|
|
206
|
-
const r = await
|
|
215
|
+
const r = await backendFetch(`${BACKEND}/auth/link`, {
|
|
207
216
|
method: "POST",
|
|
208
217
|
headers: { "Content-Type": "application/json", ...authHeaders() },
|
|
209
218
|
body: JSON.stringify({ shop: opts.shop, app: opts.app })
|
|
@@ -222,7 +231,7 @@ async function adminApps(method, opts = {}) {
|
|
|
222
231
|
const url = `${BACKEND}/admin/apps${opts.id ? `/${opts.id}` : ""}`;
|
|
223
232
|
const token = process.env.TIKTOK_ADMIN_TOKEN;
|
|
224
233
|
try {
|
|
225
|
-
const r = await
|
|
234
|
+
const r = await backendFetch(url, {
|
|
226
235
|
method,
|
|
227
236
|
headers: {
|
|
228
237
|
"Content-Type": "application/json",
|
|
@@ -245,7 +254,7 @@ async function adminApps(method, opts = {}) {
|
|
|
245
254
|
async function fetchEvents(shop, query) {
|
|
246
255
|
try {
|
|
247
256
|
const qs = new URLSearchParams(query).toString();
|
|
248
|
-
const r = await
|
|
257
|
+
const r = await backendFetch(`${BACKEND}/events/${shop}${qs ? "?" + qs : ""}`, { headers: authHeaders() });
|
|
249
258
|
if (r.status === 401) return { ok: false, error: { code: "AUTH_EXPIRED", message: "\u672A\u767B\u5F55\u6216 token \u5931\u6548", retryable: false } };
|
|
250
259
|
if (r.status === 404) return { ok: false, error: { code: "SHOP_NOT_AUTHORIZED", message: "\u672A\u627E\u5230\u4F60\u540D\u4E0B\u7684\u5DF2\u6388\u6743\u5E97\u94FA", retryable: false }, meta: { shop } };
|
|
251
260
|
const body = await r.json();
|
|
@@ -256,7 +265,7 @@ async function fetchEvents(shop, query) {
|
|
|
256
265
|
}
|
|
257
266
|
async function ackEvents(shop, body) {
|
|
258
267
|
try {
|
|
259
|
-
const r = await
|
|
268
|
+
const r = await backendFetch(`${BACKEND}/events/${shop}/ack`, {
|
|
260
269
|
method: "POST",
|
|
261
270
|
headers: { "Content-Type": "application/json", ...authHeaders() },
|
|
262
271
|
body: JSON.stringify(body)
|
|
@@ -275,7 +284,7 @@ async function uploadImage(shop, filePath, useCase) {
|
|
|
275
284
|
const form = new FormData();
|
|
276
285
|
form.append("data", new Blob([buf]), basename(filePath));
|
|
277
286
|
form.append("use_case", useCase);
|
|
278
|
-
const r = await
|
|
287
|
+
const r = await backendFetch(`${BACKEND}/proxy-upload/${shop}/image`, { method: "POST", headers: authHeaders(), body: form });
|
|
279
288
|
const body = await r.json().catch(() => ({}));
|
|
280
289
|
if (body?.code === 0) return { ok: true, data: { uri: body.data?.uri, url: body.data?.url, use_case: useCase }, meta: { shop } };
|
|
281
290
|
return { ok: false, error: { code: r.status === 401 ? "AUTH_EXPIRED" : "TIKTOK_ERROR", message: body?.message ?? body?.error ?? `HTTP ${r.status}`, retryable: false }, meta: { shop } };
|