This version of Antigravity is no longer supported. Please upgrade to receive the latest features.

This commit is contained in:
2569718930@qq.com
2026-04-30 09:59:40 +08:00
parent 96dfb4c5b3
commit 6603515433
3 changed files with 68 additions and 3 deletions
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
import {
buildCityMarketScanCacheKey,
deriveCityMarketScanView,
normalizeCityMarketScanPayload,
resolveCityMarketScanSnapshot,
writeCachedCityMarketScan,
} from "@/components/dashboard/scan-terminal/market-scan-state";
@@ -74,6 +75,35 @@ export function runTests() {
assert.equal((cachedSnapshot.payload as unknown as { label: string }).label, "cached");
}
storage.clear();
writeCachedCityMarketScan(cacheKey, {
market_scan: {
available: true,
market_price: 0.41,
selected_slug: "highest-temperature-in-nyc-on-april-30-2026-60-61f",
},
selected_date: "2026-04-30",
} as unknown as MarketScan);
const wrappedCachedSnapshot = resolveCityMarketScanSnapshot({
detail: cityDetail(),
detailCityName: "Test City",
enabled: true,
});
assert.equal(wrappedCachedSnapshot.action, "success");
if (wrappedCachedSnapshot.action === "success") {
assert.equal(wrappedCachedSnapshot.payload.available, true);
assert.equal(wrappedCachedSnapshot.payload.market_price, 0.41);
assert.equal(wrappedCachedSnapshot.payload.selected_date, "2026-04-30");
}
const wrappedResponse = normalizeCityMarketScanPayload({
market_scan: { available: true, yes_buy: 0.42 } as MarketScan,
selected_date: "2026-04-30",
});
assert.equal(wrappedResponse?.available, true);
assert.equal(wrappedResponse?.yes_buy, 0.42);
assert.equal(wrappedResponse?.selected_date, "2026-04-30");
storage.clear();
assert.equal(
resolveCityMarketScanSnapshot({
@@ -7,11 +7,19 @@ import type { RemoteData } from "@/components/dashboard/scan-terminal/scan-termi
import type { CityDetail, MarketScan } from "@/lib/dashboard-types";
import { normalizeCityKey } from "./decision-utils";
const CITY_MARKET_SCAN_CACHE_PREFIX = "polyWeather_cityMarketScan_v3";
const CITY_MARKET_SCAN_CACHE_PREFIX = "polyWeather_cityMarketScan_v4";
const CITY_MARKET_SCAN_CACHE_TTL_MS = 10 * 60 * 1000;
export type CityMarketScanStatus = "idle" | "loading" | "ready" | "failed";
export type CityMarketScanApiPayload =
| MarketScan
| {
fetched_at?: string | null;
market_scan?: MarketScan | null;
selected_date?: string | null;
};
export type CityMarketScanSnapshot =
| { action: "reset"; cacheKey?: string }
| { action: "success"; cacheKey: string; payload: MarketScan; shouldWriteCache?: boolean }
@@ -32,13 +40,30 @@ export function buildCityMarketScanCacheKey({
}
export function readCachedCityMarketScan(cacheKey: string) {
return readCachedPayload<MarketScan>(cacheKey, CITY_MARKET_SCAN_CACHE_TTL_MS);
return normalizeCityMarketScanPayload(
readCachedPayload<CityMarketScanApiPayload>(cacheKey, CITY_MARKET_SCAN_CACHE_TTL_MS),
);
}
export function writeCachedCityMarketScan(cacheKey: string, payload: MarketScan) {
writeCachedPayload(cacheKey, payload);
}
export function normalizeCityMarketScanPayload(
payload: CityMarketScanApiPayload | null | undefined,
): MarketScan | null {
if (!payload || typeof payload !== "object") return null;
if ("market_scan" in payload) {
const scan = payload.market_scan;
if (!scan || typeof scan !== "object") return null;
return {
...scan,
selected_date: scan.selected_date ?? payload.selected_date ?? null,
};
}
return payload as MarketScan;
}
export function resolveCityMarketScanSnapshot({
detail,
detailCityName,
@@ -1,6 +1,10 @@
"use client";
import { extractStreamingAirportRead } from "@/components/dashboard/scan-terminal/ai-city-stream";
import {
normalizeCityMarketScanPayload,
type CityMarketScanApiPayload,
} from "@/components/dashboard/scan-terminal/market-scan-state";
import type { AiCityForecastPayload } from "@/components/dashboard/scan-terminal/types";
import {
buildBrowserBackendHeaders,
@@ -292,7 +296,7 @@ async function getMarketScan(city: string, options: MarketScanQueryOptions = {})
if (options.marketSlug) params.set("market_slug", options.marketSlug);
if (options.lite != null) params.set("lite", String(options.lite));
const headers = await buildBrowserBackendHeaders({ Accept: "application/json" });
return readJsonOrThrow<MarketScan>(
const payload = await readJsonOrThrow<CityMarketScanApiPayload>(
`/api/city/${encodeURIComponent(city)}/market-scan?${params.toString()}`,
{
cache: "no-store",
@@ -300,6 +304,12 @@ async function getMarketScan(city: string, options: MarketScanQueryOptions = {})
signal: options.signal,
},
);
return (
normalizeCityMarketScanPayload(payload) ?? {
available: false,
reason: "No market scan payload returned.",
}
);
}
function runQueuedAiCityReadTask<T>(task: () => Promise<T>, onQueued?: () => void) {