<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Serhii Zhabskyi</title>
    <description>The latest articles on DEV Community by Serhii Zhabskyi (@samplex_283d61d7a).</description>
    <link>https://dev.to/samplex_283d61d7a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3203307%2Faf128417-8852-45f9-802d-482f17ef1c00.jpeg</url>
      <title>DEV Community: Serhii Zhabskyi</title>
      <link>https://dev.to/samplex_283d61d7a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samplex_283d61d7a"/>
    <language>en</language>
    <item>
      <title>I Tried to Keep My AI Coding Assistants in Sync. It Turned Into a Configuration Problem.</title>
      <dc:creator>Serhii Zhabskyi</dc:creator>
      <pubDate>Tue, 12 May 2026 08:45:52 +0000</pubDate>
      <link>https://dev.to/samplex_283d61d7a/i-tried-to-keep-my-ai-coding-assistants-in-sync-it-turned-into-a-configuration-problem-1j48</link>
      <guid>https://dev.to/samplex_283d61d7a/i-tried-to-keep-my-ai-coding-assistants-in-sync-it-turned-into-a-configuration-problem-1j48</guid>
      <description>&lt;p&gt;Most discussions around AI coding assistants focus on models, prompts, benchmarks, or editor UX.&lt;/p&gt;

&lt;p&gt;My problem was much more boring: files.&lt;/p&gt;

&lt;p&gt;At some point I had several AI coding assistants in the same development workflow. Not because I wanted to collect tools, but because each one was useful in a slightly different context. One was better inside the IDE. Another was useful from the terminal. Another worked better for larger refactors. Another was convenient for quick repository-level questions.&lt;/p&gt;

&lt;p&gt;That part was fine.&lt;/p&gt;

&lt;p&gt;The painful part was that every assistant wanted its own configuration.&lt;/p&gt;

&lt;p&gt;One tool wanted a root instruction file. Another wanted rules in a dedicated directory. Another had its own format for MCP servers. Another supported commands. Another supported agents. Some tools had ignore files. Some had hooks. Some had permissions. Some had overlapping concepts, but not exactly the same concepts.&lt;/p&gt;

&lt;p&gt;So the same project slowly started to contain copies of the same intent in different places.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLAUDE.md
AGENTS.md
.cursor/rules/*.mdc
.github/copilot-instructions.md
.gemini/settings.json
.codex/config.toml
.windsurf/rules/*.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first this looked manageable. It was just configuration. A few markdown files. A few JSON or TOML files.&lt;/p&gt;

&lt;p&gt;Then it became a real source of drift.&lt;/p&gt;

&lt;p&gt;A TypeScript rule changed in one assistant but not in another. A command was updated in one place but the old version stayed somewhere else. An MCP server definition had slightly different names depending on the target. One assistant had a more recent description of the project architecture than the others.&lt;/p&gt;

&lt;p&gt;The result was strange: I was asking different AI assistants to work on the same codebase, but they were not really working with the same understanding of the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The issue is not “which AI assistant is best”
&lt;/h2&gt;

&lt;p&gt;I do not think this problem should be framed as Claude vs Cursor vs Copilot vs Codex vs Gemini vs anything else.&lt;/p&gt;

&lt;p&gt;In practice, developers increasingly use more than one AI tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one inside the IDE;&lt;/li&gt;
&lt;li&gt;one in the terminal;&lt;/li&gt;
&lt;li&gt;one for code review;&lt;/li&gt;
&lt;li&gt;one for large refactors;&lt;/li&gt;
&lt;li&gt;one for documentation or migration work;&lt;/li&gt;
&lt;li&gt;one used personally, another standardized by the team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not unusual anymore.&lt;/p&gt;

&lt;p&gt;The real problem is that every tool has its own configuration surface.&lt;/p&gt;

&lt;p&gt;And these surfaces are not just “prompt files”. They can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project rules;&lt;/li&gt;
&lt;li&gt;scoped rules;&lt;/li&gt;
&lt;li&gt;agent definitions;&lt;/li&gt;
&lt;li&gt;reusable commands;&lt;/li&gt;
&lt;li&gt;skills or playbooks;&lt;/li&gt;
&lt;li&gt;MCP servers;&lt;/li&gt;
&lt;li&gt;hooks;&lt;/li&gt;
&lt;li&gt;permissions;&lt;/li&gt;
&lt;li&gt;ignore files;&lt;/li&gt;
&lt;li&gt;global user-level configuration;&lt;/li&gt;
&lt;li&gt;project-level team configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single shared markdown file can help, but it does not cover the whole surface.&lt;/p&gt;

&lt;p&gt;For small projects, duplicating a few instructions manually is probably fine. For a serious project, a monorepo, or a team setup, it becomes the same class of problem we already solved many times in software engineering: one source of truth, many generated outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  I looked for an existing solution first
&lt;/h2&gt;

&lt;p&gt;Before building anything, I tried the obvious path: use an existing sync/generation tool.&lt;/p&gt;

&lt;p&gt;The idea was correct: keep a canonical configuration and generate assistant-specific files from it.&lt;/p&gt;

&lt;p&gt;That worked for simple rules.&lt;/p&gt;

&lt;p&gt;But once I tried to model the actual configuration I used every day, I kept hitting edge cases.&lt;/p&gt;

&lt;p&gt;The first issue was cross-references.&lt;/p&gt;

&lt;p&gt;If an agent references a skill, or a rule references a command, the relative path is different in every generated target. A link that works from &lt;code&gt;.agentsmesh/skills/refactor/SKILL.md&lt;/code&gt; will not necessarily work from &lt;code&gt;.claude/agents/code-reviewer.md&lt;/code&gt; or &lt;code&gt;.cursor/rules/typescript.mdc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So generation cannot be only “copy this file there”. It needs to understand references and rebase links per target.&lt;/p&gt;

&lt;p&gt;The second issue was unsupported features.&lt;/p&gt;

&lt;p&gt;Some tools have native agents. Some do not. Some have commands. Some do not. Some have hooks. Some have permissions. Some only have a general instruction file.&lt;/p&gt;

&lt;p&gt;If a target does not support a feature natively, there are a few possible choices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;drop the feature;&lt;/li&gt;
&lt;li&gt;flatten everything into a generic prompt;&lt;/li&gt;
&lt;li&gt;embed the feature with metadata so it can be reconstructed later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dropping data was not acceptable. Flattening everything made import/generate cycles lossy. I wanted round-trip behavior: import existing configs, normalize them, generate them again, and not silently lose structure.&lt;/p&gt;

&lt;p&gt;The third issue was tool velocity.&lt;/p&gt;

&lt;p&gt;New AI coding tools appear constantly. Existing ones change their config formats. Waiting for a central maintainer to add support for every new assistant is not a great model if the ecosystem keeps moving this fast.&lt;/p&gt;

&lt;p&gt;That is where I decided to build my own solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model I wanted
&lt;/h2&gt;

&lt;p&gt;The model I wanted was not unusual.&lt;/p&gt;

&lt;p&gt;We already use it everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeScript source  -&amp;gt; JavaScript output
.proto files       -&amp;gt; generated SDKs
OpenAPI schema     -&amp;gt; generated clients
Dockerfile         -&amp;gt; image
source config      -&amp;gt; target artifacts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wanted the same pattern for AI assistant configuration.&lt;/p&gt;

&lt;p&gt;There should be one canonical directory that describes the intent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.agentsmesh/
  rules/
  commands/
  agents/
  skills/
  mcp.json
  hooks.yaml
  permissions.yaml
  ignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then a generator should project that intent into the native layout of each assistant.&lt;/p&gt;

&lt;p&gt;Generated files should be treated as artifacts. You can inspect them, commit them if needed, and let tools consume them in their native format. But humans should primarily edit the canonical source.&lt;/p&gt;

&lt;p&gt;That is the important distinction.&lt;/p&gt;

&lt;p&gt;I did not want to force every tool into one lowest-common-denominator format. I wanted to preserve native output where possible, while keeping a canonical source that is easier to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is harder than it looks
&lt;/h2&gt;

&lt;p&gt;At first this sounds like a file converter.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;

&lt;p&gt;The hard parts are mostly about preserving semantics.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Native vs embedded capabilities
&lt;/h3&gt;

&lt;p&gt;A target may support a feature natively, partially, or not at all.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one assistant may have a native commands directory;&lt;/li&gt;
&lt;li&gt;another may only support commands as embedded sections in a root instruction file;&lt;/li&gt;
&lt;li&gt;another may not have a useful equivalent at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generator needs to know that difference.&lt;/p&gt;

&lt;p&gt;More importantly, the importer also needs to know that difference. Otherwise you can generate an embedded command, import it again, and lose the original command boundary.&lt;/p&gt;

&lt;p&gt;That is why metadata matters. Not because metadata is elegant, but because lossless round trips are impossible without some way to preserve structure where the target format does not have a native slot.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Link rebasing
&lt;/h3&gt;

&lt;p&gt;This was one of the first problems that made the project feel necessary.&lt;/p&gt;

&lt;p&gt;Developers naturally split configuration into multiple files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;See ../skills/refactor/SKILL.md before changing this module.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But after generation, that file may live somewhere completely different.&lt;/p&gt;

&lt;p&gt;So links must be rewritten depending on the target layout.&lt;/p&gt;

&lt;p&gt;This sounds small until you realize that agents can reference skills, skills can reference supporting files, commands can reference rules, and project/global modes have different path assumptions.&lt;/p&gt;

&lt;p&gt;If this is not handled, the generated configuration looks correct but slowly rots because internal links stop working.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Drift detection
&lt;/h3&gt;

&lt;p&gt;If generated files are committed, somebody will eventually edit them directly.&lt;/p&gt;

&lt;p&gt;That is not a moral failure. It is normal developer behavior.&lt;/p&gt;

&lt;p&gt;But then the repository needs a way to detect whether the generated files still match the canonical source.&lt;/p&gt;

&lt;p&gt;So the workflow needs a check step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agentsmesh check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The point is not to be strict for the sake of being strict. The point is to make drift visible before different assistants start reading different versions of the project rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Import matters as much as generate
&lt;/h3&gt;

&lt;p&gt;A tool like this is not useful if adoption requires a clean rewrite.&lt;/p&gt;

&lt;p&gt;Most real projects already have some assistant configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.cursor/rules/
CLAUDE.md
.github/copilot-instructions.md
AGENTS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So import needs to exist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agentsmesh import &lt;span class="nt"&gt;--from&lt;/span&gt; cursor
agentsmesh generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives a realistic migration path: start from what already exists, normalize it, then generate from the canonical structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Plugins are necessary
&lt;/h3&gt;

&lt;p&gt;The AI tooling ecosystem changes too quickly for every target to be hardcoded forever.&lt;/p&gt;

&lt;p&gt;So target support has to be data-driven and extensible.&lt;/p&gt;

&lt;p&gt;A target should describe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where its files live;&lt;/li&gt;
&lt;li&gt;which features it supports;&lt;/li&gt;
&lt;li&gt;whether each feature is native, embedded, partial, or unsupported;&lt;/li&gt;
&lt;li&gt;how to generate its output;&lt;/li&gt;
&lt;li&gt;how to import existing files back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes it possible to ship new target support as a plugin instead of changing core every time a new assistant appears.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I ended up building
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;AgentsMesh&lt;/strong&gt; around that model.&lt;/p&gt;

&lt;p&gt;The basic workflow is intentionally boring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh init
npx agentsmesh generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an existing project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh import &lt;span class="nt"&gt;--from&lt;/span&gt; cursor
npx agentsmesh generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For reviewing output before writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For personal global config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh init &lt;span class="nt"&gt;--global&lt;/span&gt;
npx agentsmesh generate &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not to replace any assistant.&lt;/p&gt;

&lt;p&gt;The goal is to stop treating assistant configuration as scattered hand-written state.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is useful outside Node.js projects
&lt;/h2&gt;

&lt;p&gt;The CLI is distributed through npm, but the problem is not Node-specific.&lt;/p&gt;

&lt;p&gt;A Rust team can have the same issue. A Python backend can have the same issue. A Java monolith can have the same issue. A Go service, Unity project, mobile app, infrastructure repo, or documentation-heavy project can all hit the same problem once several AI tools are involved.&lt;/p&gt;

&lt;p&gt;The configuration being synchronized is not about Node.js. It is about how AI assistants understand a repository.&lt;/p&gt;

&lt;p&gt;That includes things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;coding conventions;&lt;/li&gt;
&lt;li&gt;architecture rules;&lt;/li&gt;
&lt;li&gt;domain vocabulary;&lt;/li&gt;
&lt;li&gt;testing strategy;&lt;/li&gt;
&lt;li&gt;forbidden files or directories;&lt;/li&gt;
&lt;li&gt;review checklists;&lt;/li&gt;
&lt;li&gt;migration playbooks;&lt;/li&gt;
&lt;li&gt;commands for repetitive workflows;&lt;/li&gt;
&lt;li&gt;MCP server definitions;&lt;/li&gt;
&lt;li&gt;permissions and safety boundaries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every codebase has some version of this knowledge.&lt;/p&gt;

&lt;p&gt;The question is whether it lives in one place or slowly diverges across tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I think this category is going
&lt;/h2&gt;

&lt;p&gt;I do not think AI coding configuration will become simpler.&lt;/p&gt;

&lt;p&gt;I expect the opposite.&lt;/p&gt;

&lt;p&gt;Assistants will get more capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deeper repo indexing;&lt;/li&gt;
&lt;li&gt;more tool execution;&lt;/li&gt;
&lt;li&gt;more agent-like workflows;&lt;/li&gt;
&lt;li&gt;more project memory;&lt;/li&gt;
&lt;li&gt;more MCP usage;&lt;/li&gt;
&lt;li&gt;more fine-grained permissions;&lt;/li&gt;
&lt;li&gt;more team-level policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means configuration will matter more, not less.&lt;/p&gt;

&lt;p&gt;A single prompt file may be enough for now in many projects. But as soon as teams start using several assistants with different capabilities, the config layer becomes infrastructure.&lt;/p&gt;

&lt;p&gt;And infrastructure usually needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a source of truth;&lt;/li&gt;
&lt;li&gt;reproducible generation;&lt;/li&gt;
&lt;li&gt;validation;&lt;/li&gt;
&lt;li&gt;drift detection;&lt;/li&gt;
&lt;li&gt;reviewable diffs;&lt;/li&gt;
&lt;li&gt;import/export paths;&lt;/li&gt;
&lt;li&gt;extension points.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the direction I wanted AgentsMesh to take.&lt;/p&gt;

&lt;h2&gt;
  
  
  When I would not use it
&lt;/h2&gt;

&lt;p&gt;There are cases where this is overkill.&lt;/p&gt;

&lt;p&gt;If you use one assistant, one project, and one instruction file, you probably do not need a canonical sync layer.&lt;/p&gt;

&lt;p&gt;If your rules are tiny and rarely change, manual duplication might be cheaper than introducing tooling.&lt;/p&gt;

&lt;p&gt;If your team does not commit assistant config at all, the value is lower.&lt;/p&gt;

&lt;p&gt;But if you maintain several assistants, or you care that every assistant reads the same project rules, then the problem becomes real very quickly.&lt;/p&gt;

&lt;p&gt;For me, the breaking point was realizing that my AI tools were not disagreeing because the models were different.&lt;/p&gt;

&lt;p&gt;They were disagreeing because I had taught them different versions of the same project.&lt;/p&gt;

&lt;p&gt;That is the bug I wanted to remove.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;AgentsMesh repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/sampleXbro/agentsmesh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://samplexbro.github.io/agentsmesh/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>claude</category>
    </item>
    <item>
      <title>I had four AI coding assistants and the same config in five places. Here's what I built.</title>
      <dc:creator>Serhii Zhabskyi</dc:creator>
      <pubDate>Tue, 28 Apr 2026 08:31:01 +0000</pubDate>
      <link>https://dev.to/samplex_283d61d7a/i-had-four-ai-coding-assistants-and-the-same-config-in-five-places-heres-what-i-built-2ncd</link>
      <guid>https://dev.to/samplex_283d61d7a/i-had-four-ai-coding-assistants-and-the-same-config-in-five-places-heres-what-i-built-2ncd</guid>
      <description>&lt;p&gt;A while back my repo looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLAUDE.md                                        # rules for Claude Code
.claude/agents/code-reviewer.md                  # agent definitions
.claude/skills/refactor/SKILL.md                 # skill packs
.claude/commands/deploy.md                       # slash commands
.claude.json                                     # MCP servers
.cursor/rules/typescript.mdc                     # rules for Cursor
.cursor/mcp.json                                 # MCP servers (different schema)
.github/copilot-instructions.md                  # rules for Copilot
.github/agents/code-reviewer.md                  # agents (different format)
.continue/rules/typescript.md                    # rules for Continue
.continue/mcpServers/                            # MCP servers (yet another schema)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same rule - &lt;em&gt;"no &lt;code&gt;any&lt;/code&gt;, prefer &lt;code&gt;unknown&lt;/code&gt; with narrowing"&lt;/em&gt; - in four places. Same MCP server configured three times in three JSON schemas. Same code-reviewer agent described twice with different frontmatter. Same deployment command in two directories.&lt;/p&gt;

&lt;p&gt;Then someone updated &lt;code&gt;unknown&lt;/code&gt; to &lt;code&gt;never&lt;/code&gt; for a specific case in &lt;code&gt;CLAUDE.md&lt;/code&gt; only. Cursor still suggested &lt;code&gt;unknown&lt;/code&gt;. Copilot agreed with neither. We spent a standup figuring out which AI was "right."&lt;/p&gt;

&lt;p&gt;The problem wasn't rules alone. It was the entire config surface: rules, agents, skills, commands, MCP servers, hooks, permissions, and ignore files - all duplicated per tool, all drifting independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tried first
&lt;/h2&gt;

&lt;p&gt;I looked for existing tools that solve this. The most popular one in this space has the right model: one canonical source, generate per-tool configs. I used it for a few months.&lt;/p&gt;

&lt;p&gt;But I kept hitting gaps. Cross-references between files didn't get rewritten on generate, so an agent linking to a skill produced broken paths in every target. Activation semantics got inverted across tool dialects - a manual-only rule became always-on after translation. Hook configs got generated but the scripts they referenced didn't follow. Permissions weren't modeled as a feature at all. And every new AI coding tool that shipped needed a PR to the maintainer's repo — some requests sat open for over a year.&lt;/p&gt;

&lt;p&gt;These aren't bugs. They're architectural limits that compound once you grow past flat rule syncing into the full config surface: agents, skills with supporting files, hooks with scripts, permissions, MCP servers with tool-specific schemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern
&lt;/h2&gt;

&lt;p&gt;You already use this pattern elsewhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;package.json&lt;/code&gt; → &lt;code&gt;package-lock.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Dockerfile&lt;/code&gt; → image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*.proto&lt;/code&gt; → client SDKs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apply it to AI configs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One &lt;strong&gt;canonical&lt;/strong&gt; directory describes rules, commands, agents, skills, MCP, hooks, ignore, and permissions in a tool-agnostic way.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;generator&lt;/strong&gt; projects them into each tool's native format.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;importer&lt;/strong&gt; does the reverse, so you can adopt without rewriting existing configs.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;lock file&lt;/strong&gt; detects drift in CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting work is in the link rewriting, the round-trip story, and getting the full feature surface (not just rules) to project correctly across 12 tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/sampleXbro/agentsmesh" rel="noopener noreferrer"&gt;agentsmesh&lt;/a&gt; implements this pattern. Here's the canonical directory and what it generates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.agentsmesh/                           Generated output (Claude Code):
├── rules/                             ├── CLAUDE.md
│   ├── _root.md                       ├── .claude/
│   └── typescript.md                  │   ├── rules/typescript.md
├── agents/                            │   ├── agents/code-reviewer.md
│   └── code-reviewer.md              │   ├── skills/refactor/
├── skills/                            │   │   ├── SKILL.md
│   └── refactor/                      │   │   └── references/patterns.md
│       ├── SKILL.md                   │   ├── commands/deploy.md
│       └── references/                │   └── settings.json  (hooks, perms)
│           └── patterns.md            ├── .claude.json        (MCP)
├── commands/                          
│   └── deploy.md                      Generated output (Cursor):
├── mcp.json                           ├── .cursor/
├── hooks.yaml                         │   ├── rules/
├── permissions.yaml                   │   │   ├── _root.mdc
└── ignore                             │   │   └── typescript.mdc
                                       │   ├── skills/refactor/
                                       │   │   ├── SKILL.md
                                       │   │   └── references/patterns.md
                                       │   └── mcp.json
                                       ├── AGENTS.md (agents + commands embedded)
                                       └── .cursorignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One canonical source. Two different generated trees with different directory layouts, different file formats, different frontmatter conventions — all from the same &lt;code&gt;.agentsmesh/&lt;/code&gt; input.&lt;/p&gt;

&lt;p&gt;Adopt in an existing project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh import &lt;span class="nt"&gt;--from&lt;/span&gt; cursor   &lt;span class="c"&gt;# or claude-code, copilot, codex-cli, ...&lt;/span&gt;
npx agentsmesh generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;import&lt;/code&gt; walks your existing tool config, normalizes it into the canonical shape. &lt;code&gt;generate&lt;/code&gt; projects it back out to every enabled tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross-references get rewritten per-target
&lt;/h3&gt;

&lt;p&gt;This is the part I underestimated.&lt;/p&gt;

&lt;p&gt;When the code-reviewer agent file says &lt;em&gt;"see &lt;a href="//./skills/refactor/SKILL.md"&gt;the refactor skill&lt;/a&gt; for the full playbook"&lt;/em&gt;, that link has to resolve differently in every generated output:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;The agent's skill link resolves to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.claude/skills/refactor/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.cursor/skills/refactor/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex CLI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.codex/skills/refactor/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code (global)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.claude/skills/refactor/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rebaser at &lt;code&gt;src/core/reference/link-rebaser.ts&lt;/code&gt; rewrites every link per target. The rules are explicit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inside &lt;code&gt;.agentsmesh/&lt;/code&gt; → relative paths.&lt;/li&gt;
&lt;li&gt;Outside &lt;code&gt;.agentsmesh/&lt;/code&gt; in project mode → repo-root absolute paths.&lt;/li&gt;
&lt;li&gt;Outside &lt;code&gt;.agentsmesh/&lt;/code&gt; in global mode → no rewrite. Your home directory isn't mine to touch.&lt;/li&gt;
&lt;li&gt;Markdown link URLs stay relative for portability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this you can't have agents referencing skills, skills referencing other skills, rules pointing at commands. You're forced to keep everything in one flat file with no cross-references.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lossless round-trip across the full feature surface
&lt;/h3&gt;

&lt;p&gt;When a target doesn't natively support a feature (Cursor has no native skills directory, Copilot has no native hooks), the generator embeds them with metadata so re-importing reconstructs the original shape.&lt;/p&gt;

&lt;p&gt;This matters for more than just rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; with supporting files (references, templates, scripts) survive projection to tools that don't have a skills directory — they get embedded in the root instructions with metadata markers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents&lt;/strong&gt; defined in &lt;code&gt;.agentsmesh/agents/code-reviewer.md&lt;/code&gt; become &lt;code&gt;.claude/agents/code-reviewer.md&lt;/code&gt; for Claude (native), or get embedded in &lt;code&gt;AGENTS.md&lt;/code&gt; for Cursor and Codex (which read that file).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commands&lt;/strong&gt; become &lt;code&gt;.claude/commands/deploy.md&lt;/code&gt; for Claude, &lt;code&gt;.gemini/commands/deploy.toml&lt;/code&gt; for Gemini (different format entirely), or get embedded in the root instructions for tools that don't have a commands directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activation semantics&lt;/strong&gt; survive too — Cursor's &lt;code&gt;alwaysApply: false&lt;/code&gt; round-trips through Claude generation and back into canonical form without getting inverted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hooks and permissions are first-class
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;hooks.yaml&lt;/code&gt; and &lt;code&gt;permissions.yaml&lt;/code&gt; are canonical types alongside rules and skills. Hooks generate in each target's native format — JSON config in settings for Claude, wrapper scripts for Copilot, per-file &lt;code&gt;.kiro.hook&lt;/code&gt; for Kiro. Permissions project to native settings where the target supports it (currently Claude Code has full native support; others embed or partially support).&lt;/p&gt;

&lt;h3&gt;
  
  
  Targets are data, not classes
&lt;/h3&gt;

&lt;p&gt;A target is a &lt;code&gt;TargetDescriptor&lt;/code&gt; value declared in &lt;code&gt;src/targets/&amp;lt;id&amp;gt;/index.ts&lt;/code&gt;. The engine reads the descriptor and dispatches generically — it never branches on target name. Capability levels (&lt;code&gt;native | embedded | partial | none&lt;/code&gt;) are declared per feature in the descriptor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;embedded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// no native agent dir → embed in root instructions&lt;/span&gt;
  &lt;span class="nx"&gt;skills&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;partial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// limited event support&lt;/span&gt;
  &lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The builtin catalog is auto-discovered at build time by scanning &lt;code&gt;src/targets/*/index.ts&lt;/code&gt;. &lt;code&gt;agentsmesh target scaffold foo-ide&lt;/code&gt; generates the full structure — descriptor, generators, importer, linter, constants, tests — so you start from a working base. No enum to update, no shared code to edit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plugins ship as standalone npm packages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh plugin add agentsmesh-target-foo-ide
npx agentsmesh generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plugins get full built-in parity — same descriptor schema, same capability levels, same lint hooks and global-mode support as built-ins. New tool support doesn't wait for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI/dev workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx agentsmesh check&lt;/span&gt;    &lt;span class="c1"&gt;# exits 1 on drift&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest of the surface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;agentsmesh diff&lt;/code&gt; — preview what &lt;code&gt;generate&lt;/code&gt; would change, without writing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agentsmesh lint&lt;/code&gt; — validate canonical config against per-target constraints.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agentsmesh watch&lt;/code&gt; — regenerate target files on save during local editing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agentsmesh merge&lt;/code&gt; — resolve three-way &lt;code&gt;.lock&lt;/code&gt; conflicts after &lt;code&gt;git merge&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agentsmesh matrix&lt;/code&gt; — print the full support matrix for all targets and features.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Global mode for personal config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh init &lt;span class="nt"&gt;--global&lt;/span&gt;
npx agentsmesh import &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="nt"&gt;--from&lt;/span&gt; claude-code
npx agentsmesh generate &lt;span class="nt"&gt;--global&lt;/span&gt;   &lt;span class="c"&gt;# writes ~/.claude/, ~/.cursor/, ~/.codex/, ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;~/.agentsmesh/&lt;/code&gt; is for personal setup across every repo you touch. Every CLI command accepts &lt;code&gt;--global&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Native Windows
&lt;/h3&gt;

&lt;p&gt;Path-format detection (&lt;code&gt;/proj&lt;/code&gt; vs &lt;code&gt;C:\proj&lt;/code&gt;) decoupled from host platform. chokidar polling on Windows for ReadDirectoryChangesW edge cases. &lt;code&gt;basename()&lt;/code&gt; everywhere instead of &lt;code&gt;split('/')&lt;/code&gt;. CI matrix runs Linux + macOS + Windows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typed programmatic API
&lt;/h3&gt;

&lt;p&gt;Same surface as the CLI, exported with full &lt;code&gt;.d.ts&lt;/code&gt; under strict TS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadProjectContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agentsmesh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadProjectContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;drift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subpath imports for narrower bundles: &lt;code&gt;agentsmesh/engine&lt;/code&gt;, &lt;code&gt;agentsmesh/canonical&lt;/code&gt;, &lt;code&gt;agentsmesh/targets&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON Schema for every config
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;agentsmesh.yaml&lt;/code&gt;, &lt;code&gt;hooks.yaml&lt;/code&gt;, &lt;code&gt;permissions.yaml&lt;/code&gt;, &lt;code&gt;mcp.json&lt;/code&gt;, &lt;code&gt;pack.json&lt;/code&gt; — all ship with generated &lt;code&gt;$schema&lt;/code&gt; references. VS Code and JetBrains autocomplete + validation work out of the box.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community packs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agentsmesh &lt;span class="nb"&gt;install &lt;/span&gt;github:org/shared-config@v1.0.0
npx agentsmesh &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--sync&lt;/span&gt;    &lt;span class="c"&gt;# restore all packs after clone&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Packs live in &lt;code&gt;.agentsmesh/packs/&lt;/code&gt;, track in &lt;code&gt;installs.yaml&lt;/code&gt;, and merge into canonical config on every &lt;code&gt;generate&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it doesn't do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No GUI.&lt;/strong&gt; It's a CLI and a library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doesn't manage secrets.&lt;/strong&gt; MCP server tokens stay in your existing secret store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Won't help if you only use one tool.&lt;/strong&gt; The canonical layer is overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smaller ecosystem.&lt;/strong&gt; Fewer community packs and fewer eyes on it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; agentsmesh
npx agentsmesh init
&lt;span class="c"&gt;# or, in an existing project:&lt;/span&gt;
npx agentsmesh import &lt;span class="nt"&gt;--from&lt;/span&gt; cursor
npx agentsmesh generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Linux, macOS, Windows (native, not WSL). MIT. Node 20+. ESM-only. Strict TypeScript.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/sampleXbro/agentsmesh" rel="noopener noreferrer"&gt;github.com/sampleXbro/agentsmesh&lt;/a&gt; · Docs: &lt;a href="https://samplexbro.github.io/agentsmesh" rel="noopener noreferrer"&gt;samplexbro.github.io/agentsmesh&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tooling</category>
      <category>typescript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Supercharge Your Axios Requests: axios-retryer for Robust API Communication</title>
      <dc:creator>Serhii Zhabskyi</dc:creator>
      <pubDate>Sat, 24 May 2025 15:52:24 +0000</pubDate>
      <link>https://dev.to/samplex_283d61d7a/supercharge-your-axios-requests-axios-retryer-for-robust-api-communication-3fdn</link>
      <guid>https://dev.to/samplex_283d61d7a/supercharge-your-axios-requests-axios-retryer-for-robust-api-communication-3fdn</guid>
      <description>&lt;p&gt;I’ve been working on a React application that needed a robust solution for handling concurrent requests, custom retry logic, and token refresh—without shuffling together multiple scattered packages. I couldn’t find an all-in-one library that combined concurrency management, priorities, token refresh, caching, and circuit breaking in a straightforward API, so I built &lt;code&gt;axios-retryer&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  📝 Why I Wrote It
&lt;/h2&gt;

&lt;p&gt;In this TV-based frontend project some data requests were absolutely critical (e.g., user authentication or top-level layout info) and needed to complete before all the nice-to-have background calls. Sure, I could let Axios blasts run wild, but that risked important calls getting stuck behind less urgent tasks. I also hated duplicating retry logic across different request modules. So, I decided to create a single “retryer” layer for concurrency, priority handling, advanced retry strategies, token refreshing, circuit-breaking, caching, and analytics events. Doing so helped me replace multiple incomplete solutions with a single, consistent approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Key Features at a Glance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Priority &amp;amp; Concurrency&lt;/strong&gt;: Queue requests so critical calls finish before everything else, with fine-grained control over simultaneous requests.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Customizable Retry Strategies&lt;/strong&gt;: Built-in linear, exponential backoff, static, or provide your own custom retry logic function.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TokenRefreshPlugin&lt;/strong&gt;: Automatically refresh access tokens upon expiry and seamlessly replay pending requests.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;CircuitBreakerPlugin&lt;/strong&gt;: Intelligently detect repeated errors from an endpoint and temporarily halt requests to avoid further failures, then gracefully recover.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;CachingPlugin&lt;/strong&gt;: Cache responses for common requests to reduce load times and bandwidth usage.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Metrics &amp;amp; Events&lt;/strong&gt;: Observe request outcomes, success/failure rates, circuit states, and other vital statistics through a rich event system.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Minimal Overhead&lt;/strong&gt;: Approximately 6.4 kB minified + gzipped (core library with all plugins) means it won’t bloat your bundle.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⚙️ Quick Install &amp;amp; Hello World
&lt;/h2&gt;

&lt;p&gt;Installation is straightforward using npm, yarn, or pnpm. Here’s the minimal setup to get you started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Using npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;axios-retryer

&lt;span class="c"&gt;# Using yarn&lt;/span&gt;
yarn add axios-retryer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import the library&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRetryer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create a retryer instance with sensible defaults&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Attempt requests up to 3 times on failure&lt;/span&gt;
    &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// Set to true for development logging&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Use the axiosInstance provided by the retryer&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All retries failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s the essence: &lt;code&gt;createRetryer()&lt;/code&gt; returns a manager object, and you use its &lt;code&gt;axiosInstance&lt;/code&gt; property, which is a specially configured Axios instance with concurrency, retry logic, and plugin support baked in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Priority &amp;amp; Concurrency
&lt;/h2&gt;

&lt;p&gt;Priority and concurrency control were the main motivators for this library. In many applications, you can’t just fire off 20 requests simultaneously and hope they resolve in the right order. Instead, you often need to limit how many calls happen at once (&lt;code&gt;maxConcurrentRequests&lt;/code&gt;), while also ensuring critical requests jump the queue (&lt;code&gt;__priority&lt;/code&gt;).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Concurrency&lt;/strong&gt;: If you set &lt;code&gt;maxConcurrentRequests&lt;/code&gt; to, say, 2, &lt;code&gt;axios-retryer&lt;/code&gt; will ensure that no more than two requests are in-flight at any given time. This can mitigate server load and prevent the UI from becoming unresponsive under heavy network traffic.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Priority&lt;/strong&gt;: By passing a &lt;code&gt;__priority&lt;/code&gt; option (numeric, typically using predefined constants) in your request config, you can dictate which requests get processed first from the queue. Lower numeric priority values in the constants (e.g., &lt;code&gt;CRITICAL&lt;/code&gt;) mean higher actual priority.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s a TypeScript snippet demonstrating this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AXIOS_RETRYER_REQUEST_PRIORITIES&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;maxConcurrentRequests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Max two concurrent requests&lt;/span&gt;
  &lt;span class="c1"&gt;// Requests with priority &amp;gt;= HIGH will block lower priority ones&lt;/span&gt;
  &lt;span class="na"&gt;blockingQueueThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AXIOS_RETRYER_REQUEST_PRIORITIES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HIGH&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;exampleRequests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Critical request - gets processed sooner, potentially blocking others&lt;/span&gt;
  &lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/critical-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AXIOS_RETRYER_REQUEST_PRIORITIES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CRITICAL&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Critical data received:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// Standard important request&lt;/span&gt;
  &lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AXIOS_RETRYER_REQUEST_PRIORITIES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HIGH&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User profile received:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// Lower priority request - waits if concurrency is at capacity or blocked&lt;/span&gt;
  &lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/background-sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AXIOS_RETRYER_REQUEST_PRIORITIES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LOW&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Background sync complete:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;exampleRequests&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes, &lt;code&gt;axios-retryer&lt;/code&gt; manages an internal priority queue. When &lt;code&gt;maxConcurrentRequests&lt;/code&gt; is reached, new requests are enqueued. Within that queue, items are sorted by their &lt;code&gt;__priority&lt;/code&gt;. The &lt;code&gt;blockingQueueThreshold&lt;/code&gt; adds another layer, ensuring that no requests with a priority lower than the threshold are processed if higher-priority requests are pending.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retry Strategies (Linear, Exponential, Static, Custom)
&lt;/h2&gt;

&lt;p&gt;We’ve all implemented the typical "retry a request 3 times if it fails," but sometimes a more sophisticated approach is needed. &lt;code&gt;axios-retryer&lt;/code&gt; supports various backoff strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Linear&lt;/strong&gt;: Increments wait times consistently (e.g., 1s, 2s, 3s).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Exponential&lt;/strong&gt;: Doubles the backoff period with each attempt (e.g., 1s, 2s, 4s, 8s). This is the default.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Static&lt;/strong&gt;: Static backoff period (e.g. 2s, 2s, 2s, 2s).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Custom&lt;/strong&gt;: Pass your own function to calculate delays.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You configure the retry behavior within the &lt;code&gt;createRetryer&lt;/code&gt; options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AXIOS_RETRYER_BACKOFF_TYPES&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Total retry attempts&lt;/span&gt;
  &lt;span class="na"&gt;backoffType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AXIOS_RETRYER_BACKOFF_TYPES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EXPONENTIAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 'linear', 'exponential', 'static'&lt;/span&gt;
  &lt;span class="c1"&gt;// You can also specify retryable HTTP methods and status codes&lt;/span&gt;
  &lt;span class="na"&gt;retryableMethods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;options&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;put&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;retryableStatuses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;408&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;599&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="c1"&gt;// Retries on 408, 429, or 5xx&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// This request will use the exponential backoff strategy defined above&lt;/span&gt;
&lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/some-flaky-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed after exponential backoff retries:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a completely custom strategy, you can provide a &lt;code&gt;retryStrategy&lt;/code&gt; object with &lt;code&gt;isRetryable&lt;/code&gt;, &lt;code&gt;shouldRetry&lt;/code&gt;, and &lt;code&gt;getDelay&lt;/code&gt; functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createRetryStrategy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customStrategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryStrategy&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;isRetryable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;shouldRetry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Don't retry POST requests more than once&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Note: attempt is 0-indexed for calculation&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;getDelay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Linear backoff with jitter&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customRetryer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;retryStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customStrategy&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;customRetryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/another-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed with custom strategy:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The library automatically handles the asynchronous timeouts for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  TokenRefreshPlugin (Single Refresh + Replay)
&lt;/h2&gt;

&lt;p&gt;Dealing with expired authentication tokens is a common pain point, especially if multiple requests are made around the token's expiration time. The &lt;code&gt;TokenRefreshPlugin&lt;/code&gt; simplifies this by detecting token-related errors (typically 401 Unauthorized), automatically fetching a new token (once per expiration cycle), and then replaying the requests that failed due to the expired token.&lt;/p&gt;

&lt;p&gt;Here’s how you set it up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRetryer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createTokenRefreshPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer/plugins/TokenRefreshPlugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Import base axios for the refresh function if needed&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;maxConcurrentRequests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="c1"&gt;// other configurations...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenRefreshPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTokenRefreshPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;axiosInstanceForRefresh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This function is called to get a new token&lt;/span&gt;
    &lt;span class="c1"&gt;// It receives an Axios instance specifically for the refresh call&lt;/span&gt;
    &lt;span class="c1"&gt;// to avoid circular dependencies with the retryer's interceptors.&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Attempting to refresh token...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refreshToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;refreshToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Use a clean axios instance for the refresh call&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth/refresh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;refreshToken&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accessToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Token refreshed successfully.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// Must return the new token&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Optional configuration for the plugin&lt;/span&gt;
    &lt;span class="na"&gt;authHeaderName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// Default: 'Authorization'&lt;/span&gt;
    &lt;span class="na"&gt;tokenPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;             &lt;span class="c1"&gt;// Default: 'Bearer '&lt;/span&gt;
    &lt;span class="na"&gt;refreshStatusCodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;          &lt;span class="c1"&gt;// Default: [401]&lt;/span&gt;
    &lt;span class="na"&gt;maxRefreshAttempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// Default: 3&lt;/span&gt;
    &lt;span class="c1"&gt;// Custom detector for APIs that don't use 401 (e.g., GraphQL)&lt;/span&gt;
    &lt;span class="na"&gt;customErrorDetector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UNAUTHENTICATED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token expired&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Add the plugin to the retryer instance&lt;/span&gt;
&lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokenRefreshPlugin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Now, requests made with retryer.axiosInstance will benefit from auto token refresh&lt;/span&gt;
&lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/secure-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Secure data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to get secure data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a request returns a status code matching &lt;code&gt;refreshStatusCodes&lt;/code&gt; (or if &lt;code&gt;customErrorDetector&lt;/code&gt; returns true), the plugin pauses outgoing requests, executes your &lt;code&gt;fetchNewToken&lt;/code&gt; function, updates the default headers of the &lt;code&gt;retryer.axiosInstance&lt;/code&gt; with the new token, and then replays the original failed request and any other requests that were queued while the token was being refreshed.&lt;/p&gt;

&lt;h2&gt;
  
  
  CircuitBreakerPlugin
&lt;/h2&gt;

&lt;p&gt;To prevent an application from repeatedly trying to connect to a service that is known to be failing, you can use the &lt;code&gt;CircuitBreakerPlugin&lt;/code&gt;. Once a configured error threshold is met (e.g., 5 failed requests in a row), the circuit "opens," and subsequent requests to that service fail immediately (short-circuit) without hitting the network. After a cooldown period, the circuit transitions to a "half-open" state, allowing a limited number of test requests. If these succeed, the circuit "closes" and normal operation resumes. If they fail, it re-opens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRetryer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createCircuitBreaker&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer/plugins/CircuitBreakerPlugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Corrected import name&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// other configurations...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;circuitBreakerPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCircuitBreaker&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;failureThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Trip after 5 consecutive failures&lt;/span&gt;
  &lt;span class="na"&gt;openTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// Stay open for 30 seconds&lt;/span&gt;
  &lt;span class="na"&gt;halfOpenMax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// Allow 2 test requests in half-open state&lt;/span&gt;
  &lt;span class="na"&gt;successThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Need 2 successes in half-open to close&lt;/span&gt;
  &lt;span class="na"&gt;useSlidingWindow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;  &lt;span class="c1"&gt;// Set to true for time-based failure counting&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;circuitBreakerPlugin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Requests to a consistently failing service will eventually be short-circuited&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchDataRepeatedly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/unreliable-service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Service responded:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Service call failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAxiosError&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Circuit is open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Circuit breaker is open, not attempting network request.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Simulate multiple calls&lt;/span&gt;
&lt;span class="c1"&gt;// setInterval(fetchDataRepeatedly, 2000);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern is crucial for building resilient applications that can gracefully handle temporary outages of downstream services.&lt;/p&gt;

&lt;h2&gt;
  
  
  CachingPlugin
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;CachingPlugin&lt;/code&gt; (using &lt;code&gt;createCachePlugin&lt;/code&gt;) helps you cache responses from specific endpoints, reducing unnecessary network calls and improving perceived performance. You can configure cache lifetime, which HTTP methods to cache, and more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRetryer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createCachePlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer/plugins/CachingPlugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Corrected import name&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// other configurations...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cachePlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCachePlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;timeToRevalidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Cache entries for 1 minute (in ms)&lt;/span&gt;
  &lt;span class="na"&gt;cacheMethods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;       &lt;span class="c1"&gt;// Only cache GET requests (default)&lt;/span&gt;
  &lt;span class="na"&gt;cleanupInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Check for stale entries every 5 minutes&lt;/span&gt;
  &lt;span class="na"&gt;maxItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;               &lt;span class="c1"&gt;// Store up to 100 cached items&lt;/span&gt;
  &lt;span class="na"&gt;compareHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// Set to true to include headers in cache key&lt;/span&gt;
  &lt;span class="na"&gt;cacheOnlyRetriedRequests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// Set to true to only cache successful retried requests&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachePlugin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchCachedData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fetching /static-data...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/static-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Data 1:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(from network or cache)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fetching /static-data again...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/static-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Data 2:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(likely from cache if within TTR)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;fetchCachedData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// You can also control caching on a per-request basis&lt;/span&gt;
&lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/realtime-updates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__cachingOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// Disable caching for this specific request&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/submit-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__cachingOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Force caching for this POST request (if method allowed globally)&lt;/span&gt;
    &lt;span class="na"&gt;ttr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;   &lt;span class="c1"&gt;// Custom Time To Revalidate: 30 seconds&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plugin automatically generates cache keys based on the request URL, method, and optionally headers. It provides methods to invalidate or clear the cache programmatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metrics/Events
&lt;/h2&gt;

&lt;p&gt;Monitoring real-time performance and understanding request behavior can help you catch bottlenecks or diagnose issues. &lt;code&gt;axios-retryer&lt;/code&gt; emits a variety of events throughout the request lifecycle, allowing you to wire up custom analytics or logging.&lt;/p&gt;

&lt;p&gt;You subscribe to these events using the &lt;code&gt;on&lt;/code&gt; method of the &lt;code&gt;retryer&lt;/code&gt; instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRetryer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios-retryer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRetryer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Enable debug for more event logs&lt;/span&gt;

&lt;span class="nx"&gt;retryer&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onRetryProcessStarted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Event] Retry process started for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beforeRetry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attemptInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Event] Before retry attempt &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;attemptInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attemptNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;afterRetry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attemptInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wasSuccessful&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Event] After retry attempt &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;attemptInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attemptNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Success: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;wasSuccessful&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onRetryProcessFinished&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Event] Retry process finished for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Metrics:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// metrics include totalAttempts, wasSuccessful, etc.&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onMetricsUpdated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;globalMetrics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// These are overall metrics for the retryer instance&lt;/span&gt;
    &lt;span class="c1"&gt;// console.log('[Event] Global metrics updated:', globalMetrics);&lt;/span&gt;
    &lt;span class="c1"&gt;// updateDashboard(globalMetrics);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onTokenRefreshed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Event] Token was successfully refreshed.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Example request to trigger events&lt;/span&gt;
&lt;span class="nx"&gt;retryer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/flaky&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request to flaky endpoint eventually failed or succeeded.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;globalMetrics&lt;/code&gt; object provided by &lt;code&gt;onMetricsUpdated&lt;/code&gt; includes counts for total requests, successful retries, failed retries, and new timer health statistics to help monitor event loop congestion.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Less-Obvious Use Cases
&lt;/h2&gt;

&lt;p&gt;Beyond the standard retry or concurrency scenarios, here are some other ways &lt;code&gt;axios-retryer&lt;/code&gt; can be beneficial:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Offline-First PWAs&lt;/strong&gt;: In Progressive Web Apps, use &lt;code&gt;mode: 'manual'&lt;/code&gt; to store failed requests when offline. When the connection is re-established, call &lt;code&gt;retryer.retryFailedRequests()&lt;/code&gt; to sync critical data, respecting priorities.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Serverless Edge Functions&lt;/strong&gt;: When calling external APIs from environments with strict concurrency limits (like some edge function providers), &lt;code&gt;maxConcurrentRequests&lt;/code&gt; helps stay within quotas.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;React Query/SWR Adapter&lt;/strong&gt;: While libraries like React Query or SWR handle their own caching and some retries, &lt;code&gt;axios-retryer&lt;/code&gt; can manage the underlying Axios instance to provide global concurrency limits, priority queuing, and standardized token refresh logic for all data fetches.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Robust Microservice Communication (Node.js)&lt;/strong&gt;: If your Node.js backend acts as an API gateway or communicates with multiple microservices, &lt;code&gt;axios-retryer&lt;/code&gt; (with plugins like Circuit Breaker) can make these interactions more resilient.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Batch Data Uploads/Processing&lt;/strong&gt;: For scenarios where you need to upload many items or process a batch of API calls, concurrency control ensures you don't overwhelm the server, and retries handle intermittent failures gracefully.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Web Scraping Responsibly&lt;/strong&gt;: When scraping data, use &lt;code&gt;maxConcurrentRequests&lt;/code&gt; and appropriate backoff strategies with &lt;code&gt;queueDelay&lt;/code&gt; to avoid overwhelming the target server and to respect its rate limits.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  📈 Performance &amp;amp; Bundle Size
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;axios-retryer&lt;/code&gt; is designed to be efficient. The core library, including all plugins, comes in at approximately &lt;strong&gt;6.4 kB minified and gzipped&lt;/strong&gt;. The plugin system is modular, so if you don't use a plugin, its code won't be included in your bundle when using tree-shaking.&lt;/p&gt;

&lt;p&gt;Performance considerations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The priority queue uses efficient data structures (like a binary heap) for O(log n) operations.&lt;/li&gt;
&lt;li&gt;  Retry strategies add minimal overhead, primarily driven by JavaScript timers.&lt;/li&gt;
&lt;li&gt;  The new timer management system actively monitors and helps prevent event loop congestion from excessive timers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should integrate smoothly into typical front-end or Node.js projects without significantly impacting bundle size or runtime performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛣️ Roadmap &amp;amp; Contribution Call
&lt;/h2&gt;

&lt;p&gt;I have several features and improvements planned for future releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;WebSocket Reconnection Plugin&lt;/strong&gt;: A dedicated plugin to manage robust WebSocket connections, including automatic reconnection with backoff strategies.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;DevTools Panel&lt;/strong&gt;: A browser extension (e.g., for Chrome/Firefox DevTools) to visualize the request queue, circuit breaker states, cache contents, and active timers.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;More Granular Cache Control&lt;/strong&gt;: Advanced cache invalidation strategies and tagging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Contributions are highly welcome! Whether it's tackling one of these features, suggesting new ones, improving documentation, or reporting bugs, your input is valuable. Please check out the &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file on GitHub, open an issue to discuss your ideas, or submit a pull request.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏁 Conclusion / CTA
&lt;/h2&gt;

&lt;p&gt;If you're tired of cobbling together solutions for API request concurrency, complex retries, token refreshing, circuit breaking, and caching, &lt;code&gt;axios-retryer&lt;/code&gt; offers a unified and powerful approach.&lt;/p&gt;

&lt;p&gt;Install: &lt;code&gt;npm install axios-retryer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Explore the documentation, examples, and source code on &lt;a href="https://github.com/sampleXbro/axios-retryer" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. If you find it useful, please consider giving it a star! I’d love to hear your feedback, learn about your use cases, and see how &lt;code&gt;axios-retryer&lt;/code&gt; can be improved to better serve the developer community.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>axios</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
