diff --git a/.github/workflows/build-backend-stg.yml b/.github/workflows/build-backend-stg.yml
index 322e4ec4..bcc54942 100644
--- a/.github/workflows/build-backend-stg.yml
+++ b/.github/workflows/build-backend-stg.yml
@@ -69,7 +69,7 @@ jobs:
XTRAMCP_OPENREVIEW_PASSWORD: ${{ secrets.XTRAMCP_OPENREVIEW_PASSWORD_STG }}
XTRAMCP_CROSSREF_EMAIL_ADDRESS: ${{ secrets.XTRAMCP_CROSSREF_EMAIL_ADDRESS_STG }}
XTRAMCP_DOI_EMAIL_ADDRESS: ${{ secrets.XTRAMCP_DOI_EMAIL_ADDRESS_STG }}
- XTRAMCP_ACL_METADATA_DB_URL: ${{ secrets.XTRAMCP_ACL_METADATA_DB_URL_PRD }}
+ XTRAMCP_ACL_METADATA_DB_URL: ${{ secrets.XTRAMCP_ACL_METADATA_DB_URL_STG }}
XTRAMCP_ARXIV_METADATA_DB_URL: ${{ secrets.XTRAMCP_ARXIV_METADATA_DB_URL_STG }}
XTRAMCP_MONGO_URI: ${{ secrets.XTRAMCP_MONGO_URI_STG }}
MONGO_URI: ${{ secrets.MONGO_URI_STG }}
diff --git a/README.md b/README.md
index 4dcd38ab..1fcbada2 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
-**PaperDebugger** is an AI-powered academic writing assistant that helps researchers debug and improve their research papers with intelligent suggestions and seamless Overleaf integration, without leaving the editor. It is powered by a custom MCP-based orchestration engine that simulates the full academic workflow **Research → Critique → Revision**.
+**PaperDebugger** is an AI-powered academic writing assistant that helps researchers debug and improve their research papers with intelligent suggestions and seamless Overleaf integration, without leaving the editor. It is powered by our [custom MCP-based orchestration engine](demo/xtramcp/readme.md) that simulates the full academic workflow **Research → Critique → Revision**.
This enables multi-step reasoning, reviewer-style critique, and structured revision passes beyond standard chat-based assistance.
@@ -50,7 +50,7 @@ PaperDebugger never modifies your project, it only reads and provides suggestion
- **💬 Comment System**: Automatically generate and insert comments into your project
- **📚 Prompt Library**: Custom prompt templates for different use cases
- **🔒 Privacy First**: Your content stays secure - we only read, never modify
-- **🧠 Multi-Agent Orchestration** – [XtraMCP](https://github.com/PaperDebugger/xtramcp) support for literature-grounded research, AI-Conference review, citation verification, and domain-specific revision
+- **🧠 Multi-Agent Orchestration** – [XtraMCP](demo/xtramcp/readme.md) support for literature-grounded research, AI-Conference review, citation verification, and domain-specific revision
https://github.com/user-attachments/assets/6c20924d-1eb6-44d5-95b0-207bd08b718b
diff --git a/demo/xtramcp/readme.md b/demo/xtramcp/readme.md
index ec970988..e2d13de1 100644
--- a/demo/xtramcp/readme.md
+++ b/demo/xtramcp/readme.md
@@ -19,13 +19,14 @@ This document describes the core tools exposed by XtraMCP and how they combine i
| Tool Name | Role | Purpose | Primary Data Source | Presently Deployed |
|---------------------------|-----------|-----------------------------------------------------------------|--------------------------------|----------------------|
| `search_relevant_papers` | Researcher | Fast semantic search over recent CS papers in a local vector DB, enhanced with semantic re-ranker module | Local DB | Yes |
-| `deep_research` | Researcher | Multi-step literature synthesis & positioning of your draft | Local DB + retrieved papers analysis | *Temporarily Disabled* |
-| `online_search_papers` | Researcher | Online search over external academic corpora | OpenReview + arXiv | Yes (*Partially*) with arXiv |
-| `review_paper` | Reviewer | Conference-style structured review of a draft | Your draft + section-level review (static & semantic) | Yes (*Partially*) — Title, Abstract, Intro — to balance operational cost. |
-| `verify_citations` | Reviewer | Ensure citations are grounded, valid, and traceable | Your draft's bibliography | *Coming Soon*! |
+| `deep_research` | Researcher | Multi-step literature synthesis & positioning of your draft | Local DB + retrieved papers analysis | Yes |
+| `online_search_papers` | Researcher | Online search over external academic corpora | OpenReview + arXiv | Yes |
+| `review_paper` | Reviewer | Conference-style structured review of a draft | Your draft + section-level review (static & semantic) | Yes (slightly scaled down to balance operational cost) |
+| `verify_citations` | Reviewer | Ensure citations are grounded, valid, and traceable | Your draft's bibliography | Yes |
+| `generate_citations` | Reviewer | Generates BibTeX-style citations by simplying providing arxiv ID / DOI / URL / title | Your draft | Yes |
| `enhance_academic_writing`| Enhancer | Context-aware rewriting and polishing of selected text | Your draft + XtraGPT | *Temporarily Disabled* |
-| `get_user_papers` | Misc / Researcher| Fetch all published papers with description, by a specific user | OpenReview | *Disabled* (requires auth; easy to enable with local deployment) |
-| `search_user` | Misc | Fetch user's profile, including info such as publications, co-authors | OpenReview | *Disabled* (requires auth; easy to enable with local deployment)|
+| `get_user_papers` | Misc / Researcher| Fetch all published papers with description, by a specific user | OpenReview | Yes |
+| `search_user` | Misc | Fetch user's profile, including info such as publications, co-authors | OpenReview | Yes |
---
@@ -122,7 +123,7 @@ Analyze and review a draft against the standards of **top-tier ML conferences**
## 5. `verify_citations`
**Purpose:**
-Verify that citations in your draft are valid, grounded, and traceable, helping reduce the risk of desk rejection due to incorrect or unverifiable references.
+Verify that citations in your draft are valid, grounded, and traceable, helping reduce the risk of desk rejection due to incorrect or unverifiable references. There have been [embarrassing cases](https://gptzero.me/news/neurips/) where accepted papers were found with hallucinated citations. This tool helps to avoid such occurrences.
**How it works**:
- Parses your bibliography and in-text citations.
@@ -137,8 +138,21 @@ Typical usage:
- “Check whether any citations in this draft are invalid or unverifiable.”
---
+## 6. `generate_citations`
-## 6. `enhance_academic_writing`
+**Purpose:**
+Generate BibTeX-style citations easily by simply providing the paper's arxiv ID or DOI or URL or just its title.
+
+**How it works**:
+- Searches online for the paper's official source
+- Formats into BibTeX-style citation ready for copy-pasting
+- Inform user if proposed information is invalid / unmatched
+
+Typical usage:
+- “generate_citations: [https://arxiv.org/abs/2505.11336, ... ]”
+
+---
+## 7. `enhance_academic_writing`
**Purpose:**
Suggest **context-aware academic writing enhancements** for selected text.
@@ -157,7 +171,7 @@ Suggest **context-aware academic writing enhancements** for selected text.
- "enhance_academic_writing this paragraph to be clearer and more concise, preserving all technical details.”
- "enhance_academic_writing the abstract to be suitable for NeurIPS.”
-## 7. `get_user_papers`
+## 8. `get_user_papers`
**Purpose:**
Retrieve **all papers authored by a given user** (OpenReview), identified by email.
@@ -172,7 +186,7 @@ Useful for quickly assembling a researcher’s publication list or grounding con
- “get_user_papers for
in summary mode.”
- “Retrieve all publications by this researcher and then compare my draft using deep_research.”
-## 8. Conference Formatter (WIP)
+## 9. Conference Formatter (WIP)
Upcoming workflows will:
@@ -191,7 +205,8 @@ Upcoming workflows will:
- **Reviewer Flow**
1. Run `review_paper` on the full draft.
- 2. For high-impact issues, call `enhance_academic_writing` on the relevant spans.
+ 2. For high-impact issues, call `enhance_academic_writing` on the relevant spans.
+ 3. Verify your citations with `verify_citations` or if you haven't yet formatted them, include with `generate_citations`.
- **Enhancer Flow**
1. Select a paragraph or section in Overleaf.
diff --git a/hack/dev.sh b/hack/dev.sh
index 78143403..e074ff0a 100755
--- a/hack/dev.sh
+++ b/hack/dev.sh
@@ -6,20 +6,21 @@ ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &>/dev/null && pwd)
cd $ROOT_DIR
OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
-OPENAI_API_KEY=${OPENAI_API_KEY:-sk-dummy-OPENAI_API_KEY}
+OPENAI_API_KEY=${OPENAI_API_KEY:-}
INFERENCE_BASE_URL=${INFERENCE_BASE_URL:-https://inference.paperdebugger.workers.dev}
-INFERENCE_API_KEY=${INFERENCE_API_KEY:-sk-dummy-OPEN-ROUTER}
+INFERENCE_API_KEY=${INFERENCE_API_KEY:-}
MCP_BASIC_KEY=${MCP_BASIC_KEY:-sk-dummy-MCP_BASIC_KEY}
MCP_PAPERSCORE_KEY=${MCP_PAPERSCORE_KEY:-sk-dummy-MCP_PAPERSCORE_KEY}
XTRAMCP_OPENAI_BASE_URL=${XTRAMCP_OPENAI_BASE_URL:-https://api.openai.com/v1}
-XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-sk-dummy-XTRAMCP_OPENAI_API_KEY}
+XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-}
XTRAMCP_OPENREVIEW_BASE_URL=${XTRAMCP_OPENREVIEW_BASE_URL:-https://api2.openreview.net}
-XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-dummy-XTRAMCP_OPENREVIEW_USERNAME}
-XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-dummy-XTRAMCP_OPENREVIEW_PASSWORD}
-XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-dummy-crossref-email-address}
-XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-dummy-doi-email-address}
-XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-postgresql://dummy-arxiv-metadata-db-url}
-XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-mongodb://dummy-mongo-uri}
+XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-}
+XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-}
+XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-}
+XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-}
+XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-}
+XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-}
+XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-}
PAPERDEBUGGER_IMAGE=${PAPERDEBUGGER_IMAGE:-ghcr.io/paperdebugger/sharelatex-paperdebugger:latest}
MONGO_URI=${MONGO_URI:-}
GHCR_DOCKER_CONFIG=${GHCR_DOCKER_CONFIG:-dummy-ghcr-docker-config}
@@ -42,6 +43,7 @@ helm template $ROOT_DIR/helm-chart \
--set-string xtramcp_openreview_password=$XTRAMCP_OPENREVIEW_PASSWORD \
--set-string xtramcp_crossref_email_address=$XTRAMCP_CROSSREF_EMAIL_ADDRESS \
--set-string xtramcp_doi_email_address=$XTRAMCP_DOI_EMAIL_ADDRESS \
+ --set-string xtramcp_acl_metadata_db_url=$XTRAMCP_ACL_METADATA_DB_URL \
--set-string xtramcp_arxiv_metadata_db_url=$XTRAMCP_ARXIV_METADATA_DB_URL \
--set-string xtramcp_mongo_uri=$XTRAMCP_MONGO_URI \
--set-string paperdebugger.image=$PAPERDEBUGGER_IMAGE \
diff --git a/hack/prd.sh b/hack/prd.sh
index 26b173e0..f3995d7b 100755
--- a/hack/prd.sh
+++ b/hack/prd.sh
@@ -6,21 +6,21 @@ ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &>/dev/null && pwd)
cd $ROOT_DIR
OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
-OPENAI_API_KEY=${OPENAI_API_KEY:-sk-dummy-OPENAI_API_KEY}
+OPENAI_API_KEY=${OPENAI_API_KEY:-}
INFERENCE_BASE_URL=${INFERENCE_BASE_URL:-https://inference.paperdebugger.workers.dev}
-INFERENCE_API_KEY=${INFERENCE_API_KEY:-sk-dummy-OPEN-ROUTER}
+INFERENCE_API_KEY=${INFERENCE_API_KEY:-}
MCP_BASIC_KEY=${MCP_BASIC_KEY:-sk-dummy-MCP_BASIC_KEY}
MCP_PAPERSCORE_KEY=${MCP_PAPERSCORE_KEY:-sk-dummy-MCP_PAPERSCORE_KEY}
XTRAMCP_OPENAI_BASE_URL=${XTRAMCP_OPENAI_BASE_URL:-https://api.openai.com/v1}
-XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-sk-dummy-XTRAMCP_OPENAI_API_KEY}
+XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-}
XTRAMCP_OPENREVIEW_BASE_URL=${XTRAMCP_OPENREVIEW_BASE_URL:-https://api2.openreview.net}
-XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-dummy-XTRAMCP_OPENREVIEW_USERNAME}
-XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-dummy-XTRAMCP_OPENREVIEW_PASSWORD}
-XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-dummy-crossref-email-address}
-XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-dummy-doi-email-address}
-XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-postgresql://dummy-acl-metadata-db-url}
-XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-postgresql://dummy-arxiv-metadata-db-url}
-XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-mongodb://dummy-mongo-uri}
+XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-}
+XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-}
+XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-}
+XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-}
+XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-}
+XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-}
+XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-}
PAPERDEBUGGER_IMAGE=${PAPERDEBUGGER_IMAGE:-ghcr.io/paperdebugger/sharelatex-paperdebugger:latest}
MONGO_URI=${MONGO_URI:-}
GHCR_DOCKER_CONFIG=${GHCR_DOCKER_CONFIG:-dummy-ghcr-docker-config}
diff --git a/hack/stg.sh b/hack/stg.sh
index 9e400860..c1cc86f6 100755
--- a/hack/stg.sh
+++ b/hack/stg.sh
@@ -8,19 +8,19 @@ cd $ROOT_DIR
OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
OPENAI_API_KEY=${OPENAI_API_KEY:-}
INFERENCE_BASE_URL=${INFERENCE_BASE_URL:-https://inference.paperdebugger.workers.dev}
-INFERENCE_API_KEY=${INFERENCE_API_KEY:-sk-dummy-OPEN-ROUTER}
+INFERENCE_API_KEY=${INFERENCE_API_KEY:-}
MCP_BASIC_KEY=${MCP_BASIC_KEY:-sk-dummy-MCP_BASIC_KEY}
MCP_PAPERSCORE_KEY=${MCP_PAPERSCORE_KEY:-sk-dummy-MCP_PAPERSCORE_KEY}
XTRAMCP_OPENAI_BASE_URL=${XTRAMCP_OPENAI_BASE_URL:-https://api.openai.com/v1}
-XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-sk-dummy-XTRAMCP_OPENAI_API_KEY}
+XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-}
XTRAMCP_OPENREVIEW_BASE_URL=${XTRAMCP_OPENREVIEW_BASE_URL:-https://api2.openreview.net}
-XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-dummy-XTRAMCP_OPENREVIEW_USERNAME}
-XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-dummy-XTRAMCP_OPENREVIEW_PASSWORD}
-XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-dummy-crossref-email-address}
-XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-dummy-doi-email-address}
-XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-postgresql://dummy-acl-metadata-db-url}
-XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-postgresql://dummy-arxiv-metadata-db-url}
-XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-mongodb://dummy-mongo-uri}
+XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-}
+XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-}
+XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-}
+XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-}
+XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-}
+XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-}
+XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-}
PAPERDEBUGGER_IMAGE=${PAPERDEBUGGER_IMAGE:-ghcr.io/paperdebugger/sharelatex-paperdebugger:latest}
MONGO_URI=${MONGO_URI:-}
GHCR_DOCKER_CONFIG=${GHCR_DOCKER_CONFIG:-dummy-ghcr-docker-config}
diff --git a/helm-chart/templates/paperdebugger.yaml b/helm-chart/templates/paperdebugger.yaml
index 098d65d2..982e1f1a 100644
--- a/helm-chart/templates/paperdebugger.yaml
+++ b/helm-chart/templates/paperdebugger.yaml
@@ -15,8 +15,8 @@ spec:
spec:
imagePullSecrets:
- name: ghcr-secret
- {{ if .Values.mongo.in_cluster }}
initContainers:
+ {{- if .Values.mongo.in_cluster }}
- name: init-mongodb
image: mongo:latest
command:
@@ -26,7 +26,17 @@ spec:
"--eval",
'db.isMaster().primary || rs.initiate({_id: "in-cluster", members: [{_id: 0, host: "mongo:27017"}]})',
]
- {{ end }}
+ {{- end }}
+ - name: wait-for-xtramcp-port
+ image: busybox:1.36
+ command: ["sh", "-c"]
+ args:
+ - |
+ echo "Waiting for xtramcp health endpoint..."
+ until wget -q --spider http://paperdebugger-xtramcp-server:8080/health; do
+ sleep 2
+ done
+ echo "xtramcp is healthy."
containers:
- name: paperdebugger
image: {{ .Values.paperdebugger.image }}
diff --git a/webapp/_webapp/src/index.css b/webapp/_webapp/src/index.css
index 77d8049e..9802e32a 100644
--- a/webapp/_webapp/src/index.css
+++ b/webapp/_webapp/src/index.css
@@ -219,7 +219,12 @@ object {
border: 1px solid;
background-color: transparent;
overflow: hidden;
- @apply overflow-hidden w-full h-full dark:!border-default-200 !border-default-200;
+ @apply overflow-hidden w-full h-full dark:!border-default-200 !border-default-200 text-default-800;
+
+ textarea,
+ input {
+ background-color: var(--pd-default-bg);
+ }
}
.pd-app-control-title-bar {
diff --git a/webapp/_webapp/src/libs/apiclient.ts b/webapp/_webapp/src/libs/apiclient.ts
index bc932787..5f83bfcc 100644
--- a/webapp/_webapp/src/libs/apiclient.ts
+++ b/webapp/_webapp/src/libs/apiclient.ts
@@ -7,6 +7,7 @@ import { EventEmitter } from "events";
import { ErrorCode, ErrorSchema } from "../pkg/gen/apiclient/shared/v1/shared_pb";
import { errorToast } from "./toasts";
import { storage } from "./storage";
+import { useAuthStore } from "../stores/auth-store";
// Exhaustive type check helper - will cause compile error if a case is not handled
const assertNever = (x: never): never => {
@@ -29,6 +30,7 @@ class ApiClient {
private axiosInstance: AxiosInstance;
private refreshToken: string | null;
private onTokenRefreshedEventEmitter: EventEmitter;
+ private refreshPromise: Promise | null = null;
constructor(baseURL: string, apiVersion: ApiVersion) {
this.axiosInstance = axios.create({
@@ -64,6 +66,8 @@ class ApiClient {
}
setTokens(token: string, refreshToken: string): void {
+ useAuthStore.getState().setToken(token);
+ useAuthStore.getState().setRefreshToken(refreshToken);
this.refreshToken = refreshToken;
this.axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${token}`;
}
@@ -89,15 +93,27 @@ class ApiClient {
}
async refresh() {
- const response = await this.axiosInstance.post("/auth/refresh", {
- refreshToken: this.refreshToken,
- });
- const resp = fromJson(RefreshTokenResponseSchema, response.data);
- this.setTokens(resp.token, resp.refreshToken);
- this.onTokenRefreshedEventEmitter.emit("tokenRefreshed", {
- token: resp.token,
- refreshToken: resp.refreshToken,
- });
+ if (this.refreshPromise) {
+ return this.refreshPromise;
+ }
+
+ this.refreshPromise = (async () => {
+ try {
+ const response = await this.axiosInstance.post("/auth/refresh", {
+ refreshToken: this.refreshToken,
+ });
+ const resp = fromJson(RefreshTokenResponseSchema, response.data);
+ this.setTokens(resp.token, resp.refreshToken);
+ this.onTokenRefreshedEventEmitter.emit("tokenRefreshed", {
+ token: resp.token,
+ refreshToken: resp.refreshToken,
+ });
+ } finally {
+ this.refreshPromise = null;
+ }
+ })();
+
+ return this.refreshPromise;
}
private async requestWithRefresh(config: AxiosRequestConfig): Promise {