<?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: Devil</title>
    <description>The latest articles on DEV Community by Devil (@devil_21cf096c1059553286d).</description>
    <link>https://dev.to/devil_21cf096c1059553286d</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%2F3865079%2F72d2e181-86f5-40ce-a3cb-850642417765.jpg</url>
      <title>DEV Community: Devil</title>
      <link>https://dev.to/devil_21cf096c1059553286d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devil_21cf096c1059553286d"/>
    <language>en</language>
    <item>
      <title>I Built a Developer Trading Card Generator with Google AI Studio — Meet CodeCard Forge</title>
      <dc:creator>Devil</dc:creator>
      <pubDate>Sat, 25 Apr 2026 05:04:55 +0000</pubDate>
      <link>https://dev.to/devil_21cf096c1059553286d/i-built-a-developer-trading-card-generator-with-google-ai-studio-meet-codecard-forge-43i2</link>
      <guid>https://dev.to/devil_21cf096c1059553286d/i-built-a-developer-trading-card-generator-with-google-ai-studio-meet-codecard-forge-43i2</guid>
      <description>&lt;h1&gt;
  
  
  I Used Google AI Studio to Mint My Developer Identity as a Collectible Card — Here's What Happened
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-cloud-next-2026-04-22"&gt;Google Cloud NEXT Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I want to be honest with you: I did not expect this to work.&lt;/p&gt;

&lt;p&gt;Not "work" in the sense of running without errors. I mean work in the sense of — within a single afternoon, going from a random idea in my head to a real, deployed web application that I'm actually proud to show people. That's not how software has ever felt before. Until Google Cloud NEXT '26.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;Google AI Studio dropped a feature at NEXT '26 that lets you describe an app in plain English and watch it get built in front of you — full TypeScript, React components, API integrations, the whole thing. I'd seen the Magic: The Gathering card demo floating around. Cool, but everyone was going to write about that.&lt;/p&gt;

&lt;p&gt;I wanted to build something that felt &lt;em&gt;mine&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So I landed on this: &lt;strong&gt;CodeCard Forge&lt;/strong&gt; — an app where developers mint their own identity as a collectible trading card. You enter your name, your top 3 skills, years of experience, and a one-liner bio. Gemini writes you a "Special Ability" description based on your stack. Imagen generates your avatar. And the card assigns you a rarity tier — Rare, Epic, or Legendary.&lt;/p&gt;

&lt;p&gt;The tagline wrote itself: &lt;em&gt;Mint your developer identity as a collectible.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For my own card I entered: AI Engineer, MI Engineer, DL Engineer — 1 year of experience — and a bio that says "like making machines alive."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Prompt That Started Everything
&lt;/h2&gt;

&lt;p&gt;Here's the exact prompt I typed into Google AI Studio's Build interface:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Create an app called CodeCard Forge that generates a developer trading card. The user enters their name, top 3 skills, years of experience, and a one-line bio. Use Imagen to generate a stylized avatar/portrait for the card, and Gemini to write a fun 'special ability' description based on their skills. Style the card like a collectible trading card with stats and a rare/epic/legendary rarity tier."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hit Run. And then I just... watched.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Actually Surprised Me
&lt;/h2&gt;

&lt;p&gt;I've used AI coding tools before. I expected something half-baked that I'd need to spend an hour fixing.&lt;/p&gt;

&lt;p&gt;What I did not expect was how &lt;strong&gt;fast&lt;/strong&gt; a complete, structured application appeared — not a snippet, not a prototype shell, but a full file tree: &lt;code&gt;components/&lt;/code&gt;, &lt;code&gt;services/&lt;/code&gt;, &lt;code&gt;types.ts&lt;/code&gt;, &lt;code&gt;App.tsx&lt;/code&gt;, deployment config and all. I was reading through the files while they were still being written.&lt;/p&gt;

&lt;p&gt;The moment that genuinely caught me off guard was the "Thinking..." section in the Code Assistant panel. Gemini 2.5 doesn't just generate — it plans out loud. It decided on its own how to split responsibilities between Imagen (visuals) and Gemini (text/lore), how to structure the React components, and how to handle the rarity logic. I didn't tell it any of that.&lt;/p&gt;

&lt;p&gt;The other thing: when it hit errors during generation (and it did — type mismatches, an import conflict), it caught and fixed them itself before I even saw the problem. No red screen, no Stack Overflow tab, no asking me what to do. Just: &lt;em&gt;"Analyzing 10 errors... resolved."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's new behavior. That's not autocomplete.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Result: CodeCard Forge
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxoodey2aevbfq2fg1du.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxoodey2aevbfq2fg1du.png" alt=" " width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final app has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clean forge form on the left (name, skills, XP, bio)&lt;/li&gt;
&lt;li&gt;A live card preview that generates on the right&lt;/li&gt;
&lt;li&gt;Gemini-written "Special Ability" lore based on your actual stack&lt;/li&gt;
&lt;li&gt;An Imagen-generated portrait styled to the card's rarity&lt;/li&gt;
&lt;li&gt;Rarity tiers: Rare → Epic → Legendary (based on years of experience + skill depth)&lt;/li&gt;
&lt;li&gt;Footer: &lt;em&gt;"Art and Ability descriptions powered by Gemini AI. Stylized after Vintage CCG Rarity Standards."&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ae307xk40171clgx4wu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ae307xk40171clgx4wu.png" alt=" " width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I generated my own card. I got &lt;strong&gt;Common&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm choosing to take that as a challenge.&lt;/p&gt;

&lt;p&gt;But here's the thing — look at the Special Ability Gemini wrote for me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;*&lt;em&gt;Algorithmic Awakening — Converts any 'Hardware' or 'Tool' card on your field into a 'Sentient Machine' unit with Power and...&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Common rarity. Legendary ability. An AI accidentally wrote the most accurate description of a self-taught developer I've ever seen. You start underestimated. You adapt. You stack.&lt;/p&gt;

&lt;p&gt;I did not expect a card generator to say something real.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Means for Developers Like Me
&lt;/h2&gt;

&lt;p&gt;I write code with AI. I'm not ashamed of that — I review it, I understand it, I make sure it's correct. What changed with this NEXT '26 feature isn't the code quality. It's the &lt;strong&gt;starting point&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before, "I have an app idea" meant: set up the repo, configure the bundler, wire up the API client, figure out the deployment pipeline, write the boilerplate... and somewhere in there, lose the energy that sparked the idea in the first place.&lt;/p&gt;

&lt;p&gt;Now the starting point is a deployed URL with a working app behind it. The creative work — the idea, the angle, the &lt;em&gt;why&lt;/em&gt; — that's still yours. The scaffolding just doesn't get in the way anymore.&lt;/p&gt;

&lt;p&gt;CodeCard Forge isn't production software. But it's a real thing that exists, that I built in an afternoon, that I can show in a portfolio and talk about in an interview. That's the shift.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It + Build Your Own Card
&lt;/h2&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://ai.studio/apps/3fd4a770-cf13-4220-9b2b-f35b4785287b" rel="noopener noreferrer"&gt;CodeCard Forge — Live Demo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Type in your stack and see what rarity you pull. If you're Legendary, you've earned it.&lt;/p&gt;

&lt;p&gt;And if you want to build something like this yourself, the Google AI Studio Build feature is free to try at &lt;a href="https://aistudio.google.com" rel="noopener noreferrer"&gt;aistudio.google.com&lt;/a&gt;. The only cost is the idea.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: #devchallenge #cloudnextchallenge #googlecloud #gemini #ai #webdev&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>cloudnextchallenge</category>
      <category>googlecloud</category>
      <category>gemini</category>
    </item>
    <item>
      <title>The JWT Refresh Race Condition Nobody Talks About (v0.3.0 — Now Production Ready)</title>
      <dc:creator>Devil</dc:creator>
      <pubDate>Tue, 07 Apr 2026 06:23:58 +0000</pubDate>
      <link>https://dev.to/devil_21cf096c1059553286d/the-jwt-refresh-race-condition-nobody-talks-about-and-how-i-fixed-it-pid</link>
      <guid>https://dev.to/devil_21cf096c1059553286d/the-jwt-refresh-race-condition-nobody-talks-about-and-how-i-fixed-it-pid</guid>
      <description>&lt;h2&gt;
  
  
  The Bug That Kept Logging Me Out
&lt;/h2&gt;

&lt;p&gt;I was building a PWA with a custom Node.js backend and Supabase auth. &lt;br&gt;
Everything worked fine — until users (me) kept getting randomly logged out &lt;br&gt;
for no obvious reason.&lt;/p&gt;

&lt;p&gt;No errors. No warnings. Just suddenly back at the login screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Was Actually Happening
&lt;/h2&gt;

&lt;p&gt;Most JWT auth setups use two refresh strategies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proactive&lt;/strong&gt; — a timer fires ~1 minute before the access token expires and &lt;br&gt;
refreshes it silently in the background.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reactive&lt;/strong&gt; — an Axios interceptor catches 401 errors and refreshes the token &lt;br&gt;
when a request fails.&lt;/p&gt;

&lt;p&gt;The problem: both fired at the same time.&lt;/p&gt;

&lt;p&gt;Here's the exact sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Proactive timer fires → sends refresh token to backend&lt;/li&gt;
&lt;li&gt;An API call returns 401 simultaneously → interceptor also sends the same 
refresh token&lt;/li&gt;
&lt;li&gt;Backend receives two requests with the same refresh token&lt;/li&gt;
&lt;li&gt;First one succeeds → Supabase rotates the token, old one is now dead&lt;/li&gt;
&lt;li&gt;Second one fails with 401 → interceptor hits the failure path → clears 
localStorage → redirects to /login&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;User is logged out. No error. No warning. Just gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Existing Libraries Don't Fix This
&lt;/h2&gt;

&lt;p&gt;I checked axios-auth-refresh and axios-auth-refresh-queue. Both solve &lt;br&gt;
concurrent 401s — multiple requests failing at the same time. &lt;/p&gt;

&lt;p&gt;But neither coordinates with a proactive timer. They only know about &lt;br&gt;
requests going through Axios. Your timer fires outside of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;Both the proactive timer and the reactive interceptor need to share a &lt;br&gt;
single lock. If one is already refreshing, the other should join a queue &lt;br&gt;
and wait for the result — not fire a second request.&lt;/p&gt;

&lt;p&gt;I extracted this pattern into a small package:&lt;/p&gt;

&lt;h2&gt;
  
  
  axios-refresh-sync
&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;axios-refresh-sync@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;createRefreshManager&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-refresh-sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRefreshManager&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;refreshEndpoint&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/auth/refresh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;getAccessToken&lt;/span&gt;&lt;span class="p"&gt;:&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;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;access_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;getRefreshToken&lt;/span&gt;&lt;span class="p"&gt;:&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;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;refresh_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;setTokens&lt;/span&gt;&lt;span class="p"&gt;:&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;refreshToken&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;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;access_token&lt;/span&gt;&lt;span class="dl"&gt;'&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;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;refresh_token&lt;/span&gt;&lt;span class="dl"&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="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;onRefreshFailed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Call after login or app init&lt;/span&gt;
&lt;span class="nx"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scheduleRefresh&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 it. Both the timer and the interceptor now coordinate under one lock.&lt;br&gt;
If one is mid-refresh, the other waits. Supabase only gets called once.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works Internally
&lt;/h2&gt;

&lt;p&gt;Each manager gets its own isolated lock instance containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;acquireLock()&lt;/code&gt; — check if a refresh is already running&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setLock(true/false)&lt;/code&gt; — claim or release the lock&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;enqueue()&lt;/code&gt; — join the waiting queue if locked&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flushQueue()&lt;/code&gt; — resolve or reject everyone waiting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both proactive and interceptor modules read from the same lock instance.&lt;br&gt;
Neither can race the other. Multiple managers don't share state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Works With Any Backend
&lt;/h2&gt;

&lt;p&gt;Despite being built with Supabase in mind, the package is completely &lt;br&gt;
backend agnostic. As long as your refresh endpoint accepts a refresh token &lt;br&gt;
and returns new tokens, it works.&lt;/p&gt;

&lt;p&gt;Storage is also configurable — you bring your own get/set functions, &lt;br&gt;
so localStorage, cookies, or anything else works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update: v0.2.0 — Multi-tab sync
&lt;/h2&gt;

&lt;p&gt;One gap I noticed after publishing: if a token is refreshed in Tab A, &lt;br&gt;
Tab B still had the stale token in memory and would try to refresh again.&lt;/p&gt;

&lt;p&gt;v0.2.0 fixes this using the localStorage &lt;code&gt;storage&lt;/code&gt; event — when one tab &lt;br&gt;
refreshes the token, all other tabs detect it and flush their queues &lt;br&gt;
automatically with the new token. No duplicate refresh requests across tabs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update: v0.3.0 — Production Ready
&lt;/h2&gt;

&lt;p&gt;After some sharp feedback from the community, v0.3.0 fixes several real bugs:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔴 Critical: Interceptor Recursion Bug (Fixed)
&lt;/h3&gt;

&lt;p&gt;The refresh call was using the same axios instance that had the 401 interceptor &lt;br&gt;
attached. If your refresh token expired, the interceptor would catch the 401 from &lt;br&gt;
the refresh endpoint and try to refresh again — infinite loop.&lt;/p&gt;

&lt;p&gt;Fix: The library now creates a bare axios instance internally for refresh calls &lt;br&gt;
with no interceptors attached.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instance Isolation (Fixed)
&lt;/h3&gt;

&lt;p&gt;Two &lt;code&gt;createRefreshManager()&lt;/code&gt; calls previously shared the same lock and timer &lt;br&gt;
state. They would corrupt each other. Each manager now gets fully isolated state.&lt;/p&gt;

&lt;h3&gt;
  
  
  New: &lt;code&gt;destroy()&lt;/code&gt; Method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRefreshManager&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;// On logout or component teardown:&lt;/span&gt;
&lt;span class="nx"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// clears timer, removes interceptor, removes storage listener&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New: Custom Response Parser
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;createRefreshManager&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// If your backend returns different field names:&lt;/span&gt;
  &lt;span class="na"&gt;parseTokens&lt;/span&gt;&lt;span class="p"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;accessToken&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;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;refreshToken&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;refresh&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  19 Tests Added
&lt;/h3&gt;

&lt;p&gt;Full test suite covering concurrent 401s, timer vs interceptor race, &lt;br&gt;
refresh failure, multi-instance isolation, and destroy cleanup.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;npm: &lt;a href="https://npmjs.com/package/axios-refresh-sync" rel="noopener noreferrer"&gt;axios-refresh-sync&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/mk90909876-art/axios-refresh-sync.git" rel="noopener noreferrer"&gt;mk90909876-art/axios-refresh-sync&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've ever had users mysteriously logged out and couldn't figure out why — &lt;br&gt;
this might be it.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>auth</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
