Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions extension/background.js
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ async function getConfig() {
);
return {
token: session.token || '',
refreshToken: session.refreshToken,
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Missing fallback — inconsistent with token field

token gets a || '' fallback (line 11) so callers always see a string. refreshToken has no fallback, so it can be undefined when no refresh token is stored. This is a minor inconsistency — consider session.refreshToken || '' for symmetry, or add a comment explaining why undefined is intentional here (e.g. so !refreshToken correctly triggers the "Not logged in" guard in rotateAccessToken).

serverUrl: API_URL,
};
}
Expand Down Expand Up @@ -49,7 +50,7 @@ async function fetchMemories(query, limit = 5) {
}

async function submitConversation(conversation, sourceModel) {
return apiFetch('/v1/memory/submit', {
return apiFetch(`/v1/memory/submit`, {
Comment thread
Freedisch marked this conversation as resolved.
Outdated
method: 'POST',
body: JSON.stringify({ conversation, source_model: sourceModel }),
});
Expand All @@ -61,8 +62,9 @@ async function rotateAccessToken() {
throw new Error('Not logged in please open the extension to log in');
}

const response = await fetch(`${serverUrl}${`/v1/auth/refresh`}`, {
const response = await fetch(`${serverUrl}/v1/auth/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken }),
});

Expand Down Expand Up @@ -126,6 +128,9 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
case 'LIST_MEMORIES': {
return apiFetch('/v1/memory');
}
case 'GENERATE_MCP_TOKEN': {
return apiFetch('/v1/mcp/token', { method: 'POST' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edge case: GENERATE_MCP_TOKEN silently fails if the service worker is restarted mid-call

This is a general concern for the new message-passing architecture, but it's most user-visible here. If the Manifest V3 service worker is suspended between the popup sending GENERATE_MCP_TOKEN and apiFetch completing, chrome.runtime.sendMessage can reject with "Could not establish connection". The popup's catch block handles it (shows "Error"), but the user has no indication of why — and retrying will likely work.

Minor, but worth noting: apiFetch('/v1/mcp/token', { method: 'POST' }) sends a POST with an empty body. If the server expects a JSON body (even {}), this could 400. The other POST call (submitConversation) always includes a body. Confirm the /v1/mcp/token endpoint accepts an empty-body POST.

}
case 'GET_CONFIG': {
return getConfig();
}
Expand Down
21 changes: 7 additions & 14 deletions extension/popup/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,15 @@ $('btn-cancel').addEventListener('click', () => showView('login'));
async function loadConnectedState(token) {
_activeToken = token;
try {
const res = await fetch(`${API_URL}/v1/memory`, {
headers: { Authorization: `Bearer ${token}` },
});
const res = await chrome.runtime.sendMessage({ type: 'LIST_MEMORIES' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleanup: _activeToken and API_URL are now dead code

After this PR, all API calls in popup.js go through chrome.runtime.sendMessage instead of direct fetch. This means:

  • _activeToken (line 4) is assigned on line 86 and cleared on logout (line 153), but is never read anywhere. It was previously used as the Authorization header in the MCP token fetch, but that now goes through the background too.
  • API_URL (line 2) was used for the direct fetch calls to /v1/memory and /v1/mcp/token. Both are removed in this PR, leaving the constant unused.

Both should be removed to avoid confusion about whether popup.js still makes direct API calls.


if (res.status === 401) {
await chrome.storage.sync.remove(['userName', 'userEmail', 'userAvatar']);
await chrome.storage.session.remove(['token']);
if (!res.ok) {
showView('login');
setMsg('Session expired — please sign in again', 'error');
setMsg('Could not reach server', 'error');
Comment thread
Freedisch marked this conversation as resolved.
Outdated
return;
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
}

const data = await res.json();
const data = res.data;
$('stat-memories').textContent = data.count ?? data.memories?.length ?? 0;

showView('connected');
Expand All @@ -114,12 +110,9 @@ $('btn-generate-mcp').addEventListener('click', async () => {
btn.disabled = true;
btn.textContent = '…';
try {
const res = await fetch(`${API_URL}/v1/mcp/token`, {
method: 'POST',
headers: { Authorization: `Bearer ${_activeToken}` },
});
if (!res.ok) throw new Error('server error');
const data = await res.json();
const res = await chrome.runtime.sendMessage({ type: 'GENERATE_MCP_TOKEN' });
if (!res.ok) throw new Error(res.error || 'server error');
const data = res.data;
$('mcp-token-value').textContent = data.mcp_token;
$('mcp-token-display').style.display = 'block';
$('btn-copy-mcp').textContent = 'Copy';
Expand Down
Loading