Unified · Split
| @@ -29,6 +29,33 @@ const OPENAPI_SPEC_CACHE_TTL_MS = 5 * 60 * 60_000; · 28 unmodified lines | ||
| 29 | 29 | /** Cache version - bump when tool snapshot/registry/type-hint semantics change. */ |
| 30 | 30 | const TOOL_SOURCE_CACHE_VERSION = "v25"; |
| 31 | 31 | |
| 32 | +function toPreparedOpenApiSpec(value: unknown): PreparedOpenApiSpec | null { | |
| 33 | + const record = asPayload(value); | |
| 34 | + if (!Array.isArray(record.servers)) { | |
| 35 | + return null; | |
| 36 | + } | |
| 37 | + if (!record.paths || typeof record.paths !== "object" || Array.isArray(record.paths)) { | |
| 38 | + return null; | |
| 39 | + } | |
| 40 | + | |
| 41 | + const servers = record.servers.filter((entry): entry is string => typeof entry === "string"); | |
| 42 | + const warnings = Array.isArray(record.warnings) | |
| 43 | + ? record.warnings.filter((entry): entry is string => typeof entry === "string") | |
| 44 | + : []; | |
| 45 | + const dtsStatus = | |
| 46 | + record.dtsStatus === "ready" || record.dtsStatus === "failed" || record.dtsStatus === "skipped" | |
| 47 | + ? record.dtsStatus | |
| 48 | + : undefined; | |
| 49 | + | |
| 50 | + return { | |
| 51 | + servers, | |
| 52 | + paths: asPayload(record.paths), | |
| 53 | + warnings, | |
| 54 | + dts: typeof record.dts === "string" ? record.dts : undefined, | |
| 55 | + dtsStatus, | |
| 56 | + }; | |
| 57 | +} | |
| 58 | + | |
| 32 | 59 | export function sourceSignature(workspaceId: string, sources: Array<{ id: string; updatedAt: number; enabled: boolean }>): string { |
| 33 | 60 | const parts = sources |
| 34 | 61 | .map((source) => `${source.id}:${source.updatedAt}:${source.enabled ? 1 : 0}`) |
| @@ -235,9 +262,12 @@ async function loadCachedOpenApiSpec( · 200 unmodified lines | ||
| 235 | 262 | const blob = await ctx.storage.get(entry.storageId); |
| 236 | 263 | if (blob) { |
| 237 | 264 | const json = await blob.text(); |
| 238 | − const prepared = JSON.parse(json) as PreparedOpenApiSpec; | |
| 239 | − if (!includeDts || getDtsStatus(prepared) !== "skipped") { | |
| 240 | − return prepared; | |
| 265 | + const parsedResult = Result.try(() => JSON.parse(json)); | |
| 266 | + if (parsedResult.isOk()) { | |
| 267 | + const prepared = toPreparedOpenApiSpec(parsedResult.value); | |
| 268 | + if (prepared && (!includeDts || getDtsStatus(prepared) !== "skipped")) { | |
| 269 | + return prepared; | |
| 270 | + } | |
| 241 | 271 | } |
| 242 | 272 | } |
| 243 | 273 | } |