@lynn123411/dsh-a6api 1.0.1 → 1.2.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/lib/index.js CHANGED
@@ -892,6 +892,66 @@ async function fetchChannelDetails(channelId, userId, sessionCookie, targetModel
892
892
  }
893
893
  return null;
894
894
  }
895
+ async function fetchPriceFluctuation(userId, sessionCookie, accessToken) {
896
+ const token = (accessToken || sessionCookie || "").trim();
897
+ const uid = (userId || "").trim();
898
+ if (!uid && !token) {
899
+ return { pendingCount: 0, unseenCount: 0, totalCount: 0, authError: false };
900
+ }
901
+ const headers = buildWebHeaders(uid || void 0, token || void 0);
902
+ const url = "https://a6api.com/api/marketplace/price-notices";
903
+ try {
904
+ const res = await fetch(url, { headers, signal: AbortSignal.timeout(8e3) });
905
+ if (res.status === 401 || res.status === 403) {
906
+ console.warn("[dsh-a6api] fetchPriceFluctuation auth failed", res.status);
907
+ return { pendingCount: 0, unseenCount: 0, totalCount: 0, authError: true };
908
+ }
909
+ if (!res.ok) {
910
+ console.warn("[dsh-a6api] fetchPriceFluctuation HTTP", res.status);
911
+ return { pendingCount: 0, unseenCount: 0, totalCount: 0 };
912
+ }
913
+ const json = await res.json().catch(() => null);
914
+ if (!json) return { pendingCount: 0, unseenCount: 0, totalCount: 0 };
915
+ if (json.success === false) return { pendingCount: 0, unseenCount: 0, totalCount: 0 };
916
+ let arr = [];
917
+ if (Array.isArray(json)) arr = json;
918
+ else if (Array.isArray(json.data)) arr = json.data;
919
+ else if (Array.isArray(json.data?.notices)) arr = json.data.notices;
920
+ else if (Array.isArray(json.data?.items)) arr = json.data.items;
921
+ else if (Array.isArray(json.notices)) arr = json.notices;
922
+ else if (Array.isArray(json.items)) arr = json.items;
923
+ const pickWithPresent = (keys) => {
924
+ for (const k of keys) {
925
+ const v = json?.data?.[k] ?? json?.[k];
926
+ if (v !== void 0 && v !== null) {
927
+ const n = Number(v);
928
+ if (!Number.isNaN(n)) return { value: n, present: true };
929
+ }
930
+ }
931
+ return { value: 0, present: false };
932
+ };
933
+ const pendingPick = pickWithPresent(["pendingCount", "pending_count", "pending", "openCount"]);
934
+ const unseenPick = pickWithPresent(["unseenCount", "unseen_count", "unseen", "has_unseen_count"]);
935
+ let pending = pendingPick.value;
936
+ let unseen = unseenPick.value;
937
+ const total = arr.length;
938
+ if (!pendingPick.present && arr.length > 0) {
939
+ const counted = arr.filter((n) => {
940
+ const s = String(n.state || n.status || "").toLowerCase();
941
+ return s === "open" || s === "pending" || n.pending === true;
942
+ }).length;
943
+ const hasState = arr.some((n) => n.state !== void 0 || n.status !== void 0);
944
+ if (hasState) pending = counted;
945
+ }
946
+ if (!unseenPick.present && arr.length > 0) {
947
+ unseen = arr.filter((n) => n.has_unseen === true || n.hasUnseen === true || n.unseen === true || n.is_unread === true).length;
948
+ }
949
+ return { pendingCount: pending, unseenCount: unseen, totalCount: total, notices: arr };
950
+ } catch (err) {
951
+ console.warn("[dsh-a6api] fetchPriceFluctuation error", err);
952
+ return { pendingCount: 0, unseenCount: 0, totalCount: 0 };
953
+ }
954
+ }
895
955
 
896
956
  // src/server/probe.ts
897
957
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -972,13 +1032,14 @@ async function probeSingleModel(baseURL, apiKey, userId, accessToken, modelName)
972
1032
  error: requestOk ? void 0 : requestError
973
1033
  };
974
1034
  }
975
- async function getKnownMerchantsFromLogs(userId, accessToken, modelNames = []) {
1035
+ async function getKnownMerchantsFromLogs(userId, accessToken, modelNames = [], logs) {
976
1036
  if (!userId && !accessToken || modelNames.length === 0) return {};
977
1037
  const result = {};
978
1038
  try {
979
- const logs = await fetchRecentLogs(userId, accessToken, 50);
1039
+ const items = logs !== void 0 ? logs : await fetchRecentLogs(userId, accessToken, 50);
1040
+ const sorted = items.slice().sort((a, b) => (Number(b.created_at) || 0) - (Number(a.created_at) || 0));
980
1041
  const modelToLog = /* @__PURE__ */ new Map();
981
- for (const log of logs) {
1042
+ for (const log of sorted) {
982
1043
  const mName = log.model_name;
983
1044
  const chId = Number(log.channel);
984
1045
  if (mName && chId && !modelToLog.has(mName.toLowerCase())) {
@@ -1377,23 +1438,43 @@ function apply(ctx) {
1377
1438
  ])
1378
1439
  ];
1379
1440
  }
1441
+ const allLogs = await fetchRecentLogs(config.userId, token, 100);
1442
+ allLogs.sort((a, b) => (Number(b.created_at) || 0) - (Number(a.created_at) || 0));
1380
1443
  if (config.userId || token) {
1381
1444
  const missing = modelIds.filter((m) => {
1382
1445
  const entry = merchantCardCache.get(m.toLowerCase());
1383
1446
  return !entry || Date.now() - entry.at >= MERCHANT_CARD_TTL_MS;
1384
1447
  });
1385
1448
  if (missing.length > 0) {
1386
- const found = await getKnownMerchantsFromLogs(config.userId, token, missing);
1449
+ let found = {};
1450
+ try {
1451
+ found = await Promise.race([
1452
+ getKnownMerchantsFromLogs(config.userId, token, missing, allLogs),
1453
+ new Promise((resolve) => setTimeout(() => resolve({}), 1e4))
1454
+ ]);
1455
+ } catch {
1456
+ found = {};
1457
+ }
1387
1458
  for (const [mName, card] of Object.entries(found)) {
1388
1459
  merchantCardCache.set(mName.toLowerCase(), { card, at: Date.now() });
1389
1460
  }
1390
1461
  }
1391
1462
  }
1463
+ const lastRoutedMap = /* @__PURE__ */ new Map();
1464
+ for (const log of allLogs) {
1465
+ const mName = log.model_name;
1466
+ const chId = Number(log.channel);
1467
+ const ts = Number(log.created_at) || 0;
1468
+ if (mName && chId > 0 && ts > 0 && !lastRoutedMap.has(mName.toLowerCase())) {
1469
+ lastRoutedMap.set(mName.toLowerCase(), ts);
1470
+ }
1471
+ }
1392
1472
  const dshSet = new Set(dshConfiguredModels);
1393
1473
  const models = modelIds.map((mId) => {
1394
1474
  const meta = resolveModelMeta(mId);
1395
1475
  const cacheEntry = merchantCardCache.get(mId.toLowerCase());
1396
1476
  const cachedCard = cacheEntry && Date.now() - cacheEntry.at < MERCHANT_CARD_TTL_MS ? cacheEntry.card : void 0;
1477
+ const routedAt = lastRoutedMap.get(mId.toLowerCase());
1397
1478
  return {
1398
1479
  model_name: mId,
1399
1480
  brand: meta.brand,
@@ -1403,10 +1484,12 @@ function apply(ctx) {
1403
1484
  hasReasoning: Boolean(meta.reasoningEfforts || meta.thinkingFormat),
1404
1485
  inDsh: dshSet.has(mId),
1405
1486
  merchant: cachedCard,
1406
- probeStatus: cachedCard ? "success" : "idle"
1487
+ probeStatus: cachedCard ? "success" : "idle",
1488
+ lastRoutedAt: routedAt,
1489
+ lastRoutedText: routedAt ? formatRelativeTime(routedAt) : void 0
1407
1490
  };
1408
1491
  });
1409
- const recentLogs = await fetchRecentLogs(config.userId, token, 20);
1492
+ const recentLogs = allLogs.slice(0, 20);
1410
1493
  const response = {
1411
1494
  config: maskConfig(config),
1412
1495
  balance,
@@ -1494,6 +1577,17 @@ function apply(ctx) {
1494
1577
  const dshConfiguredModels = await getDshConfiguredModels();
1495
1578
  return sendJson(res, 200, { ok: true, dshConfiguredModels });
1496
1579
  }
1580
+ if (pathname === "/price-fluctuation" && (req.method === "GET" || req.method === "HEAD")) {
1581
+ const config = await readPluginConfig();
1582
+ const token = config.accessToken || config.sessionCookie || "";
1583
+ if (!token || !config.userId) {
1584
+ return sendJson(res, 200, { ok: true, data: { pendingCount: 0, unseenCount: 0, totalCount: 0, hasAuth: false, authError: false, updatedAt: Date.now() } });
1585
+ }
1586
+ const result = await fetchPriceFluctuation(config.userId, token, token);
1587
+ const { notices, ...counts } = result;
1588
+ const hasAuth = !counts.authError;
1589
+ return sendJson(res, 200, { ok: true, data: { pendingCount: counts.pendingCount, unseenCount: counts.unseenCount, totalCount: counts.totalCount, hasAuth, authError: Boolean(counts.authError), updatedAt: Date.now() } });
1590
+ }
1497
1591
  return sendJson(res, 404, { ok: false, error: "Not found" });
1498
1592
  } catch (err) {
1499
1593
  console.error("[dsh-a6api] API error:", err);