@lynn123411/dsh-a6api 1.4.1 → 1.5.1
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 +5 -4
- package/lib/client.js +231 -159
- package/lib/client.js.map +4 -4
- package/lib/index.js +232 -147
- package/lib/index.js.map +2 -2
- package/lib/types/client/components/A6ApiSidebarCard.d.ts +2 -1
- package/lib/types/client/components/MarketPill.d.ts +6 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -810,11 +810,19 @@ async function fetchPriceFluctuation(userId, accessToken) {
|
|
|
810
810
|
let unseen = unseenPick.value;
|
|
811
811
|
const total = arr.length;
|
|
812
812
|
if (!pendingPick.present && arr.length > 0) {
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
813
|
+
const isPendingNotice = (n) => {
|
|
814
|
+
if (n?.pending === true) return true;
|
|
815
|
+
const rels = Array.isArray(n?.relations) ? n.relations : [];
|
|
816
|
+
if (rels.length > 0) {
|
|
817
|
+
return rels.some((r) => String(r?.state ?? "").toLowerCase() === "open");
|
|
818
|
+
}
|
|
819
|
+
const s = String(n?.state ?? n?.status ?? "").toLowerCase();
|
|
820
|
+
return s === "open" || s === "pending" || s === "effective";
|
|
821
|
+
};
|
|
822
|
+
const counted = arr.filter(isPendingNotice).length;
|
|
823
|
+
const hasState = arr.some(
|
|
824
|
+
(n) => n.state !== void 0 || n.status !== void 0 || Array.isArray(n.relations) && n.relations.length > 0
|
|
825
|
+
);
|
|
818
826
|
if (hasState) pending = counted;
|
|
819
827
|
}
|
|
820
828
|
if (!unseenPick.present && arr.length > 0) {
|
|
@@ -1791,6 +1799,197 @@ function overlayPinsOnModels(models, pins, tokenId) {
|
|
|
1791
1799
|
};
|
|
1792
1800
|
});
|
|
1793
1801
|
}
|
|
1802
|
+
function createUpstreamMemo(ttlMs, shouldCache) {
|
|
1803
|
+
let cache = /* @__PURE__ */ new Map();
|
|
1804
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
1805
|
+
let epoch = 0;
|
|
1806
|
+
return {
|
|
1807
|
+
/**
|
|
1808
|
+
* 数据变更后调用:旧结果立即不可用。
|
|
1809
|
+
* 同时清空在途构建表:变更完成后才到达的请求不会「加入」变更前已开始的旧构建
|
|
1810
|
+
* (旧构建的写缓存仍有代际校验兜底),而是必然发起一次新构建拿到最新数据。
|
|
1811
|
+
*/
|
|
1812
|
+
invalidate() {
|
|
1813
|
+
epoch += 1;
|
|
1814
|
+
cache.clear();
|
|
1815
|
+
inflight.clear();
|
|
1816
|
+
},
|
|
1817
|
+
async get(key, fetcher) {
|
|
1818
|
+
const hit = cache.get(key);
|
|
1819
|
+
if (hit && hit.epoch === epoch && Date.now() - hit.at < ttlMs) return hit.data;
|
|
1820
|
+
let pending = inflight.get(key);
|
|
1821
|
+
if (!pending) {
|
|
1822
|
+
const buildEpoch = epoch;
|
|
1823
|
+
const run = Promise.resolve().then(fetcher).then((data) => {
|
|
1824
|
+
if (buildEpoch === epoch && (!shouldCache || shouldCache(data))) {
|
|
1825
|
+
cache.set(key, { data, at: Date.now(), epoch: buildEpoch });
|
|
1826
|
+
}
|
|
1827
|
+
return data;
|
|
1828
|
+
}).finally(() => {
|
|
1829
|
+
if (inflight.get(key) === run) inflight.delete(key);
|
|
1830
|
+
});
|
|
1831
|
+
inflight.set(key, run);
|
|
1832
|
+
pending = run;
|
|
1833
|
+
}
|
|
1834
|
+
return pending;
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
var stateMemo = createUpstreamMemo(12e4);
|
|
1839
|
+
var priceCountsMemo = createUpstreamMemo(12e4, (counts) => !counts.authError);
|
|
1840
|
+
function stateCacheKeyOf(config) {
|
|
1841
|
+
const fingerprint = (s) => {
|
|
1842
|
+
let h = 0;
|
|
1843
|
+
for (let i = 0; i < s.length; i++) h = h * 31 + s.charCodeAt(i) | 0;
|
|
1844
|
+
return (h >>> 0).toString(36);
|
|
1845
|
+
};
|
|
1846
|
+
return `${config.baseURL || ""}|${config.userId || ""}|${fingerprint(config.apiKey || "")}|${fingerprint(config.accessToken || "")}`;
|
|
1847
|
+
}
|
|
1848
|
+
async function getCachedStateResponse(config, configAccess) {
|
|
1849
|
+
return stateMemo.get(stateCacheKeyOf(config), () => buildStateResponse(config, configAccess));
|
|
1850
|
+
}
|
|
1851
|
+
async function buildStateResponse(config, configAccess) {
|
|
1852
|
+
const token = config.accessToken || "";
|
|
1853
|
+
const [balance, dshConfiguredModels, modelIdsRaw, allLogs, pins] = await Promise.all([
|
|
1854
|
+
fetchBalance(config.baseURL, config.apiKey, config.userId, token),
|
|
1855
|
+
configAccess.getDshConfiguredModels(),
|
|
1856
|
+
config.apiKey ? fetchTokenModels(config.baseURL, config.apiKey) : Promise.resolve([]),
|
|
1857
|
+
fetchRecentLogs(config.userId, token, 100),
|
|
1858
|
+
config.userId && token ? fetchMarketplacePins(config.userId, token).catch(() => []) : Promise.resolve([])
|
|
1859
|
+
]);
|
|
1860
|
+
if (balance?.userId && String(balance.userId) !== config.userId) {
|
|
1861
|
+
tokenResolveCache = null;
|
|
1862
|
+
config.userId = String(balance.userId);
|
|
1863
|
+
await configAccess.writeConfig({ userId: config.userId });
|
|
1864
|
+
}
|
|
1865
|
+
let modelIds = modelIdsRaw;
|
|
1866
|
+
if (modelIds.length === 0) {
|
|
1867
|
+
modelIds = [
|
|
1868
|
+
.../* @__PURE__ */ new Set([
|
|
1869
|
+
...dshConfiguredModels,
|
|
1870
|
+
"gpt-5.6-sol",
|
|
1871
|
+
"gpt-5.6-terra",
|
|
1872
|
+
"gpt-5.6-luna",
|
|
1873
|
+
"claude-fable-5",
|
|
1874
|
+
"claude-opus-5",
|
|
1875
|
+
"grok-4.6"
|
|
1876
|
+
])
|
|
1877
|
+
];
|
|
1878
|
+
}
|
|
1879
|
+
allLogs.sort((a, b) => (Number(b.created_at) || 0) - (Number(a.created_at) || 0));
|
|
1880
|
+
if (config.userId || token) {
|
|
1881
|
+
const missing = modelIds.filter((m) => {
|
|
1882
|
+
const entry = merchantCardCache.get(m.toLowerCase());
|
|
1883
|
+
return !entry || Date.now() - entry.at >= MERCHANT_CARD_TTL_MS;
|
|
1884
|
+
});
|
|
1885
|
+
if (missing.length > 0) {
|
|
1886
|
+
let found = {};
|
|
1887
|
+
try {
|
|
1888
|
+
found = await Promise.race([
|
|
1889
|
+
getKnownMerchantsFromLogs(config.userId, token, missing, allLogs),
|
|
1890
|
+
new Promise((resolve2) => setTimeout(() => resolve2({}), 1e4))
|
|
1891
|
+
]);
|
|
1892
|
+
} catch {
|
|
1893
|
+
found = {};
|
|
1894
|
+
}
|
|
1895
|
+
for (const [mName, card] of Object.entries(found)) {
|
|
1896
|
+
merchantCardCache.set(mName.toLowerCase(), { card, at: Date.now() });
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
const lastRoutedMap = /* @__PURE__ */ new Map();
|
|
1901
|
+
for (const log of allLogs) {
|
|
1902
|
+
const mName = log.model_name;
|
|
1903
|
+
const chId = Number(log.channel);
|
|
1904
|
+
const ts = Number(log.created_at) || 0;
|
|
1905
|
+
if (mName && chId > 0 && ts > 0 && !lastRoutedMap.has(mName.toLowerCase())) {
|
|
1906
|
+
lastRoutedMap.set(mName.toLowerCase(), ts);
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
const dshSet = new Set(dshConfiguredModels);
|
|
1910
|
+
let models = modelIds.map((mId) => {
|
|
1911
|
+
const meta = resolveModelMeta(mId);
|
|
1912
|
+
const cacheEntry = merchantCardCache.get(mId.toLowerCase());
|
|
1913
|
+
const cachedCard = cacheEntry && Date.now() - cacheEntry.at < MERCHANT_CARD_TTL_MS ? cacheEntry.card : void 0;
|
|
1914
|
+
const routedAt = lastRoutedMap.get(mId.toLowerCase());
|
|
1915
|
+
return {
|
|
1916
|
+
model_name: mId,
|
|
1917
|
+
brand: meta.brand,
|
|
1918
|
+
contextWindow: meta.contextWindow,
|
|
1919
|
+
maxTokens: meta.maxTokens,
|
|
1920
|
+
modalities: meta.modalities,
|
|
1921
|
+
hasReasoning: Boolean(meta.reasoningEfforts || meta.thinkingFormat),
|
|
1922
|
+
inDsh: dshSet.has(mId),
|
|
1923
|
+
merchant: cachedCard,
|
|
1924
|
+
probeStatus: cachedCard ? "success" : "idle",
|
|
1925
|
+
lastRoutedAt: routedAt,
|
|
1926
|
+
lastRoutedText: routedAt ? formatRelativeTime(routedAt) : void 0
|
|
1927
|
+
};
|
|
1928
|
+
});
|
|
1929
|
+
const resolvedTokenId = pins.length > 0 ? await resolveTokenId(config) : null;
|
|
1930
|
+
models = overlayPinsOnModels(models, pins, resolvedTokenId);
|
|
1931
|
+
const rePointTargets = models.filter(
|
|
1932
|
+
(m) => m.pinStatus === "pin_elsewhere" && m.pinTokenMatched === true && m.pinnedChannelId && m.pinnedChannelId > 0
|
|
1933
|
+
).map((m) => ({ modelName: m.model_name, channelId: m.pinnedChannelId }));
|
|
1934
|
+
if (rePointTargets.length > 0 && config.userId && token) {
|
|
1935
|
+
try {
|
|
1936
|
+
await Promise.race([
|
|
1937
|
+
(async () => {
|
|
1938
|
+
for (let i = 0; i < rePointTargets.length; i += 4) {
|
|
1939
|
+
const batch = rePointTargets.slice(i, i + 4);
|
|
1940
|
+
await Promise.all(
|
|
1941
|
+
batch.map(async ({ modelName, channelId }) => {
|
|
1942
|
+
try {
|
|
1943
|
+
const pinnedCard = await fetchChannelDetails(
|
|
1944
|
+
channelId,
|
|
1945
|
+
config.userId,
|
|
1946
|
+
token,
|
|
1947
|
+
modelName
|
|
1948
|
+
);
|
|
1949
|
+
if (pinnedCard && Number(pinnedCard.channel_id) === Number(channelId)) {
|
|
1950
|
+
merchantCardCache.set(modelName.toLowerCase(), { card: pinnedCard, at: Date.now() });
|
|
1951
|
+
}
|
|
1952
|
+
} catch {
|
|
1953
|
+
}
|
|
1954
|
+
})
|
|
1955
|
+
);
|
|
1956
|
+
}
|
|
1957
|
+
})(),
|
|
1958
|
+
new Promise((resolve2) => setTimeout(() => resolve2(), 1e4))
|
|
1959
|
+
]);
|
|
1960
|
+
} catch {
|
|
1961
|
+
}
|
|
1962
|
+
models = models.map((m) => {
|
|
1963
|
+
if (m.pinStatus !== "pin_elsewhere" || m.pinTokenMatched !== true) return m;
|
|
1964
|
+
const entry = merchantCardCache.get(m.model_name.toLowerCase());
|
|
1965
|
+
const card = entry && Date.now() - entry.at < MERCHANT_CARD_TTL_MS ? entry.card : void 0;
|
|
1966
|
+
if (card && Number(card.channel_id) === Number(m.pinnedChannelId)) {
|
|
1967
|
+
const pinnedLog = allLogs.find(
|
|
1968
|
+
(l) => l.model_name?.toLowerCase() === m.model_name.toLowerCase() && Number(l.channel) === m.pinnedChannelId
|
|
1969
|
+
);
|
|
1970
|
+
const pinnedAt = pinnedLog ? Number(pinnedLog.created_at) || 0 : void 0;
|
|
1971
|
+
return {
|
|
1972
|
+
...m,
|
|
1973
|
+
merchant: card,
|
|
1974
|
+
pinStatus: "pin_here",
|
|
1975
|
+
probeStatus: "success",
|
|
1976
|
+
lastRoutedAt: pinnedAt,
|
|
1977
|
+
lastRoutedText: pinnedAt ? formatRelativeTime(pinnedAt) : void 0
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
return m;
|
|
1981
|
+
});
|
|
1982
|
+
}
|
|
1983
|
+
const recentLogs = allLogs.slice(0, 20);
|
|
1984
|
+
return {
|
|
1985
|
+
config: maskConfig(config),
|
|
1986
|
+
balance,
|
|
1987
|
+
models,
|
|
1988
|
+
dshConfiguredModels,
|
|
1989
|
+
recentLogs,
|
|
1990
|
+
pins
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1794
1993
|
function apply(ctx) {
|
|
1795
1994
|
const configAccess = createConfigAccess(ctx);
|
|
1796
1995
|
void configAccess.ensureMigrated();
|
|
@@ -1813,146 +2012,7 @@ function apply(ctx) {
|
|
|
1813
2012
|
try {
|
|
1814
2013
|
if (pathname === "/state" && (req.method === "GET" || req.method === "HEAD")) {
|
|
1815
2014
|
const config = await configAccess.readConfig();
|
|
1816
|
-
const
|
|
1817
|
-
const [balance, dshConfiguredModels, modelIdsRaw, allLogs, pins] = await Promise.all([
|
|
1818
|
-
fetchBalance(config.baseURL, config.apiKey, config.userId, token),
|
|
1819
|
-
configAccess.getDshConfiguredModels(),
|
|
1820
|
-
config.apiKey ? fetchTokenModels(config.baseURL, config.apiKey) : Promise.resolve([]),
|
|
1821
|
-
fetchRecentLogs(config.userId, token, 100),
|
|
1822
|
-
config.userId && token ? fetchMarketplacePins(config.userId, token).catch(() => []) : Promise.resolve([])
|
|
1823
|
-
]);
|
|
1824
|
-
if (balance?.userId && String(balance.userId) !== config.userId) {
|
|
1825
|
-
tokenResolveCache = null;
|
|
1826
|
-
config.userId = String(balance.userId);
|
|
1827
|
-
await configAccess.writeConfig({ userId: config.userId });
|
|
1828
|
-
}
|
|
1829
|
-
let modelIds = modelIdsRaw;
|
|
1830
|
-
if (modelIds.length === 0) {
|
|
1831
|
-
modelIds = [
|
|
1832
|
-
.../* @__PURE__ */ new Set([
|
|
1833
|
-
...dshConfiguredModels,
|
|
1834
|
-
"gpt-5.6-sol",
|
|
1835
|
-
"gpt-5.6-terra",
|
|
1836
|
-
"gpt-5.6-luna",
|
|
1837
|
-
"claude-fable-5",
|
|
1838
|
-
"claude-opus-5",
|
|
1839
|
-
"grok-4.6"
|
|
1840
|
-
])
|
|
1841
|
-
];
|
|
1842
|
-
}
|
|
1843
|
-
allLogs.sort((a, b) => (Number(b.created_at) || 0) - (Number(a.created_at) || 0));
|
|
1844
|
-
if (config.userId || token) {
|
|
1845
|
-
const missing = modelIds.filter((m) => {
|
|
1846
|
-
const entry = merchantCardCache.get(m.toLowerCase());
|
|
1847
|
-
return !entry || Date.now() - entry.at >= MERCHANT_CARD_TTL_MS;
|
|
1848
|
-
});
|
|
1849
|
-
if (missing.length > 0) {
|
|
1850
|
-
let found = {};
|
|
1851
|
-
try {
|
|
1852
|
-
found = await Promise.race([
|
|
1853
|
-
getKnownMerchantsFromLogs(config.userId, token, missing, allLogs),
|
|
1854
|
-
new Promise((resolve2) => setTimeout(() => resolve2({}), 1e4))
|
|
1855
|
-
]);
|
|
1856
|
-
} catch {
|
|
1857
|
-
found = {};
|
|
1858
|
-
}
|
|
1859
|
-
for (const [mName, card] of Object.entries(found)) {
|
|
1860
|
-
merchantCardCache.set(mName.toLowerCase(), { card, at: Date.now() });
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
const lastRoutedMap = /* @__PURE__ */ new Map();
|
|
1865
|
-
for (const log of allLogs) {
|
|
1866
|
-
const mName = log.model_name;
|
|
1867
|
-
const chId = Number(log.channel);
|
|
1868
|
-
const ts = Number(log.created_at) || 0;
|
|
1869
|
-
if (mName && chId > 0 && ts > 0 && !lastRoutedMap.has(mName.toLowerCase())) {
|
|
1870
|
-
lastRoutedMap.set(mName.toLowerCase(), ts);
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
const dshSet = new Set(dshConfiguredModels);
|
|
1874
|
-
let models = modelIds.map((mId) => {
|
|
1875
|
-
const meta = resolveModelMeta(mId);
|
|
1876
|
-
const cacheEntry = merchantCardCache.get(mId.toLowerCase());
|
|
1877
|
-
const cachedCard = cacheEntry && Date.now() - cacheEntry.at < MERCHANT_CARD_TTL_MS ? cacheEntry.card : void 0;
|
|
1878
|
-
const routedAt = lastRoutedMap.get(mId.toLowerCase());
|
|
1879
|
-
return {
|
|
1880
|
-
model_name: mId,
|
|
1881
|
-
brand: meta.brand,
|
|
1882
|
-
contextWindow: meta.contextWindow,
|
|
1883
|
-
maxTokens: meta.maxTokens,
|
|
1884
|
-
modalities: meta.modalities,
|
|
1885
|
-
hasReasoning: Boolean(meta.reasoningEfforts || meta.thinkingFormat),
|
|
1886
|
-
inDsh: dshSet.has(mId),
|
|
1887
|
-
merchant: cachedCard,
|
|
1888
|
-
probeStatus: cachedCard ? "success" : "idle",
|
|
1889
|
-
lastRoutedAt: routedAt,
|
|
1890
|
-
lastRoutedText: routedAt ? formatRelativeTime(routedAt) : void 0
|
|
1891
|
-
};
|
|
1892
|
-
});
|
|
1893
|
-
const resolvedTokenId = pins.length > 0 ? await resolveTokenId(config) : null;
|
|
1894
|
-
models = overlayPinsOnModels(models, pins, resolvedTokenId);
|
|
1895
|
-
const rePointTargets = models.filter(
|
|
1896
|
-
(m) => m.pinStatus === "pin_elsewhere" && m.pinTokenMatched === true && m.pinnedChannelId && m.pinnedChannelId > 0
|
|
1897
|
-
).map((m) => ({ modelName: m.model_name, channelId: m.pinnedChannelId }));
|
|
1898
|
-
if (rePointTargets.length > 0 && config.userId && token) {
|
|
1899
|
-
try {
|
|
1900
|
-
await Promise.race([
|
|
1901
|
-
(async () => {
|
|
1902
|
-
for (let i = 0; i < rePointTargets.length; i += 4) {
|
|
1903
|
-
const batch = rePointTargets.slice(i, i + 4);
|
|
1904
|
-
await Promise.all(
|
|
1905
|
-
batch.map(async ({ modelName, channelId }) => {
|
|
1906
|
-
try {
|
|
1907
|
-
const pinnedCard = await fetchChannelDetails(
|
|
1908
|
-
channelId,
|
|
1909
|
-
config.userId,
|
|
1910
|
-
token,
|
|
1911
|
-
modelName
|
|
1912
|
-
);
|
|
1913
|
-
if (pinnedCard && Number(pinnedCard.channel_id) === Number(channelId)) {
|
|
1914
|
-
merchantCardCache.set(modelName.toLowerCase(), { card: pinnedCard, at: Date.now() });
|
|
1915
|
-
}
|
|
1916
|
-
} catch {
|
|
1917
|
-
}
|
|
1918
|
-
})
|
|
1919
|
-
);
|
|
1920
|
-
}
|
|
1921
|
-
})(),
|
|
1922
|
-
new Promise((resolve2) => setTimeout(() => resolve2(), 1e4))
|
|
1923
|
-
]);
|
|
1924
|
-
} catch {
|
|
1925
|
-
}
|
|
1926
|
-
models = models.map((m) => {
|
|
1927
|
-
if (m.pinStatus !== "pin_elsewhere" || m.pinTokenMatched !== true) return m;
|
|
1928
|
-
const entry = merchantCardCache.get(m.model_name.toLowerCase());
|
|
1929
|
-
const card = entry && Date.now() - entry.at < MERCHANT_CARD_TTL_MS ? entry.card : void 0;
|
|
1930
|
-
if (card && Number(card.channel_id) === Number(m.pinnedChannelId)) {
|
|
1931
|
-
const pinnedLog = allLogs.find(
|
|
1932
|
-
(l) => l.model_name?.toLowerCase() === m.model_name.toLowerCase() && Number(l.channel) === m.pinnedChannelId
|
|
1933
|
-
);
|
|
1934
|
-
const pinnedAt = pinnedLog ? Number(pinnedLog.created_at) || 0 : void 0;
|
|
1935
|
-
return {
|
|
1936
|
-
...m,
|
|
1937
|
-
merchant: card,
|
|
1938
|
-
pinStatus: "pin_here",
|
|
1939
|
-
probeStatus: "success",
|
|
1940
|
-
lastRoutedAt: pinnedAt,
|
|
1941
|
-
lastRoutedText: pinnedAt ? formatRelativeTime(pinnedAt) : void 0
|
|
1942
|
-
};
|
|
1943
|
-
}
|
|
1944
|
-
return m;
|
|
1945
|
-
});
|
|
1946
|
-
}
|
|
1947
|
-
const recentLogs = allLogs.slice(0, 20);
|
|
1948
|
-
const response = {
|
|
1949
|
-
config: maskConfig(config),
|
|
1950
|
-
balance,
|
|
1951
|
-
models,
|
|
1952
|
-
dshConfiguredModels,
|
|
1953
|
-
recentLogs,
|
|
1954
|
-
pins
|
|
1955
|
-
};
|
|
2015
|
+
const response = await getCachedStateResponse(config, configAccess);
|
|
1956
2016
|
return sendJson(res, 200, { ok: true, data: response });
|
|
1957
2017
|
}
|
|
1958
2018
|
if (pathname === "/config" && req.method === "POST") {
|
|
@@ -1985,6 +2045,8 @@ function apply(ctx) {
|
|
|
1985
2045
|
if (updated.activeModels.length > 0) {
|
|
1986
2046
|
await configAccess.syncModels(updated.baseURL, updated.activeModels);
|
|
1987
2047
|
}
|
|
2048
|
+
stateMemo.invalidate();
|
|
2049
|
+
priceCountsMemo.invalidate();
|
|
1988
2050
|
return sendJson(res, 200, { ok: true, config: maskConfig(updated), balance });
|
|
1989
2051
|
}
|
|
1990
2052
|
if (pathname === "/balance" && (req.method === "GET" || req.method === "HEAD")) {
|
|
@@ -2010,6 +2072,7 @@ function apply(ctx) {
|
|
|
2010
2072
|
if (result.merchant) {
|
|
2011
2073
|
merchantCardCache.set(modelName.toLowerCase(), { card: result.merchant, at: Date.now() });
|
|
2012
2074
|
}
|
|
2075
|
+
stateMemo.invalidate();
|
|
2013
2076
|
return sendJson(res, 200, { ok: true, result });
|
|
2014
2077
|
}
|
|
2015
2078
|
let modelIds = body.modelNames;
|
|
@@ -2027,6 +2090,7 @@ function apply(ctx) {
|
|
|
2027
2090
|
}
|
|
2028
2091
|
results.push(r);
|
|
2029
2092
|
}
|
|
2093
|
+
stateMemo.invalidate();
|
|
2030
2094
|
return sendJson(res, 200, { ok: true, results });
|
|
2031
2095
|
}
|
|
2032
2096
|
if (pathname === "/sync-models" && req.method === "POST") {
|
|
@@ -2037,6 +2101,7 @@ function apply(ctx) {
|
|
|
2037
2101
|
const baseURL = body.baseURL || config.baseURL;
|
|
2038
2102
|
await configAccess.syncModels(baseURL, modelIds);
|
|
2039
2103
|
const dshConfiguredModels = await configAccess.getDshConfiguredModels();
|
|
2104
|
+
stateMemo.invalidate();
|
|
2040
2105
|
return sendJson(res, 200, { ok: true, dshConfiguredModels });
|
|
2041
2106
|
}
|
|
2042
2107
|
if (pathname === "/pin" && req.method === "POST") {
|
|
@@ -2051,8 +2116,10 @@ function apply(ctx) {
|
|
|
2051
2116
|
let card = cachedMerchantOf(modelName);
|
|
2052
2117
|
let tokenId = await resolveTokenId(config);
|
|
2053
2118
|
if ((!card || !tokenId) && config.apiKey) {
|
|
2119
|
+
let probedOk = false;
|
|
2054
2120
|
try {
|
|
2055
2121
|
const probe = await probeSingleModel(config.baseURL, config.apiKey, userId, token, modelName);
|
|
2122
|
+
probedOk = Boolean(probe && probe.success);
|
|
2056
2123
|
if (!tokenId && probe.tokenId && Number(probe.tokenId) > 0) tokenId = Number(probe.tokenId);
|
|
2057
2124
|
if (!card && probe.merchant) {
|
|
2058
2125
|
card = probe.merchant;
|
|
@@ -2060,6 +2127,7 @@ function apply(ctx) {
|
|
|
2060
2127
|
}
|
|
2061
2128
|
} catch {
|
|
2062
2129
|
}
|
|
2130
|
+
if (probedOk) stateMemo.invalidate();
|
|
2063
2131
|
}
|
|
2064
2132
|
if (!card) {
|
|
2065
2133
|
return sendJson(res, 400, { ok: false, error: "\u8BE5\u6A21\u578B\u6682\u65E0\u5546\u5BB6\u6570\u636E\uFF0C\u8BF7\u5148\u300C\u63A2\u6D4B\u5546\u5BB6\u300D" });
|
|
@@ -2086,6 +2154,7 @@ function apply(ctx) {
|
|
|
2086
2154
|
at: Date.now()
|
|
2087
2155
|
});
|
|
2088
2156
|
const pinList = await fetchMarketplacePins(userId, token);
|
|
2157
|
+
stateMemo.invalidate();
|
|
2089
2158
|
return sendJson(res, 200, { ok: true, message: `\u5DF2\u56FA\u5B9A ${modelName} \u81F3\u5546\u6237 #${card.channel_id}`, pins: pinList, tokenId });
|
|
2090
2159
|
}
|
|
2091
2160
|
if (pathname === "/unpin" && req.method === "POST") {
|
|
@@ -2113,6 +2182,7 @@ function apply(ctx) {
|
|
|
2113
2182
|
});
|
|
2114
2183
|
}
|
|
2115
2184
|
const pinList = await fetchMarketplacePins(userId, token);
|
|
2185
|
+
stateMemo.invalidate();
|
|
2116
2186
|
return sendJson(res, 200, { ok: true, message: `\u5DF2\u53D6\u6D88\u56FA\u5B9A ${modelName}`, pins: pinList, tokenId });
|
|
2117
2187
|
}
|
|
2118
2188
|
if (pathname === "/disable" && req.method === "POST") {
|
|
@@ -2122,14 +2192,17 @@ function apply(ctx) {
|
|
|
2122
2192
|
if (!modelName) return sendJson(res, 400, { ok: false, error: "\u7F3A\u5C11\u6A21\u578B\u540D\u79F0" });
|
|
2123
2193
|
let card = cachedMerchantOf(modelName);
|
|
2124
2194
|
if (!card && config.apiKey) {
|
|
2195
|
+
let probedOk = false;
|
|
2125
2196
|
try {
|
|
2126
2197
|
const probe = await probeSingleModel(config.baseURL, config.apiKey, config.userId, config.accessToken || "", modelName);
|
|
2198
|
+
probedOk = Boolean(probe && probe.success);
|
|
2127
2199
|
if (probe.merchant) {
|
|
2128
2200
|
card = probe.merchant;
|
|
2129
2201
|
merchantCardCache.set(modelName.toLowerCase(), { card, at: Date.now() });
|
|
2130
2202
|
}
|
|
2131
2203
|
} catch {
|
|
2132
2204
|
}
|
|
2205
|
+
if (probedOk) stateMemo.invalidate();
|
|
2133
2206
|
}
|
|
2134
2207
|
if (!card || !card.channel_id) {
|
|
2135
2208
|
return sendJson(res, 400, { ok: false, error: "\u8BE5\u6A21\u578B\u6682\u65E0\u5546\u5BB6\u6570\u636E\uFF0C\u8BF7\u5148\u300C\u63A2\u6D4B\u5546\u5BB6\u300D" });
|
|
@@ -2146,6 +2219,7 @@ function apply(ctx) {
|
|
|
2146
2219
|
card: { ...card, user_channel_disabled: true },
|
|
2147
2220
|
at: Date.now()
|
|
2148
2221
|
});
|
|
2222
|
+
stateMemo.invalidate();
|
|
2149
2223
|
return sendJson(res, 200, { ok: true, message: `\u5DF2\u7981\u7528\u5546\u6237 #${card.channel_id} \u5BF9\u8BE5\u6A21\u578B\u7684\u670D\u52A1` });
|
|
2150
2224
|
}
|
|
2151
2225
|
if (pathname === "/restore" && req.method === "POST") {
|
|
@@ -2155,14 +2229,17 @@ function apply(ctx) {
|
|
|
2155
2229
|
if (!modelName) return sendJson(res, 400, { ok: false, error: "\u7F3A\u5C11\u6A21\u578B\u540D\u79F0" });
|
|
2156
2230
|
let card = cachedMerchantOf(modelName);
|
|
2157
2231
|
if (!card && config.apiKey) {
|
|
2232
|
+
let probedOk = false;
|
|
2158
2233
|
try {
|
|
2159
2234
|
const probe = await probeSingleModel(config.baseURL, config.apiKey, config.userId, config.accessToken || "", modelName);
|
|
2235
|
+
probedOk = Boolean(probe && probe.success);
|
|
2160
2236
|
if (probe.merchant) {
|
|
2161
2237
|
card = probe.merchant;
|
|
2162
2238
|
merchantCardCache.set(modelName.toLowerCase(), { card, at: Date.now() });
|
|
2163
2239
|
}
|
|
2164
2240
|
} catch {
|
|
2165
2241
|
}
|
|
2242
|
+
if (probedOk) stateMemo.invalidate();
|
|
2166
2243
|
}
|
|
2167
2244
|
if (!card || !card.channel_id) {
|
|
2168
2245
|
return sendJson(res, 400, { ok: false, error: "\u8BE5\u6A21\u578B\u6682\u65E0\u5546\u5BB6\u6570\u636E\uFF0C\u8BF7\u5148\u300C\u63A2\u6D4B\u5546\u5BB6\u300D" });
|
|
@@ -2179,6 +2256,7 @@ function apply(ctx) {
|
|
|
2179
2256
|
card: { ...card, user_channel_disabled: false },
|
|
2180
2257
|
at: Date.now()
|
|
2181
2258
|
});
|
|
2259
|
+
stateMemo.invalidate();
|
|
2182
2260
|
return sendJson(res, 200, { ok: true, message: `\u5DF2\u6062\u590D\u5546\u6237 #${card.channel_id} \u5BF9\u8BE5\u6A21\u578B\u7684\u670D\u52A1` });
|
|
2183
2261
|
}
|
|
2184
2262
|
if (pathname === "/price-fluctuation" && (req.method === "GET" || req.method === "HEAD")) {
|
|
@@ -2187,8 +2265,11 @@ function apply(ctx) {
|
|
|
2187
2265
|
if (!token || !config.userId) {
|
|
2188
2266
|
return sendJson(res, 200, { ok: true, data: { pendingCount: 0, unseenCount: 0, totalCount: 0, hasAuth: false, authError: false, updatedAt: Date.now() } });
|
|
2189
2267
|
}
|
|
2190
|
-
const
|
|
2191
|
-
|
|
2268
|
+
const counts = await priceCountsMemo.get(stateCacheKeyOf(config), async () => {
|
|
2269
|
+
const result = await fetchPriceFluctuation(config.userId, token);
|
|
2270
|
+
const { notices, ...rest } = result;
|
|
2271
|
+
return rest;
|
|
2272
|
+
});
|
|
2192
2273
|
const hasAuth = !counts.authError;
|
|
2193
2274
|
return sendJson(res, 200, { ok: true, data: { pendingCount: counts.pendingCount, unseenCount: counts.unseenCount, totalCount: counts.totalCount, hasAuth, authError: Boolean(counts.authError), updatedAt: Date.now() } });
|
|
2194
2275
|
}
|
|
@@ -2211,6 +2292,7 @@ function apply(ctx) {
|
|
|
2211
2292
|
}
|
|
2212
2293
|
if (pathname === "/catalog/clear" && req.method === "POST") {
|
|
2213
2294
|
await clearCatalog();
|
|
2295
|
+
stateMemo.invalidate();
|
|
2214
2296
|
return sendJson(res, 200, { ok: true });
|
|
2215
2297
|
}
|
|
2216
2298
|
if (pathname === "/catalog/fetch-models" && req.method === "POST") {
|
|
@@ -2231,6 +2313,7 @@ function apply(ctx) {
|
|
|
2231
2313
|
await upsertCatalogEntries(
|
|
2232
2314
|
models.map((m) => ({ id: m.id, brand: m.brand, reasoningEfforts: m.reasoningEfforts }))
|
|
2233
2315
|
);
|
|
2316
|
+
stateMemo.invalidate();
|
|
2234
2317
|
return sendJson(res, 200, {
|
|
2235
2318
|
ok: true,
|
|
2236
2319
|
total: models.length,
|
|
@@ -2246,6 +2329,7 @@ function apply(ctx) {
|
|
|
2246
2329
|
return sendJson(res, 400, { ok: false, error: "\u76EE\u5F55\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u300C\u4ECE A6API \u83B7\u53D6\u5E02\u573A\u6A21\u578B\u300D" });
|
|
2247
2330
|
}
|
|
2248
2331
|
const result = await queryOpenRouter(modelIds);
|
|
2332
|
+
stateMemo.invalidate();
|
|
2249
2333
|
return sendJson(res, 200, {
|
|
2250
2334
|
ok: true,
|
|
2251
2335
|
updated: result.updated.length,
|
|
@@ -2308,6 +2392,7 @@ function apply(ctx) {
|
|
|
2308
2392
|
} catch (err) {
|
|
2309
2393
|
console.warn("[dsh-a6api] catalog update: resync settings failed:", err?.message || err);
|
|
2310
2394
|
}
|
|
2395
|
+
stateMemo.invalidate();
|
|
2311
2396
|
return sendJson(res, 200, { ok: true, entry });
|
|
2312
2397
|
}
|
|
2313
2398
|
return sendJson(res, 404, { ok: false, error: "Not found" });
|