@lynn123411/dsh-a6api 1.5.0 → 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/lib/client.js +2 -1
- package/lib/client.js.map +2 -2
- package/lib/index.js +219 -142
- package/lib/index.js.map +2 -2
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1799,6 +1799,197 @@ function overlayPinsOnModels(models, pins, tokenId) {
|
|
|
1799
1799
|
};
|
|
1800
1800
|
});
|
|
1801
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
|
+
}
|
|
1802
1993
|
function apply(ctx) {
|
|
1803
1994
|
const configAccess = createConfigAccess(ctx);
|
|
1804
1995
|
void configAccess.ensureMigrated();
|
|
@@ -1821,146 +2012,7 @@ function apply(ctx) {
|
|
|
1821
2012
|
try {
|
|
1822
2013
|
if (pathname === "/state" && (req.method === "GET" || req.method === "HEAD")) {
|
|
1823
2014
|
const config = await configAccess.readConfig();
|
|
1824
|
-
const
|
|
1825
|
-
const [balance, dshConfiguredModels, modelIdsRaw, allLogs, pins] = await Promise.all([
|
|
1826
|
-
fetchBalance(config.baseURL, config.apiKey, config.userId, token),
|
|
1827
|
-
configAccess.getDshConfiguredModels(),
|
|
1828
|
-
config.apiKey ? fetchTokenModels(config.baseURL, config.apiKey) : Promise.resolve([]),
|
|
1829
|
-
fetchRecentLogs(config.userId, token, 100),
|
|
1830
|
-
config.userId && token ? fetchMarketplacePins(config.userId, token).catch(() => []) : Promise.resolve([])
|
|
1831
|
-
]);
|
|
1832
|
-
if (balance?.userId && String(balance.userId) !== config.userId) {
|
|
1833
|
-
tokenResolveCache = null;
|
|
1834
|
-
config.userId = String(balance.userId);
|
|
1835
|
-
await configAccess.writeConfig({ userId: config.userId });
|
|
1836
|
-
}
|
|
1837
|
-
let modelIds = modelIdsRaw;
|
|
1838
|
-
if (modelIds.length === 0) {
|
|
1839
|
-
modelIds = [
|
|
1840
|
-
.../* @__PURE__ */ new Set([
|
|
1841
|
-
...dshConfiguredModels,
|
|
1842
|
-
"gpt-5.6-sol",
|
|
1843
|
-
"gpt-5.6-terra",
|
|
1844
|
-
"gpt-5.6-luna",
|
|
1845
|
-
"claude-fable-5",
|
|
1846
|
-
"claude-opus-5",
|
|
1847
|
-
"grok-4.6"
|
|
1848
|
-
])
|
|
1849
|
-
];
|
|
1850
|
-
}
|
|
1851
|
-
allLogs.sort((a, b) => (Number(b.created_at) || 0) - (Number(a.created_at) || 0));
|
|
1852
|
-
if (config.userId || token) {
|
|
1853
|
-
const missing = modelIds.filter((m) => {
|
|
1854
|
-
const entry = merchantCardCache.get(m.toLowerCase());
|
|
1855
|
-
return !entry || Date.now() - entry.at >= MERCHANT_CARD_TTL_MS;
|
|
1856
|
-
});
|
|
1857
|
-
if (missing.length > 0) {
|
|
1858
|
-
let found = {};
|
|
1859
|
-
try {
|
|
1860
|
-
found = await Promise.race([
|
|
1861
|
-
getKnownMerchantsFromLogs(config.userId, token, missing, allLogs),
|
|
1862
|
-
new Promise((resolve2) => setTimeout(() => resolve2({}), 1e4))
|
|
1863
|
-
]);
|
|
1864
|
-
} catch {
|
|
1865
|
-
found = {};
|
|
1866
|
-
}
|
|
1867
|
-
for (const [mName, card] of Object.entries(found)) {
|
|
1868
|
-
merchantCardCache.set(mName.toLowerCase(), { card, at: Date.now() });
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
const lastRoutedMap = /* @__PURE__ */ new Map();
|
|
1873
|
-
for (const log of allLogs) {
|
|
1874
|
-
const mName = log.model_name;
|
|
1875
|
-
const chId = Number(log.channel);
|
|
1876
|
-
const ts = Number(log.created_at) || 0;
|
|
1877
|
-
if (mName && chId > 0 && ts > 0 && !lastRoutedMap.has(mName.toLowerCase())) {
|
|
1878
|
-
lastRoutedMap.set(mName.toLowerCase(), ts);
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
const dshSet = new Set(dshConfiguredModels);
|
|
1882
|
-
let models = modelIds.map((mId) => {
|
|
1883
|
-
const meta = resolveModelMeta(mId);
|
|
1884
|
-
const cacheEntry = merchantCardCache.get(mId.toLowerCase());
|
|
1885
|
-
const cachedCard = cacheEntry && Date.now() - cacheEntry.at < MERCHANT_CARD_TTL_MS ? cacheEntry.card : void 0;
|
|
1886
|
-
const routedAt = lastRoutedMap.get(mId.toLowerCase());
|
|
1887
|
-
return {
|
|
1888
|
-
model_name: mId,
|
|
1889
|
-
brand: meta.brand,
|
|
1890
|
-
contextWindow: meta.contextWindow,
|
|
1891
|
-
maxTokens: meta.maxTokens,
|
|
1892
|
-
modalities: meta.modalities,
|
|
1893
|
-
hasReasoning: Boolean(meta.reasoningEfforts || meta.thinkingFormat),
|
|
1894
|
-
inDsh: dshSet.has(mId),
|
|
1895
|
-
merchant: cachedCard,
|
|
1896
|
-
probeStatus: cachedCard ? "success" : "idle",
|
|
1897
|
-
lastRoutedAt: routedAt,
|
|
1898
|
-
lastRoutedText: routedAt ? formatRelativeTime(routedAt) : void 0
|
|
1899
|
-
};
|
|
1900
|
-
});
|
|
1901
|
-
const resolvedTokenId = pins.length > 0 ? await resolveTokenId(config) : null;
|
|
1902
|
-
models = overlayPinsOnModels(models, pins, resolvedTokenId);
|
|
1903
|
-
const rePointTargets = models.filter(
|
|
1904
|
-
(m) => m.pinStatus === "pin_elsewhere" && m.pinTokenMatched === true && m.pinnedChannelId && m.pinnedChannelId > 0
|
|
1905
|
-
).map((m) => ({ modelName: m.model_name, channelId: m.pinnedChannelId }));
|
|
1906
|
-
if (rePointTargets.length > 0 && config.userId && token) {
|
|
1907
|
-
try {
|
|
1908
|
-
await Promise.race([
|
|
1909
|
-
(async () => {
|
|
1910
|
-
for (let i = 0; i < rePointTargets.length; i += 4) {
|
|
1911
|
-
const batch = rePointTargets.slice(i, i + 4);
|
|
1912
|
-
await Promise.all(
|
|
1913
|
-
batch.map(async ({ modelName, channelId }) => {
|
|
1914
|
-
try {
|
|
1915
|
-
const pinnedCard = await fetchChannelDetails(
|
|
1916
|
-
channelId,
|
|
1917
|
-
config.userId,
|
|
1918
|
-
token,
|
|
1919
|
-
modelName
|
|
1920
|
-
);
|
|
1921
|
-
if (pinnedCard && Number(pinnedCard.channel_id) === Number(channelId)) {
|
|
1922
|
-
merchantCardCache.set(modelName.toLowerCase(), { card: pinnedCard, at: Date.now() });
|
|
1923
|
-
}
|
|
1924
|
-
} catch {
|
|
1925
|
-
}
|
|
1926
|
-
})
|
|
1927
|
-
);
|
|
1928
|
-
}
|
|
1929
|
-
})(),
|
|
1930
|
-
new Promise((resolve2) => setTimeout(() => resolve2(), 1e4))
|
|
1931
|
-
]);
|
|
1932
|
-
} catch {
|
|
1933
|
-
}
|
|
1934
|
-
models = models.map((m) => {
|
|
1935
|
-
if (m.pinStatus !== "pin_elsewhere" || m.pinTokenMatched !== true) return m;
|
|
1936
|
-
const entry = merchantCardCache.get(m.model_name.toLowerCase());
|
|
1937
|
-
const card = entry && Date.now() - entry.at < MERCHANT_CARD_TTL_MS ? entry.card : void 0;
|
|
1938
|
-
if (card && Number(card.channel_id) === Number(m.pinnedChannelId)) {
|
|
1939
|
-
const pinnedLog = allLogs.find(
|
|
1940
|
-
(l) => l.model_name?.toLowerCase() === m.model_name.toLowerCase() && Number(l.channel) === m.pinnedChannelId
|
|
1941
|
-
);
|
|
1942
|
-
const pinnedAt = pinnedLog ? Number(pinnedLog.created_at) || 0 : void 0;
|
|
1943
|
-
return {
|
|
1944
|
-
...m,
|
|
1945
|
-
merchant: card,
|
|
1946
|
-
pinStatus: "pin_here",
|
|
1947
|
-
probeStatus: "success",
|
|
1948
|
-
lastRoutedAt: pinnedAt,
|
|
1949
|
-
lastRoutedText: pinnedAt ? formatRelativeTime(pinnedAt) : void 0
|
|
1950
|
-
};
|
|
1951
|
-
}
|
|
1952
|
-
return m;
|
|
1953
|
-
});
|
|
1954
|
-
}
|
|
1955
|
-
const recentLogs = allLogs.slice(0, 20);
|
|
1956
|
-
const response = {
|
|
1957
|
-
config: maskConfig(config),
|
|
1958
|
-
balance,
|
|
1959
|
-
models,
|
|
1960
|
-
dshConfiguredModels,
|
|
1961
|
-
recentLogs,
|
|
1962
|
-
pins
|
|
1963
|
-
};
|
|
2015
|
+
const response = await getCachedStateResponse(config, configAccess);
|
|
1964
2016
|
return sendJson(res, 200, { ok: true, data: response });
|
|
1965
2017
|
}
|
|
1966
2018
|
if (pathname === "/config" && req.method === "POST") {
|
|
@@ -1993,6 +2045,8 @@ function apply(ctx) {
|
|
|
1993
2045
|
if (updated.activeModels.length > 0) {
|
|
1994
2046
|
await configAccess.syncModels(updated.baseURL, updated.activeModels);
|
|
1995
2047
|
}
|
|
2048
|
+
stateMemo.invalidate();
|
|
2049
|
+
priceCountsMemo.invalidate();
|
|
1996
2050
|
return sendJson(res, 200, { ok: true, config: maskConfig(updated), balance });
|
|
1997
2051
|
}
|
|
1998
2052
|
if (pathname === "/balance" && (req.method === "GET" || req.method === "HEAD")) {
|
|
@@ -2018,6 +2072,7 @@ function apply(ctx) {
|
|
|
2018
2072
|
if (result.merchant) {
|
|
2019
2073
|
merchantCardCache.set(modelName.toLowerCase(), { card: result.merchant, at: Date.now() });
|
|
2020
2074
|
}
|
|
2075
|
+
stateMemo.invalidate();
|
|
2021
2076
|
return sendJson(res, 200, { ok: true, result });
|
|
2022
2077
|
}
|
|
2023
2078
|
let modelIds = body.modelNames;
|
|
@@ -2035,6 +2090,7 @@ function apply(ctx) {
|
|
|
2035
2090
|
}
|
|
2036
2091
|
results.push(r);
|
|
2037
2092
|
}
|
|
2093
|
+
stateMemo.invalidate();
|
|
2038
2094
|
return sendJson(res, 200, { ok: true, results });
|
|
2039
2095
|
}
|
|
2040
2096
|
if (pathname === "/sync-models" && req.method === "POST") {
|
|
@@ -2045,6 +2101,7 @@ function apply(ctx) {
|
|
|
2045
2101
|
const baseURL = body.baseURL || config.baseURL;
|
|
2046
2102
|
await configAccess.syncModels(baseURL, modelIds);
|
|
2047
2103
|
const dshConfiguredModels = await configAccess.getDshConfiguredModels();
|
|
2104
|
+
stateMemo.invalidate();
|
|
2048
2105
|
return sendJson(res, 200, { ok: true, dshConfiguredModels });
|
|
2049
2106
|
}
|
|
2050
2107
|
if (pathname === "/pin" && req.method === "POST") {
|
|
@@ -2059,8 +2116,10 @@ function apply(ctx) {
|
|
|
2059
2116
|
let card = cachedMerchantOf(modelName);
|
|
2060
2117
|
let tokenId = await resolveTokenId(config);
|
|
2061
2118
|
if ((!card || !tokenId) && config.apiKey) {
|
|
2119
|
+
let probedOk = false;
|
|
2062
2120
|
try {
|
|
2063
2121
|
const probe = await probeSingleModel(config.baseURL, config.apiKey, userId, token, modelName);
|
|
2122
|
+
probedOk = Boolean(probe && probe.success);
|
|
2064
2123
|
if (!tokenId && probe.tokenId && Number(probe.tokenId) > 0) tokenId = Number(probe.tokenId);
|
|
2065
2124
|
if (!card && probe.merchant) {
|
|
2066
2125
|
card = probe.merchant;
|
|
@@ -2068,6 +2127,7 @@ function apply(ctx) {
|
|
|
2068
2127
|
}
|
|
2069
2128
|
} catch {
|
|
2070
2129
|
}
|
|
2130
|
+
if (probedOk) stateMemo.invalidate();
|
|
2071
2131
|
}
|
|
2072
2132
|
if (!card) {
|
|
2073
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" });
|
|
@@ -2094,6 +2154,7 @@ function apply(ctx) {
|
|
|
2094
2154
|
at: Date.now()
|
|
2095
2155
|
});
|
|
2096
2156
|
const pinList = await fetchMarketplacePins(userId, token);
|
|
2157
|
+
stateMemo.invalidate();
|
|
2097
2158
|
return sendJson(res, 200, { ok: true, message: `\u5DF2\u56FA\u5B9A ${modelName} \u81F3\u5546\u6237 #${card.channel_id}`, pins: pinList, tokenId });
|
|
2098
2159
|
}
|
|
2099
2160
|
if (pathname === "/unpin" && req.method === "POST") {
|
|
@@ -2121,6 +2182,7 @@ function apply(ctx) {
|
|
|
2121
2182
|
});
|
|
2122
2183
|
}
|
|
2123
2184
|
const pinList = await fetchMarketplacePins(userId, token);
|
|
2185
|
+
stateMemo.invalidate();
|
|
2124
2186
|
return sendJson(res, 200, { ok: true, message: `\u5DF2\u53D6\u6D88\u56FA\u5B9A ${modelName}`, pins: pinList, tokenId });
|
|
2125
2187
|
}
|
|
2126
2188
|
if (pathname === "/disable" && req.method === "POST") {
|
|
@@ -2130,14 +2192,17 @@ function apply(ctx) {
|
|
|
2130
2192
|
if (!modelName) return sendJson(res, 400, { ok: false, error: "\u7F3A\u5C11\u6A21\u578B\u540D\u79F0" });
|
|
2131
2193
|
let card = cachedMerchantOf(modelName);
|
|
2132
2194
|
if (!card && config.apiKey) {
|
|
2195
|
+
let probedOk = false;
|
|
2133
2196
|
try {
|
|
2134
2197
|
const probe = await probeSingleModel(config.baseURL, config.apiKey, config.userId, config.accessToken || "", modelName);
|
|
2198
|
+
probedOk = Boolean(probe && probe.success);
|
|
2135
2199
|
if (probe.merchant) {
|
|
2136
2200
|
card = probe.merchant;
|
|
2137
2201
|
merchantCardCache.set(modelName.toLowerCase(), { card, at: Date.now() });
|
|
2138
2202
|
}
|
|
2139
2203
|
} catch {
|
|
2140
2204
|
}
|
|
2205
|
+
if (probedOk) stateMemo.invalidate();
|
|
2141
2206
|
}
|
|
2142
2207
|
if (!card || !card.channel_id) {
|
|
2143
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" });
|
|
@@ -2154,6 +2219,7 @@ function apply(ctx) {
|
|
|
2154
2219
|
card: { ...card, user_channel_disabled: true },
|
|
2155
2220
|
at: Date.now()
|
|
2156
2221
|
});
|
|
2222
|
+
stateMemo.invalidate();
|
|
2157
2223
|
return sendJson(res, 200, { ok: true, message: `\u5DF2\u7981\u7528\u5546\u6237 #${card.channel_id} \u5BF9\u8BE5\u6A21\u578B\u7684\u670D\u52A1` });
|
|
2158
2224
|
}
|
|
2159
2225
|
if (pathname === "/restore" && req.method === "POST") {
|
|
@@ -2163,14 +2229,17 @@ function apply(ctx) {
|
|
|
2163
2229
|
if (!modelName) return sendJson(res, 400, { ok: false, error: "\u7F3A\u5C11\u6A21\u578B\u540D\u79F0" });
|
|
2164
2230
|
let card = cachedMerchantOf(modelName);
|
|
2165
2231
|
if (!card && config.apiKey) {
|
|
2232
|
+
let probedOk = false;
|
|
2166
2233
|
try {
|
|
2167
2234
|
const probe = await probeSingleModel(config.baseURL, config.apiKey, config.userId, config.accessToken || "", modelName);
|
|
2235
|
+
probedOk = Boolean(probe && probe.success);
|
|
2168
2236
|
if (probe.merchant) {
|
|
2169
2237
|
card = probe.merchant;
|
|
2170
2238
|
merchantCardCache.set(modelName.toLowerCase(), { card, at: Date.now() });
|
|
2171
2239
|
}
|
|
2172
2240
|
} catch {
|
|
2173
2241
|
}
|
|
2242
|
+
if (probedOk) stateMemo.invalidate();
|
|
2174
2243
|
}
|
|
2175
2244
|
if (!card || !card.channel_id) {
|
|
2176
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" });
|
|
@@ -2187,6 +2256,7 @@ function apply(ctx) {
|
|
|
2187
2256
|
card: { ...card, user_channel_disabled: false },
|
|
2188
2257
|
at: Date.now()
|
|
2189
2258
|
});
|
|
2259
|
+
stateMemo.invalidate();
|
|
2190
2260
|
return sendJson(res, 200, { ok: true, message: `\u5DF2\u6062\u590D\u5546\u6237 #${card.channel_id} \u5BF9\u8BE5\u6A21\u578B\u7684\u670D\u52A1` });
|
|
2191
2261
|
}
|
|
2192
2262
|
if (pathname === "/price-fluctuation" && (req.method === "GET" || req.method === "HEAD")) {
|
|
@@ -2195,8 +2265,11 @@ function apply(ctx) {
|
|
|
2195
2265
|
if (!token || !config.userId) {
|
|
2196
2266
|
return sendJson(res, 200, { ok: true, data: { pendingCount: 0, unseenCount: 0, totalCount: 0, hasAuth: false, authError: false, updatedAt: Date.now() } });
|
|
2197
2267
|
}
|
|
2198
|
-
const
|
|
2199
|
-
|
|
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
|
+
});
|
|
2200
2273
|
const hasAuth = !counts.authError;
|
|
2201
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() } });
|
|
2202
2275
|
}
|
|
@@ -2219,6 +2292,7 @@ function apply(ctx) {
|
|
|
2219
2292
|
}
|
|
2220
2293
|
if (pathname === "/catalog/clear" && req.method === "POST") {
|
|
2221
2294
|
await clearCatalog();
|
|
2295
|
+
stateMemo.invalidate();
|
|
2222
2296
|
return sendJson(res, 200, { ok: true });
|
|
2223
2297
|
}
|
|
2224
2298
|
if (pathname === "/catalog/fetch-models" && req.method === "POST") {
|
|
@@ -2239,6 +2313,7 @@ function apply(ctx) {
|
|
|
2239
2313
|
await upsertCatalogEntries(
|
|
2240
2314
|
models.map((m) => ({ id: m.id, brand: m.brand, reasoningEfforts: m.reasoningEfforts }))
|
|
2241
2315
|
);
|
|
2316
|
+
stateMemo.invalidate();
|
|
2242
2317
|
return sendJson(res, 200, {
|
|
2243
2318
|
ok: true,
|
|
2244
2319
|
total: models.length,
|
|
@@ -2254,6 +2329,7 @@ function apply(ctx) {
|
|
|
2254
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" });
|
|
2255
2330
|
}
|
|
2256
2331
|
const result = await queryOpenRouter(modelIds);
|
|
2332
|
+
stateMemo.invalidate();
|
|
2257
2333
|
return sendJson(res, 200, {
|
|
2258
2334
|
ok: true,
|
|
2259
2335
|
updated: result.updated.length,
|
|
@@ -2316,6 +2392,7 @@ function apply(ctx) {
|
|
|
2316
2392
|
} catch (err) {
|
|
2317
2393
|
console.warn("[dsh-a6api] catalog update: resync settings failed:", err?.message || err);
|
|
2318
2394
|
}
|
|
2395
|
+
stateMemo.invalidate();
|
|
2319
2396
|
return sendJson(res, 200, { ok: true, entry });
|
|
2320
2397
|
}
|
|
2321
2398
|
return sendJson(res, 404, { ok: false, error: "Not found" });
|