Compare commits

...

4 Commits

Author SHA1 Message Date
Alexander Brown
aa5c54b482 Merge branch 'main' into refactor/auth-token-priority 2026-03-30 12:31:01 -07:00
Benjamin Lu
86a3938d11 test: add runtime-safe browser_tests alias (#10735)
## What changed

Added a runtime-safe `#e2e/*` alias for `browser_tests`, updated the
browser test docs, and migrated a representative fixture/spec import
path to the new convention.

## Why

`@/*` only covers `src/`, so browser test imports were falling back to
deep relative paths. `#e2e/*` resolves in both Node/Playwright runtime
and TypeScript.

## Validation

- `pnpm format`
- `pnpm typecheck:browser`
- `pnpm exec playwright test browser_tests/tests/actionbar.spec.ts
--list`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10735-test-add-runtime-safe-browser_tests-alias-3336d73d36508122b253cb36a4ead1c1)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-30 19:24:09 +00:00
jaeone94
e11a1776ed fix: prevent saving active workflow content to inactive tab on close (#10745)
## Summary

- Closing an inactive workflow tab and clicking "Save" overwrites that
workflow with the **active** tab's content, causing permanent data loss
- `saveWorkflow()` and `saveWorkflowAs()` call `checkState()` which
serializes `app.rootGraph` (the active canvas) into the inactive
workflow's `changeTracker.activeState`
- Guard `checkState()` to only run when the workflow being saved is the
active one — in both `saveWorkflow` and `saveWorkflowAs`

## Linked Issues

- Fixes https://github.com/Comfy-Org/ComfyUI/issues/13230

## Root Cause

PR #9137 (commit `9fb93a5b0`, v1.41.7) added
`workflow.changeTracker?.checkState()` inside `saveWorkflow()` and
`saveWorkflowAs()`. `checkState()` always serializes `app.rootGraph` —
the graph on the canvas. When called on an inactive tab's change
tracker, it captures the active tab's data instead.

## Test plan

- [x] E2E: "Closing an inactive tab with save preserves its own content"
— persisted workflow B with added node, close while A is active, re-open
and verify
- [x] E2E: "Closing an inactive unsaved tab with save preserves its own
content" — temporary workflow B with added node, close while A is
active, save-as with filename, re-open and verify
- [x] Manual: open A and B, edit B, switch to A, close B tab, click
Save, re-open B — content should be B's not A's
2026-03-30 12:12:38 -07:00
bymyself
7b6f431496 refactor: extract auth-routing from workspaceApi to auth domain
- Add getAuthHeaderOrThrow() and getFirebaseAuthHeaderOrThrow() to authStore
- Delegate workspaceApi's auth-or-throw helpers to authStore methods
- Remove unused i18n import from workspaceApi
- Update shared mock factory with new methods
- Thrown errors now use AuthStoreError (auth domain)
2026-03-29 17:26:12 -07:00
9 changed files with 434 additions and 75 deletions

View File

@@ -119,7 +119,7 @@ When writing new tests, follow these patterns:
```typescript
// Import the test fixture
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
test.describe('Feature Name', () => {
// Set up test environment if needed
@@ -148,6 +148,12 @@ Always check for existing helpers and fixtures before implementing new ones:
Most common testing needs are already addressed by these helpers, which will make your tests more consistent and reliable.
### Import Conventions
- Prefer `@e2e/*` for imports within `browser_tests/`
- Continue using `@/*` for imports from `src/`
- Avoid introducing new deep relative imports within `browser_tests/` when the alias is available
### Key Testing Patterns
1. **Focus elements explicitly**:

View File

@@ -2,42 +2,42 @@ import type { APIRequestContext, Locator, Page } from '@playwright/test'
import { test as base } from '@playwright/test'
import { config as dotenvConfig } from 'dotenv'
import { TestIds } from './selectors'
import { sleep } from './utils/timing'
import { comfyExpect } from './utils/customMatchers'
import { NodeBadgeMode } from '../../src/types/nodeSource'
import { ComfyActionbar } from '../helpers/actionbar'
import { ComfyTemplates } from '../helpers/templates'
import { ComfyMouse } from './ComfyMouse'
import { VueNodeHelpers } from './VueNodeHelpers'
import { ComfyNodeSearchBox } from './components/ComfyNodeSearchBox'
import { ComfyNodeSearchBoxV2 } from './components/ComfyNodeSearchBoxV2'
import { ContextMenu } from './components/ContextMenu'
import { SettingDialog } from './components/SettingDialog'
import { BottomPanel } from './components/BottomPanel'
import { QueuePanel } from './components/QueuePanel'
import { ComfyActionbar } from '@e2e/helpers/actionbar'
import { ComfyTemplates } from '@e2e/helpers/templates'
import { ComfyMouse } from '@e2e/fixtures/ComfyMouse'
import { TestIds } from '@e2e/fixtures/selectors'
import { comfyExpect } from '@e2e/fixtures/utils/customMatchers'
import { assetPath } from '@e2e/fixtures/utils/paths'
import { sleep } from '@e2e/fixtures/utils/timing'
import { VueNodeHelpers } from '@e2e/fixtures/VueNodeHelpers'
import { BottomPanel } from '@e2e/fixtures/components/BottomPanel'
import { ComfyNodeSearchBox } from '@e2e/fixtures/components/ComfyNodeSearchBox'
import { ComfyNodeSearchBoxV2 } from '@e2e/fixtures/components/ComfyNodeSearchBoxV2'
import { ContextMenu } from '@e2e/fixtures/components/ContextMenu'
import { QueuePanel } from '@e2e/fixtures/components/QueuePanel'
import { SettingDialog } from '@e2e/fixtures/components/SettingDialog'
import {
AssetsSidebarTab,
NodeLibrarySidebarTab,
WorkflowsSidebarTab
} from './components/SidebarTab'
import { Topbar } from './components/Topbar'
import { AssetsHelper } from './helpers/AssetsHelper'
import { CanvasHelper } from './helpers/CanvasHelper'
import { PerformanceHelper } from './helpers/PerformanceHelper'
import { QueueHelper } from './helpers/QueueHelper'
import { ClipboardHelper } from './helpers/ClipboardHelper'
import { CommandHelper } from './helpers/CommandHelper'
import { DragDropHelper } from './helpers/DragDropHelper'
import { FeatureFlagHelper } from './helpers/FeatureFlagHelper'
import { KeyboardHelper } from './helpers/KeyboardHelper'
import { NodeOperationsHelper } from './helpers/NodeOperationsHelper'
import { SettingsHelper } from './helpers/SettingsHelper'
import { AppModeHelper } from './helpers/AppModeHelper'
import { SubgraphHelper } from './helpers/SubgraphHelper'
import { ToastHelper } from './helpers/ToastHelper'
import { WorkflowHelper } from './helpers/WorkflowHelper'
import { assetPath } from './utils/paths'
} from '@e2e/fixtures/components/SidebarTab'
import { Topbar } from '@e2e/fixtures/components/Topbar'
import { AppModeHelper } from '@e2e/fixtures/helpers/AppModeHelper'
import { AssetsHelper } from '@e2e/fixtures/helpers/AssetsHelper'
import { CanvasHelper } from '@e2e/fixtures/helpers/CanvasHelper'
import { ClipboardHelper } from '@e2e/fixtures/helpers/ClipboardHelper'
import { CommandHelper } from '@e2e/fixtures/helpers/CommandHelper'
import { DragDropHelper } from '@e2e/fixtures/helpers/DragDropHelper'
import { FeatureFlagHelper } from '@e2e/fixtures/helpers/FeatureFlagHelper'
import { KeyboardHelper } from '@e2e/fixtures/helpers/KeyboardHelper'
import { NodeOperationsHelper } from '@e2e/fixtures/helpers/NodeOperationsHelper'
import { PerformanceHelper } from '@e2e/fixtures/helpers/PerformanceHelper'
import { QueueHelper } from '@e2e/fixtures/helpers/QueueHelper'
import { SettingsHelper } from '@e2e/fixtures/helpers/SettingsHelper'
import { SubgraphHelper } from '@e2e/fixtures/helpers/SubgraphHelper'
import { ToastHelper } from '@e2e/fixtures/helpers/ToastHelper'
import { WorkflowHelper } from '@e2e/fixtures/helpers/WorkflowHelper'
import type { WorkspaceStore } from '../types/globals'
dotenvConfig()

View File

@@ -2,8 +2,8 @@ import type { Response } from '@playwright/test'
import { expect, mergeTests } from '@playwright/test'
import type { StatusWsMessage } from '../../src/schemas/apiSchema'
import { comfyPageFixture } from '../fixtures/ComfyPage'
import { webSocketFixture } from '../fixtures/ws'
import { comfyPageFixture } from '@e2e/fixtures/ComfyPage'
import { webSocketFixture } from '@e2e/fixtures/ws'
import type { WorkspaceStore } from '../types/globals'
const test = mergeTests(comfyPageFixture, webSocketFixture)

View File

@@ -323,6 +323,174 @@ test.describe('Workflow Persistence', () => {
expect(linkCountAfter).toBe(linkCountBefore)
})
test('Closing an inactive tab with save preserves its own content', async ({
comfyPage
}) => {
test.info().annotations.push({
type: 'regression',
description:
'PR #10745 — saveWorkflow called checkState on inactive tab, serializing the active graph instead'
})
await comfyPage.settings.setSetting(
'Comfy.Workflow.WorkflowTabsPosition',
'Topbar'
)
const suffix = Date.now().toString(36)
const nameA = `test-A-${suffix}`
const nameB = `test-B-${suffix}`
// Save the default workflow as A
await comfyPage.menu.topbar.saveWorkflow(nameA)
const nodeCountA = await comfyPage.nodeOps.getNodeCount()
// Create B: duplicate and save
await comfyPage.command.executeCommand('Comfy.DuplicateWorkflow')
await comfyPage.nextFrame()
await comfyPage.menu.topbar.saveWorkflow(nameB)
// Add a Note node in B to mark it as modified
await comfyPage.page.evaluate(() => {
window.app!.graph.add(window.LiteGraph!.createNode('Note', undefined, {}))
})
await comfyPage.nextFrame()
const nodeCountB = await comfyPage.nodeOps.getNodeCount()
expect(nodeCountB).toBe(nodeCountA + 1)
// Trigger checkState so isModified is set
await comfyPage.page.evaluate(() => {
const em = window.app!.extensionManager as unknown as Record<
string,
{ activeWorkflow?: { changeTracker?: { checkState(): void } } }
>
em.workflow?.activeWorkflow?.changeTracker?.checkState()
})
// Switch to A via topbar tab (making B inactive)
await comfyPage.menu.topbar.getWorkflowTab(nameA).click()
await comfyPage.workflow.waitForWorkflowIdle()
await expect
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 3000 })
.toBe(nodeCountA)
// Close inactive B tab via middle-click — triggers "Save before closing?"
await comfyPage.menu.topbar.getWorkflowTab(nameB).click({
button: 'middle'
})
// Click "Save" in the dirty close dialog
const saveButton = comfyPage.page.getByRole('button', { name: 'Save' })
await saveButton.waitFor({ state: 'visible' })
await saveButton.click()
await comfyPage.workflow.waitForWorkflowIdle()
await comfyPage.nextFrame()
// Verify we're still on A with A's content
await expect
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 3000 })
.toBe(nodeCountA)
// Re-open B from sidebar saved list
const workflowsTab = comfyPage.menu.workflowsTab
await workflowsTab.open()
await workflowsTab.getPersistedItem(nameB).dblclick()
await comfyPage.workflow.waitForWorkflowIdle()
// B should have the extra Note node we added, not A's node count
await expect
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 5000 })
.toBe(nodeCountB)
})
test('Closing an inactive unsaved tab with save preserves its own content', async ({
comfyPage
}) => {
test.info().annotations.push({
type: 'regression',
description:
'PR #10745 — saveWorkflowAs called checkState on inactive temp tab, serializing the active graph'
})
await comfyPage.settings.setSetting(
'Comfy.Workflow.WorkflowTabsPosition',
'Topbar'
)
const suffix = Date.now().toString(36)
const nameA = `test-A-${suffix}`
const nameB = `test-B-${suffix}`
// Save the default workflow as A
await comfyPage.menu.topbar.saveWorkflow(nameA)
const nodeCountA = await comfyPage.nodeOps.getNodeCount()
// Create B as an unsaved workflow with a Note node
await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow')
await comfyPage.nextFrame()
await comfyPage.page.evaluate(() => {
window.app!.graph.add(window.LiteGraph!.createNode('Note', undefined, {}))
})
await comfyPage.nextFrame()
// Trigger checkState so isModified is set
await comfyPage.page.evaluate(() => {
const em = window.app!.extensionManager as unknown as Record<
string,
{ activeWorkflow?: { changeTracker?: { checkState(): void } } }
>
em.workflow?.activeWorkflow?.changeTracker?.checkState()
})
const nodeCountB = await comfyPage.nodeOps.getNodeCount()
expect(nodeCountB).toBe(1)
expect(nodeCountA).not.toBe(nodeCountB)
// Switch to A via topbar tab (making unsaved B inactive)
await comfyPage.menu.topbar.getWorkflowTab(nameA).click()
await comfyPage.workflow.waitForWorkflowIdle()
await expect
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 3000 })
.toBe(nodeCountA)
// Close inactive unsaved B tab — triggers "Save before closing?"
await comfyPage.menu.topbar
.getWorkflowTab('Unsaved Workflow')
.click({ button: 'middle' })
// Click "Save" in the dirty close dialog (scoped to dialog)
const dialog = comfyPage.page.getByRole('dialog')
const saveButton = dialog.getByRole('button', { name: 'Save' })
await saveButton.waitFor({ state: 'visible' })
await saveButton.click()
// Fill in the filename dialog
const saveDialog = comfyPage.menu.topbar.getSaveDialog()
await saveDialog.waitFor({ state: 'visible' })
await saveDialog.fill(nameB)
await comfyPage.page.keyboard.press('Enter')
await comfyPage.workflow.waitForWorkflowIdle()
await comfyPage.nextFrame()
// Verify we're still on A with A's content
await expect
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 3000 })
.toBe(nodeCountA)
// Re-open B from sidebar saved list
const workflowsTab = comfyPage.menu.workflowsTab
await workflowsTab.open()
await workflowsTab.getPersistedItem(nameB).dblclick()
await comfyPage.workflow.waitForWorkflowIdle()
// B should have 1 node (the Note), not A's node count
await expect
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 5000 })
.toBe(nodeCountB)
})
test('Splitter panel sizes persist correctly in localStorage', async ({
comfyPage
}) => {

View File

@@ -139,7 +139,7 @@ export const useWorkflowService = () => {
}
if (isSelfOverwrite) {
workflow.changeTracker?.checkState()
if (workflowStore.isActive(workflow)) workflow.changeTracker?.checkState()
await saveWorkflow(workflow)
} else {
let target: ComfyWorkflow
@@ -156,7 +156,7 @@ export const useWorkflowService = () => {
app.rootGraph.extra.linearMode = isApp
target.initialMode = isApp ? 'app' : 'graph'
}
target.changeTracker?.checkState()
if (workflowStore.isActive(target)) target.changeTracker?.checkState()
await workflowStore.saveWorkflow(target)
}
@@ -173,7 +173,7 @@ export const useWorkflowService = () => {
if (workflow.isTemporary) {
await saveWorkflowAs(workflow)
} else {
workflow.changeTracker?.checkState()
if (workflowStore.isActive(workflow)) workflow.changeTracker?.checkState()
const isApp = workflow.initialMode === 'app'
const expectedPath =

View File

@@ -343,6 +343,10 @@ export const useWorkspaceAuthStore = defineStore('workspaceAuth', () => {
}
}
function getWorkspaceToken(): string | undefined {
return workspaceToken.value ?? undefined
}
function clearWorkspaceContext(): void {
// Increment request ID to invalidate any in-flight stale refresh operations
refreshRequestId++
@@ -370,6 +374,7 @@ export const useWorkspaceAuthStore = defineStore('workspaceAuth', () => {
switchWorkspace,
refreshToken,
getWorkspaceAuthHeader,
getWorkspaceToken,
clearWorkspaceContext
}
})

View File

@@ -0,0 +1,211 @@
import type { User } from 'firebase/auth'
import * as firebaseAuth from 'firebase/auth'
import { setActivePinia } from 'pinia'
import type { Mock } from 'vitest'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import * as vuefire from 'vuefire'
import { useAuthStore } from '@/stores/authStore'
import { createTestingPinia } from '@pinia/testing'
const { mockFeatureFlags } = vi.hoisted(() => ({
mockFeatureFlags: {
teamWorkspacesEnabled: false
}
}))
const { mockDistributionTypes } = vi.hoisted(() => ({
mockDistributionTypes: {
isCloud: true,
isDesktop: true
}
}))
const mockWorkspaceAuthHeader = vi.fn().mockReturnValue(null)
const mockGetWorkspaceToken = vi.fn().mockReturnValue(undefined)
const mockClearWorkspaceContext = vi.fn()
vi.mock('@/platform/workspace/stores/workspaceAuthStore', () => ({
useWorkspaceAuthStore: () => ({
getWorkspaceAuthHeader: mockWorkspaceAuthHeader,
getWorkspaceToken: mockGetWorkspaceToken,
clearWorkspaceContext: mockClearWorkspaceContext
})
}))
vi.mock('@/composables/useFeatureFlags', () => ({
useFeatureFlags: () => ({
flags: mockFeatureFlags
})
}))
vi.mock('vuefire', () => ({
useFirebaseAuth: vi.fn()
}))
vi.mock('vue-i18n', () => ({
useI18n: () => ({ t: (key: string) => key }),
createI18n: () => ({ global: { t: (key: string) => key } })
}))
vi.mock('firebase/auth', async (importOriginal) => {
const actual = await importOriginal<typeof firebaseAuth>()
return {
...actual,
signInWithEmailAndPassword: vi.fn(),
createUserWithEmailAndPassword: vi.fn(),
signOut: vi.fn(),
onAuthStateChanged: vi.fn(),
onIdTokenChanged: vi.fn(),
signInWithPopup: vi.fn(),
GoogleAuthProvider: class {
addScope = vi.fn()
setCustomParameters = vi.fn()
},
GithubAuthProvider: class {
addScope = vi.fn()
setCustomParameters = vi.fn()
},
getAdditionalUserInfo: vi.fn(),
setPersistence: vi.fn().mockResolvedValue(undefined)
}
})
vi.mock('@/platform/telemetry', () => ({
useTelemetry: () => ({ trackAuth: vi.fn() })
}))
vi.mock('@/stores/toastStore', () => ({
useToastStore: () => ({ add: vi.fn() })
}))
vi.mock('@/services/dialogService')
vi.mock('@/platform/distribution/types', () => mockDistributionTypes)
const mockApiKeyGetAuthHeader = vi.fn().mockReturnValue(null)
vi.mock('@/stores/apiKeyAuthStore', () => ({
useApiKeyAuthStore: () => ({
getAuthHeader: mockApiKeyGetAuthHeader,
getApiKey: vi.fn(),
currentUser: null,
isAuthenticated: false,
storeApiKey: vi.fn(),
clearStoredApiKey: vi.fn()
})
}))
type MockUser = Omit<User, 'getIdToken'> & { getIdToken: Mock }
describe('auth token priority chain', () => {
let store: ReturnType<typeof useAuthStore>
let authStateCallback: (user: User | null) => void
const mockAuth: Record<string, unknown> = {}
const mockUser: MockUser = {
uid: 'test-user-id',
email: 'test@example.com',
getIdToken: vi.fn().mockResolvedValue('firebase-token')
} as Partial<User> as MockUser
beforeEach(() => {
vi.resetAllMocks()
mockFeatureFlags.teamWorkspacesEnabled = false
mockWorkspaceAuthHeader.mockReturnValue(null)
mockGetWorkspaceToken.mockReturnValue(undefined)
mockApiKeyGetAuthHeader.mockReturnValue(null)
mockUser.getIdToken.mockResolvedValue('firebase-token')
vi.mocked(vuefire.useFirebaseAuth).mockReturnValue(
mockAuth as unknown as ReturnType<typeof vuefire.useFirebaseAuth>
)
vi.mocked(firebaseAuth.onAuthStateChanged).mockImplementation(
(_, callback) => {
authStateCallback = callback as (user: User | null) => void
;(callback as (user: User | null) => void)(mockUser)
return vi.fn()
}
)
setActivePinia(createTestingPinia({ stubActions: false }))
store = useAuthStore()
})
describe('getAuthHeader priority', () => {
it('returns workspace auth header when workspace is active and feature enabled', async () => {
mockFeatureFlags.teamWorkspacesEnabled = true
mockWorkspaceAuthHeader.mockReturnValue({
Authorization: 'Bearer workspace-token'
})
const header = await store.getAuthHeader()
expect(header).toEqual({
Authorization: 'Bearer workspace-token'
})
})
it('returns Firebase token when workspace is not active but user is authenticated', async () => {
mockFeatureFlags.teamWorkspacesEnabled = true
mockWorkspaceAuthHeader.mockReturnValue(null)
const header = await store.getAuthHeader()
expect(header).toEqual({
Authorization: 'Bearer firebase-token'
})
})
it('returns API key when neither workspace nor Firebase are available', async () => {
authStateCallback(null)
mockApiKeyGetAuthHeader.mockReturnValue({ 'X-API-KEY': 'test-key' })
const header = await store.getAuthHeader()
expect(header).toEqual({ 'X-API-KEY': 'test-key' })
})
it('returns null when no auth method is available', async () => {
authStateCallback(null)
const header = await store.getAuthHeader()
expect(header).toBeNull()
})
it('skips workspace header when team_workspaces feature is disabled', async () => {
mockFeatureFlags.teamWorkspacesEnabled = false
mockWorkspaceAuthHeader.mockReturnValue({
Authorization: 'Bearer workspace-token'
})
const header = await store.getAuthHeader()
expect(header).toEqual({
Authorization: 'Bearer firebase-token'
})
})
})
describe('getAuthToken priority', () => {
it('returns workspace token when workspace is active and feature enabled', async () => {
mockFeatureFlags.teamWorkspacesEnabled = true
mockGetWorkspaceToken.mockReturnValue('workspace-raw-token')
const token = await store.getAuthToken()
expect(token).toBe('workspace-raw-token')
})
it('returns Firebase token when workspace token is not available', async () => {
mockFeatureFlags.teamWorkspacesEnabled = true
mockGetWorkspaceToken.mockReturnValue(undefined)
const token = await store.getAuthToken()
expect(token).toBe('firebase-token')
})
})
})

View File

@@ -22,10 +22,10 @@ import { useFirebaseAuth } from 'vuefire'
import { getComfyApiBaseUrl } from '@/config/comfyApi'
import { t } from '@/i18n'
import { WORKSPACE_STORAGE_KEYS } from '@/platform/workspace/workspaceConstants'
import { isCloud } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import { useDialogService } from '@/services/dialogService'
import { useWorkspaceAuthStore } from '@/platform/workspace/stores/workspaceAuthStore'
import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore'
import type { AuthHeader } from '@/types/authTypes'
import type { operations } from '@/types/comfyRegistryTypes'
@@ -110,15 +110,7 @@ export const useAuthStore = defineStore('auth', () => {
isInitialized.value = true
if (user === null) {
lastTokenUserId.value = null
// Clear workspace sessionStorage on logout to prevent stale tokens
try {
sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE)
sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.TOKEN)
sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT)
} catch {
// Ignore sessionStorage errors (e.g., in private browsing mode)
}
useWorkspaceAuthStore().clearWorkspaceContext()
}
// Reset balance when auth state changes
@@ -175,21 +167,8 @@ export const useAuthStore = defineStore('auth', () => {
*/
const getAuthHeader = async (): Promise<AuthHeader | null> => {
if (flags.teamWorkspacesEnabled) {
const workspaceToken = sessionStorage.getItem(
WORKSPACE_STORAGE_KEYS.TOKEN
)
const expiresAt = sessionStorage.getItem(
WORKSPACE_STORAGE_KEYS.EXPIRES_AT
)
if (workspaceToken && expiresAt) {
const expiryTime = parseInt(expiresAt, 10)
if (Date.now() < expiryTime) {
return {
Authorization: `Bearer ${workspaceToken}`
}
}
}
const wsHeader = useWorkspaceAuthStore().getWorkspaceAuthHeader()
if (wsHeader) return wsHeader
}
const token = await getIdToken()
@@ -218,19 +197,8 @@ export const useAuthStore = defineStore('auth', () => {
*/
const getAuthToken = async (): Promise<string | undefined> => {
if (flags.teamWorkspacesEnabled) {
const workspaceToken = sessionStorage.getItem(
WORKSPACE_STORAGE_KEYS.TOKEN
)
const expiresAt = sessionStorage.getItem(
WORKSPACE_STORAGE_KEYS.EXPIRES_AT
)
if (workspaceToken && expiresAt) {
const expiryTime = parseInt(expiresAt, 10)
if (Date.now() < expiryTime) {
return workspaceToken
}
}
const wsToken = useWorkspaceAuthStore().getWorkspaceToken()
if (wsToken) return wsToken
}
return await getIdToken()

View File

@@ -21,6 +21,7 @@
"verbatimModuleSyntax": true,
"paths": {
"@/*": ["./src/*"],
"@e2e/*": ["./browser_tests/*"],
"@/utils/formatUtil": [
"./packages/shared-frontend-utils/src/formatUtil.ts"
],