@optima-chat/tiktok-cli 0.8.0 → 0.10.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.
Files changed (2) hide show
  1. package/dist/index.js +146 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -75,6 +75,21 @@ async function listShops() {
75
75
  return { ok: false, error: { code: "BACKEND_UNREACHABLE", message: e.message, retryable: true } };
76
76
  }
77
77
  }
78
+ async function setShopApp(shopId, serviceId, note) {
79
+ const token = process.env.TIKTOK_ADMIN_TOKEN;
80
+ try {
81
+ const r = await fetch(`${BACKEND}/admin/apps/shop-map`, {
82
+ method: "PUT",
83
+ headers: { "Content-Type": "application/json", ...token ? { "x-admin-token": token } : {} },
84
+ body: JSON.stringify({ shopId, serviceId, note })
85
+ });
86
+ const body = await r.json().catch(() => ({}));
87
+ if (!r.ok || body?.error) return { ok: false, error: { code: r.status === 401 ? "AUTH_EXPIRED" : "VALIDATION", message: body?.error ?? `HTTP ${r.status}`, retryable: false } };
88
+ return { ok: true, data: body };
89
+ } catch (e) {
90
+ return { ok: false, error: { code: "BACKEND_UNREACHABLE", message: e.message, retryable: true } };
91
+ }
92
+ }
78
93
  async function availableApps() {
79
94
  try {
80
95
  const r = await fetch(`${BACKEND}/auth/apps`, { headers: authHeaders() });
@@ -88,12 +103,12 @@ async function availableApps() {
88
103
  return { ok: false, error: { code: "BACKEND_UNREACHABLE", message: e.message, retryable: true } };
89
104
  }
90
105
  }
91
- async function authLink(app) {
106
+ async function authLink(opts) {
92
107
  try {
93
108
  const r = await fetch(`${BACKEND}/auth/link`, {
94
109
  method: "POST",
95
110
  headers: { "Content-Type": "application/json", ...authHeaders() },
96
- body: JSON.stringify({ app })
111
+ body: JSON.stringify({ shop: opts.shop, app: opts.app })
97
112
  });
98
113
  if (r.status === 401) return { ok: false, error: { code: "AUTH_EXPIRED", message: "\u672A\u767B\u5F55\u6216 token \u5931\u6548", retryable: false } };
99
114
  const body = await r.json().catch(() => ({}));
@@ -430,6 +445,118 @@ var COMMANDS = [
430
445
  }
431
446
  })
432
447
  },
448
+ {
449
+ name: "analytics videos",
450
+ summary: "\u5185\u5BB9\u89C6\u9891\u7EF4\u5EA6\u7ECF\u8425\u6570\u636E\uFF08shop_videos\uFF0C--from --to\uFF0C\u9ED8\u8BA4\u8FD130\u5929\uFF0C\u6309 GMV \u964D\u5E8F\uFF1B--sort-field --sort-order --page-size --page-token\uFF09",
451
+ run: ({ shop, args: args2 }) => proxy("GET", shop, "/analytics/202509/shop_videos/performance", {
452
+ query: {
453
+ start_date_ge: args2.from ?? daysAgo(30),
454
+ end_date_lt: args2.to ?? today(),
455
+ sort_field: args2["sort-field"] ?? "gmv",
456
+ sort_order: args2["sort-order"] ?? "DESC",
457
+ page_size: args2["page-size"] ?? "20",
458
+ ...args2["page-token"] ? { page_token: args2["page-token"] } : {}
459
+ }
460
+ })
461
+ },
462
+ {
463
+ name: "analytics videos-overview",
464
+ summary: "\u5185\u5BB9\u89C6\u9891\u6574\u4F53\u6982\u89C8\uFF08shop_videos overview\uFF1B--from --to --granularity\uFF09",
465
+ run: ({ shop, args: args2 }) => proxy("GET", shop, "/analytics/202509/shop_videos/overview_performance", {
466
+ query: {
467
+ start_date_ge: args2.from ?? daysAgo(30),
468
+ end_date_lt: args2.to ?? today(),
469
+ granularity: args2.granularity ?? "ALL"
470
+ }
471
+ })
472
+ },
473
+ {
474
+ name: "analytics video",
475
+ summary: "\u5355\u6761\u89C6\u9891\u7ECF\u8425\u660E\u7EC6\uFF08--video video_id \u5FC5\u586B\uFF1B--from --to\uFF09",
476
+ run: ({ shop, args: args2 }) => proxy("GET", shop, `/analytics/202509/shop_videos/${args2.video}/performance`, {
477
+ query: {
478
+ start_date_ge: args2.from ?? daysAgo(30),
479
+ end_date_lt: args2.to ?? today()
480
+ }
481
+ })
482
+ },
483
+ {
484
+ name: "analytics video-products",
485
+ summary: "\u5355\u6761\u89C6\u9891\u5E26\u8D27\u5546\u54C1\u8868\u73B0\uFF08--video video_id \u5FC5\u586B\uFF1B--from --to --page-size\uFF09",
486
+ run: ({ shop, args: args2 }) => proxy("GET", shop, `/analytics/202509/shop_videos/${args2.video}/products/performance`, {
487
+ query: {
488
+ start_date_ge: args2.from ?? daysAgo(30),
489
+ end_date_lt: args2.to ?? today(),
490
+ page_size: args2["page-size"] ?? "20"
491
+ }
492
+ })
493
+ },
494
+ {
495
+ name: "analytics lives",
496
+ summary: "\u76F4\u64AD\u7EF4\u5EA6\u7ECF\u8425\u6570\u636E\uFF08shop_lives\uFF0C--from --to\uFF0C\u9ED8\u8BA4\u8FD130\u5929\uFF0C\u6309 GMV \u964D\u5E8F\uFF1B--sort-field --sort-order --page-size --page-token\uFF09",
497
+ run: ({ shop, args: args2 }) => proxy("GET", shop, "/analytics/202509/shop_lives/performance", {
498
+ query: {
499
+ start_date_ge: args2.from ?? daysAgo(30),
500
+ end_date_lt: args2.to ?? today(),
501
+ sort_field: args2["sort-field"] ?? "gmv",
502
+ sort_order: args2["sort-order"] ?? "DESC",
503
+ page_size: args2["page-size"] ?? "20",
504
+ ...args2["page-token"] ? { page_token: args2["page-token"] } : {}
505
+ }
506
+ })
507
+ },
508
+ {
509
+ name: "analytics lives-overview",
510
+ summary: "\u76F4\u64AD\u6574\u4F53\u6982\u89C8\uFF08shop_lives overview\uFF1B--from --to --granularity\uFF09",
511
+ run: ({ shop, args: args2 }) => proxy("GET", shop, "/analytics/202509/shop_lives/overview_performance", {
512
+ query: {
513
+ start_date_ge: args2.from ?? daysAgo(30),
514
+ end_date_lt: args2.to ?? today(),
515
+ granularity: args2.granularity ?? "ALL"
516
+ }
517
+ })
518
+ },
519
+ {
520
+ name: "analytics skus",
521
+ summary: "SKU \u7EF4\u5EA6\u7ECF\u8425\u6570\u636E\uFF08shop_skus\uFF0C--from --to\uFF0C\u9ED8\u8BA4\u8FD130\u5929\uFF0C\u6309 GMV \u964D\u5E8F\uFF1B--sort-field --sort-order --page-size --page-token\uFF09",
522
+ run: ({ shop, args: args2 }) => proxy("GET", shop, "/analytics/202509/shop_skus/performance", {
523
+ query: {
524
+ start_date_ge: args2.from ?? daysAgo(30),
525
+ end_date_lt: args2.to ?? today(),
526
+ sort_field: args2["sort-field"] ?? "gmv",
527
+ sort_order: args2["sort-order"] ?? "DESC",
528
+ page_size: args2["page-size"] ?? "20",
529
+ ...args2["page-token"] ? { page_token: args2["page-token"] } : {}
530
+ }
531
+ })
532
+ },
533
+ {
534
+ name: "analytics sku",
535
+ summary: "\u5355\u4E2A SKU \u7ECF\u8425\u660E\u7EC6\uFF08--sku sku_id \u5FC5\u586B\uFF1B--from --to --granularity\uFF09",
536
+ run: ({ shop, args: args2 }) => proxy("GET", shop, `/analytics/202509/shop_skus/${args2.sku}/performance`, {
537
+ query: {
538
+ start_date_ge: args2.from ?? daysAgo(30),
539
+ end_date_lt: args2.to ?? today(),
540
+ granularity: args2.granularity ?? "ALL"
541
+ }
542
+ })
543
+ },
544
+ {
545
+ name: "analytics product",
546
+ summary: "\u5355\u4E2A\u5546\u54C1\u7ECF\u8425\u660E\u7EC6\uFF08--product product_id \u5FC5\u586B\uFF1B--from --to --granularity\uFF09",
547
+ run: ({ shop, args: args2 }) => proxy("GET", shop, `/analytics/202509/shop_products/${args2.product}/performance`, {
548
+ query: {
549
+ start_date_ge: args2.from ?? daysAgo(30),
550
+ end_date_lt: args2.to ?? today(),
551
+ granularity: args2.granularity ?? "ALL"
552
+ }
553
+ })
554
+ },
555
+ {
556
+ name: "analytics shop-hourly",
557
+ summary: "\u5E97\u94FA\u67D0\u5929\u5206\u65F6\uFF08\u9010\u5C0F\u65F6\uFF09\u7ECF\u8425\u6570\u636E\uFF08--date YYYY-MM-DD\uFF0C\u9ED8\u8BA4\u6628\u5929\uFF09",
558
+ run: ({ shop, args: args2 }) => proxy("GET", shop, `/analytics/202510/shop/performance/${args2.date ?? daysAgo(1)}/performance_per_hour`, {})
559
+ },
433
560
  {
434
561
  name: "products list",
435
562
  summary: "\u5546\u54C1\u5217\u8868\uFF08--status ACTIVATE \u53EA\u53D6\u5728\u552E\uFF1B\u4E0D\u4F20\u8FD4\u6240\u6709\u542B DELETED\uFF0C\u5199\u64CD\u4F5C\u524D\u52A1\u5FC5\u7B5B ACTIVATE\uFF09",
@@ -894,10 +1021,19 @@ var COMMANDS = [
894
1021
  label: args2.label,
895
1022
  ...args2.markets ? { markets: args2.markets.split(",") } : {},
896
1023
  redirectUri: args2.redirect,
897
- ...args2["owner-entity"] ? { ownerEntity: args2["owner-entity"] } : {}
1024
+ ...args2["owner-entity"] ? { ownerEntity: args2["owner-entity"] } : {},
1025
+ ..."default" in args2 ? { isDefault: true } : {}
898
1026
  }
899
1027
  })
900
1028
  },
1029
+ {
1030
+ name: "apps set-shop",
1031
+ summary: "\u9884\u7F6E shop\u2192app \u6620\u5C04\uFF08--shop shopId --app serviceId [--note]\uFF09\u2014\u2014auth link \u65F6\u6309\u5E97\u89E3\u6790\u7528\u54EA\u4E2A app",
1032
+ run: ({ args: args2 }) => {
1033
+ if (!args2.shop || !args2.app) return Promise.resolve({ ok: false, error: { code: "VALIDATION", message: "--shop \u548C --app\uFF08serviceId\uFF09\u5FC5\u586B", retryable: false } });
1034
+ return setShopApp(args2.shop, args2.app, args2.note);
1035
+ }
1036
+ },
901
1037
  {
902
1038
  name: "apps list",
903
1039
  summary: "\u5217\u51FA\u5DF2\u767B\u8BB0\u7684 TikTok App\uFF08admin\uFF0C\u542B appKey/status\uFF09",
@@ -913,15 +1049,16 @@ var COMMANDS = [
913
1049
  summary: "\u505C\u7528\u4E00\u4E2A TikTok App\uFF08--id\uFF09",
914
1050
  run: ({ args: args2 }) => adminApps("PATCH", { id: args2.id, body: { status: "disabled" } })
915
1051
  },
916
- // ── auth link(多 app:--app 必填 serviceId,决定 backend 用哪个 app_key/secret 生成授权链接)──
1052
+ // ── auth link:skill 只传 --shop,backend 按 shop 解析用哪个 app(custom 映射→默认 public)。
1053
+ // --app 仅运维显式覆盖(可选)。二者至少给一个。──
917
1054
  {
918
1055
  name: "auth link",
919
- summary: "\u751F\u6210\u5E97\u94FA\u7ED1\u5B9A\u6388\u6743\u94FE\u63A5\uFF08--app serviceId \u5FC5\u586B\uFF0C\u53D1\u7ED9\u5546\u5BB6\u70B9\u51FB\uFF09",
1056
+ summary: "\u751F\u6210\u5E97\u94FA\u7ED1\u5B9A\u6388\u6743\u94FE\u63A5\uFF08--shop shopId\uFF0Cbackend \u6309\u5E97\u5B9A app\uFF1B--app serviceId \u53EF\u9009\u8986\u76D6\uFF09",
920
1057
  run: async ({ args: args2 }) => {
921
- if (!args2.app) {
922
- return { ok: false, error: { code: "VALIDATION", message: "--app \u5FC5\u586B\uFF08serviceId\uFF09", retryable: false } };
1058
+ if (!args2.shop && !args2.app) {
1059
+ return { ok: false, error: { code: "VALIDATION", message: "--shop\uFF08shopId\uFF09\u5FC5\u586B\uFF08\u6216 --app \u8986\u76D6\uFF09", retryable: false } };
923
1060
  }
924
- return authLink(args2.app);
1061
+ return authLink({ shop: args2.shop, app: args2.app });
925
1062
  }
926
1063
  }
927
1064
  ];
@@ -988,7 +1125,7 @@ function findCommand(tokens) {
988
1125
  }
989
1126
 
990
1127
  // src/index.ts
991
- var NO_SHOP_COMMANDS = /* @__PURE__ */ new Set(["auth link", "apps add", "apps list", "apps disable", "apps available"]);
1128
+ var NO_SHOP_COMMANDS = /* @__PURE__ */ new Set(["auth link", "apps add", "apps list", "apps disable", "apps available", "apps set-shop"]);
992
1129
  function parseFlags(tokens) {
993
1130
  const args2 = {};
994
1131
  const positional2 = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/tiktok-cli",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "TikTok Shop CLI for Optima agents — 经 tiktok-backend 操作店铺",
5
5
  "type": "module",
6
6
  "bin": {