(netlifyApiToken, path, method = 'GET', payload = null, parseAs = 'json')
| 34 | const apiRoot = 'https://api.netlify.com/api/v1/'; |
| 35 | |
| 36 | async function fetchWithTimeout(netlifyApiToken, path, method = 'GET', payload = null, parseAs = 'json') { |
| 37 | const controller = new AbortController(); |
| 38 | const timeout = setTimeout(() => controller.abort(), 10000); // 10 second timeout |
| 39 | |
| 40 | try { |
| 41 | const options = { |
| 42 | signal: controller.signal, |
| 43 | method, |
| 44 | headers: { |
| 45 | 'Content-Type': 'application/json', |
| 46 | Authorization: `Bearer ${netlifyApiToken}`, |
| 47 | }, |
| 48 | }; |
| 49 | |
| 50 | if (payload) { |
| 51 | options.body = JSON.stringify(payload); |
| 52 | } |
| 53 | |
| 54 | // Handle both full URLs and API paths |
| 55 | const url = path.startsWith('http://') || path.startsWith('https://') ? path : `${apiRoot}${path}`; |
| 56 | const response = await fetch(url, options); |
| 57 | clearTimeout(timeout); |
| 58 | |
| 59 | return parseAs === 'json' ? response.json() : response.text(); |
| 60 | } catch (error) { |
| 61 | clearTimeout(timeout); |
| 62 | if (error.name === 'AbortError') { |
| 63 | console.error(`Netlify API ${method} timeout after 10s: ${path}`); |
| 64 | throw new Error(`Netlify API ${method} request timeout: ${path}`); |
| 65 | } |
| 66 | throw error; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | async function waitForDeploys(netlifyApiToken, siteId) { |
| 71 | const maxRetries = 5; |
no outgoing calls
no test coverage detected