Skip to content

fix(ci): reserialize dynamic providers before refresh#86

Closed
dsp-ant wants to merge 1 commit intomainfrom
davidsp/fix-refresh-serialization
Closed

fix(ci): reserialize dynamic providers before refresh#86
dsp-ant wants to merge 1 commit intomainfrom
davidsp/fix-refresh-serialization

Conversation

@dsp-ant
Copy link
Member

@dsp-ant dsp-ant commented Mar 21, 2026

Summary

Deploy has been failing since #83 added --refresh. Root cause: Pulumi dynamic providers serialize their implementation into each resource's __provider state field at create/update time. During refresh, the serialized read() runs — not the current source. The state still held the pre-#84 discordFetch (no 429 retry), so ~52 of 68 parallel Discord member reads rate-limited and failed. Chicken-and-egg: refresh fails → no update → state keeps stale code → refresh fails again.

  • Makefile: Split make up into two phases. Phase 1 (pulumi up --yes) serializes current provider code into state for any changed resources. Phase 2 (pulumi up --refresh --yes) refreshes using the freshly serialized read().
  • src/discord.ts: Bump maxRetries 5 → 10 for headroom against Discord's rate limit during parallel refresh reads.

Test Plan

  • Local npm run check passes (23/23)
  • Makefile tab-indentation verified via cat -et
  • Verified against @pulumi/pulumi/cmd/dynamic-provider/index.js: update() at L269 uses getProvider(news) (new code), read() at L235 uses state's __provider — so phase 1 writes new code before phase 2 reads it
  • Actual deploy verification happens in CI (Pulumi can't run locally)

Split `make up` into two phases: a plain `pulumi up` first, then
`pulumi up --refresh`. Dynamic providers serialize their implementation
into state at create/update time. During refresh, the serialized `read()`
runs — so any provider-code change (like the Discord 429 retry logic)
doesn't take effect until a successful update writes the new `__provider`
to state. Running refresh first used the stale serialized code from the
last successful deploy, which had no rate-limit handling, failing on
parallel Discord member lookups.

Also bump discordFetch maxRetries from 5 to 10 for headroom against ~68
parallel refresh reads.
@dsp-ant dsp-ant requested a review from a team as a code owner March 21, 2026 20:42
@github-actions
Copy link

Pulumi Preview

Click to expand preview output
Previewing update (prod):
  pulumi:pulumi:Stack: (same)
    [urn=urn:pulumi:prod::mcp-access::pulumi:pulumi:Stack::mcp-access-prod]
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1461488567162503189]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-community-managers]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760656226680903]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-moderators]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760673498959945]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-administrators]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760682076307516]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-core-maintainers]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760679064535238]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-lead-maintainers]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760661985464506]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-reference-servers-maintainers]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760676367597740]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-inspector-maintainers]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760670395039755]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-maintainers]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760684643221556]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-use-mcp-maintainers]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760698316652557]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-kotlin-sdk]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760695821041767]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-java-sdk]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760769758101595]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-ruby-sdk]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760658848252036]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-csharp-sdk]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760804134752443]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-go-sdk]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         return response.json();
                }
          -     return response.json();
          +     throw (lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`));
            };
                }
            ...
                        };
                    }
          -         catch {
          -             throw new Error(`Failed to read role ${id}`);
          +         catch (error) {
          +             throw new Error(`Failed to read role ${id}: ${error}`);
                    }
                };
            ...
    ~ pulumi-nodejs:dynamic:Resource: (update)
        [id=1460760687444758623]
        [urn=urn:pulumi:prod::mcp-access::pulumi-nodejs:dynamic:Resource::discord-role-sdk-maintainers]
      ~ __provider: 
            exports.handler = __f0;
            var __provider = {create: __f1, read: __f2, update: __f3, delete: __f4};
          + function __sleep(__0) {
          +   return (function() {
          +     with({ sleep: __sleep, this: undefined, arguments: undefined }) {
          + return function /*sleep*/(ms) {
          +     return new Promise((resolve) => setTimeout(resolve, ms));
          + };
          +     }
          +   }).apply(undefined, undefined).apply(this, arguments);
          + }
            function __discordFetch(__0, __1) {
              return (function() {
          -     with({ DISCORD_API_BASE: "https://discord.com/api/v10", discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          +     with({ DISCORD_API_BASE: "https://discord.com/api/v10", sleep: __sleep, discordFetch: __discordFetch, this: undefined, arguments: undefined }) {
          - return async function /*discordFetch*/(token, endpoint, options = {}) {
          -     const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          -         ...options,
          -         headers: {
          -             Authorization: `Bot ${token}`,
          -             'Content-Type': 'application/json',
          -             ...options.headers,
          -         },
          -     });
          -     if (!response.ok) {
          -         const error = (await response.json());
          -         throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          -     }
          -     // Handle 204 No Content
          -     if (response.status === 204) {
          -         return undefined;
          + return async function /*discordFetch*/(token, endpoint, options = {}, maxRetries = 10) {
          +     let lastError;
          +     for (let attempt = 0; attempt <= maxRetries; attempt++) {
          +         const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
          +             ...options,
          +             headers: {
          +                 Authorization: `Bot ${token}`,
          +                 'Content-Type': 'application/json',
          +                 ...options.headers,
          +             },
          +         });
          +         if (response.status === 429) {
          +             const body = (await response.json());
          +             const retryAfterMs = Math.ceil(body.retry_after * 1000) + Math.random() * 250;
          +             lastError = new Error(`Discord API rate limited on ${endpoint} (retry_after=${body.retry_after}s, global=${body.global})`);
          +             if (attempt < maxRetries) {
          +                 await sleep(retryAfterMs);
          +                 continue;
          +             }
          +             throw lastError;
          +         }
          +         if (!response.ok) {
          +             const error = (await response.json());
          +             throw new Error(`Discord API error: ${error.message} (code: ${error.code})`);
          +         }
          +         // Handle 204 No Content
          +         if (response.status === 204) {
          +             return undefined;
          +         }
          +         retu

... (truncated)

@dsp-ant
Copy link
Member Author

dsp-ant commented Mar 21, 2026

Pushing directly to main instead.

@dsp-ant dsp-ant closed this Mar 21, 2026
@dsp-ant dsp-ant deleted the davidsp/fix-refresh-serialization branch March 21, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant