| 73 | } |
| 74 | |
| 75 | async loadSpec(forceRefresh = false): Promise<boolean> { |
| 76 | this.error = null; |
| 77 | |
| 78 | if (this.specUrl) { |
| 79 | return this.loadCustomSpec(this.specUrl); |
| 80 | } |
| 81 | |
| 82 | // Try to read from cache |
| 83 | if (!forceRefresh) { |
| 84 | const cached = await this.readCache(this.cachePath); |
| 85 | if (cached && !this.isExpired(cached.fetchedAt)) { |
| 86 | output.debug('Using cached OpenAPI spec'); |
| 87 | this.spec = cached.spec; |
| 88 | return true; |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // Fetch fresh spec |
| 93 | try { |
| 94 | output.debug('Fetching OpenAPI spec from ' + OPENAPI_URL); |
| 95 | this.spec = await this.fetchSpec(OPENAPI_URL); |
| 96 | await this.saveCache(this.cachePath, this.spec); |
| 97 | return true; |
| 98 | } catch (err) { |
| 99 | output.debug(`Failed to fetch OpenAPI spec: ${err}`); |
| 100 | // If fetch fails, try to use stale cache |
| 101 | const stale = await this.readCache(this.cachePath); |
| 102 | if (stale) { |
| 103 | output.debug('Using stale cached OpenAPI spec'); |
| 104 | this.spec = stale.spec; |
| 105 | return true; |
| 106 | } |
| 107 | return false; |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | private async loadCustomSpec(specUrl: string): Promise<boolean> { |
| 112 | try { |