Compare commits

..

3 Commits

Author SHA1 Message Date
bymyself
2daa21f81b refactor: reconcile workspaceAuthStore with authStore
- Delegate workspace token reads from authStore to workspaceAuthStore
- getAuthHeader(): use workspaceAuthStore.getWorkspaceAuthHeader() instead of sessionStorage
- getAuthToken(): use workspaceAuthStore.getWorkspaceToken() instead of sessionStorage
- onAuthStateChanged logout: use workspaceAuthStore.clearWorkspaceContext()
- Add getWorkspaceToken() to workspaceAuthStore
- Remove WORKSPACE_STORAGE_KEYS import from authStore
- Add authTokenPriority.test.ts with 7 priority chain scenarios
2026-03-24 16:33:55 -07:00
bymyself
bbdf20d68b 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-24 16:30:22 -07:00
bymyself
ed7ceab571 refactor: rename firebaseAuthStore to authStore with shared test fixtures
- Rename src/stores/firebaseAuthStore.ts → src/stores/authStore.ts
- Rename src/composables/auth/useFirebaseAuthActions.ts → src/composables/auth/useAuthActions.ts
- Rename exports: useFirebaseAuthStore → useAuthStore, FirebaseAuthStoreError → AuthStoreError
- Update store ID from 'firebaseAuth' to 'auth'
- Create shared mock factory at src/stores/__tests__/authStoreMock.ts
- Update 27 production import sites and 16 test files

Fixes #8219
2026-03-24 16:25:39 -07:00
78 changed files with 646 additions and 2430 deletions

View File

@@ -1,2 +0,0 @@
dist/
.astro/

View File

@@ -1,24 +0,0 @@
import { defineConfig } from 'astro/config'
import vue from '@astrojs/vue'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
site: 'https://comfy.org',
output: 'static',
integrations: [vue()],
vite: {
plugins: [tailwindcss()]
},
build: {
assetsPrefix: process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: undefined
},
i18n: {
locales: ['en', 'zh-CN'],
defaultLocale: 'en',
routing: {
prefixDefaultLocale: false
}
}
})

View File

@@ -1,80 +0,0 @@
{
"name": "@comfyorg/website",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"dependencies": {
"@comfyorg/design-system": "workspace:*",
"@vercel/analytics": "catalog:",
"vue": "catalog:"
},
"devDependencies": {
"@astrojs/vue": "catalog:",
"@tailwindcss/vite": "catalog:",
"astro": "catalog:",
"tailwindcss": "catalog:",
"typescript": "catalog:"
},
"nx": {
"tags": [
"scope:website",
"type:app"
],
"targets": {
"dev": {
"executor": "nx:run-commands",
"continuous": true,
"options": {
"cwd": "apps/website",
"command": "astro dev"
}
},
"serve": {
"executor": "nx:run-commands",
"continuous": true,
"options": {
"cwd": "apps/website",
"command": "astro dev"
}
},
"build": {
"executor": "nx:run-commands",
"cache": true,
"dependsOn": [
"^build"
],
"options": {
"cwd": "apps/website",
"command": "astro build"
},
"outputs": [
"{projectRoot}/dist"
]
},
"preview": {
"executor": "nx:run-commands",
"continuous": true,
"dependsOn": [
"build"
],
"options": {
"cwd": "apps/website",
"command": "astro preview"
}
},
"typecheck": {
"executor": "nx:run-commands",
"cache": true,
"options": {
"cwd": "apps/website",
"command": "astro check"
}
}
}
}
}

View File

@@ -1,139 +0,0 @@
<script setup lang="ts">
const columns = [
{
title: 'Product',
links: [
{ label: 'Comfy Desktop', href: '/download' },
{ label: 'Comfy Cloud', href: 'https://app.comfy.org' },
{ label: 'ComfyHub', href: 'https://hub.comfy.org' },
{ label: 'Pricing', href: '/pricing' }
]
},
{
title: 'Resources',
links: [
{ label: 'Documentation', href: 'https://docs.comfy.org' },
{ label: 'Blog', href: 'https://blog.comfy.org' },
{ label: 'Gallery', href: '/gallery' },
{ label: 'GitHub', href: 'https://github.com/comfyanonymous/ComfyUI' }
]
},
{
title: 'Company',
links: [
{ label: 'About', href: '/about' },
{ label: 'Careers', href: '/careers' },
{ label: 'Enterprise', href: '/enterprise' }
]
},
{
title: 'Legal',
links: [
{ label: 'Terms of Service', href: '/terms-of-service' },
{ label: 'Privacy Policy', href: '/privacy-policy' }
]
}
]
const socials = [
{
label: 'GitHub',
href: 'https://github.com/comfyanonymous/ComfyUI',
icon: 'M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2Z'
},
{
label: 'Discord',
href: 'https://discord.gg/comfyorg',
icon: 'M20.317 4.492c-1.53-.69-3.17-1.2-4.885-1.49a.075.075 0 0 0-.079.036c-.21.369-.444.85-.608 1.23a18.566 18.566 0 0 0-5.487 0 12.36 12.36 0 0 0-.617-1.23A.077.077 0 0 0 8.562 3c-1.714.29-3.354.8-4.885 1.491a.07.07 0 0 0-.032.027C.533 9.093-.32 13.555.099 17.961a.08.08 0 0 0 .031.055 20.03 20.03 0 0 0 5.993 2.98.078.078 0 0 0 .084-.026c.462-.62.874-1.275 1.226-1.963.021-.04.001-.088-.041-.104a13.201 13.201 0 0 1-1.872-.878.075.075 0 0 1-.008-.125c.126-.093.252-.19.372-.287a.075.075 0 0 1 .078-.01c3.927 1.764 8.18 1.764 12.061 0a.075.075 0 0 1 .079.009c.12.098.245.195.372.288a.075.075 0 0 1-.006.125c-.598.344-1.22.635-1.873.877a.075.075 0 0 0-.041.105c.36.687.772 1.341 1.225 1.962a.077.077 0 0 0 .084.028 19.963 19.963 0 0 0 6.002-2.981.076.076 0 0 0 .032-.054c.5-5.094-.838-9.52-3.549-13.442a.06.06 0 0 0-.031-.028ZM8.02 15.278c-1.182 0-2.157-1.069-2.157-2.38 0-1.312.956-2.38 2.157-2.38 1.21 0 2.176 1.077 2.157 2.38 0 1.312-.956 2.38-2.157 2.38Zm7.975 0c-1.183 0-2.157-1.069-2.157-2.38 0-1.312.955-2.38 2.157-2.38 1.21 0 2.176 1.077 2.157 2.38 0 1.312-.946 2.38-2.157 2.38Z'
},
{
label: 'X',
href: 'https://x.com/comaboratory',
icon: 'M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z'
},
{
label: 'Reddit',
href: 'https://reddit.com/r/comfyui',
icon: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2Zm5.8 11.33c.02.16.03.33.03.5 0 2.55-2.97 4.63-6.63 4.63-3.65 0-6.62-2.07-6.62-4.63 0-.17.01-.34.03-.5a1.58 1.58 0 0 1-.63-1.27c0-.88.72-1.59 1.6-1.59.44 0 .83.18 1.12.46 1.1-.79 2.62-1.3 4.31-1.37l.73-3.44a.32.32 0 0 1 .39-.24l2.43.52a1.13 1.13 0 0 1 2.15.36 1.13 1.13 0 0 1-1.13 1.12 1.13 1.13 0 0 1-1.08-.82l-2.16-.46-.65 3.07c1.65.09 3.14.59 4.22 1.36.29-.28.69-.46 1.13-.46.88 0 1.6.71 1.6 1.59 0 .52-.25.97-.63 1.27ZM9.5 13.5c0 .63.51 1.13 1.13 1.13s1.12-.5 1.12-1.13-.5-1.12-1.12-1.12-1.13.5-1.13 1.12Zm5.75 2.55c-.69.69-2 .73-3.25.73s-2.56-.04-3.25-.73a.32.32 0 1 1 .45-.45c.44.44 1.37.6 2.8.6 1.43 0 2.37-.16 2.8-.6a.32.32 0 1 1 .45.45Zm-.37-1.42c.62 0 1.13-.5 1.13-1.13 0-.62-.51-1.12-1.13-1.12-.63 0-1.13.5-1.13 1.12 0 .63.5 1.13 1.13 1.13Z'
},
{
label: 'LinkedIn',
href: 'https://linkedin.com/company/comfyorg',
icon: 'M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286ZM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065Zm1.782 13.019H3.555V9h3.564v11.452ZM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003Z'
},
{
label: 'Instagram',
href: 'https://instagram.com/comfyorg',
icon: 'M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069ZM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0Zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324ZM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8Zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881Z'
}
]
</script>
<template>
<footer class="border-t border-white/10 bg-black">
<div
class="mx-auto grid max-w-7xl gap-8 px-6 py-16 sm:grid-cols-2 lg:grid-cols-5"
>
<!-- Brand -->
<div class="lg:col-span-1">
<a href="/" class="text-2xl font-bold italic text-brand-yellow">
Comfy
</a>
<p class="mt-4 text-sm text-smoke-700">
Professional control of visual AI.
</p>
</div>
<!-- Link columns -->
<nav
v-for="column in columns"
:key="column.title"
:aria-label="column.title"
class="flex flex-col gap-3"
>
<h3 class="text-sm font-semibold text-white">{{ column.title }}</h3>
<a
v-for="link in column.links"
:key="link.href"
:href="link.href"
class="text-sm text-smoke-700 transition-colors hover:text-white"
>
{{ link.label }}
</a>
</nav>
</div>
<!-- Bottom bar -->
<div class="border-t border-white/10">
<div
class="mx-auto flex max-w-7xl flex-col items-center justify-between gap-4 px-6 py-6 sm:flex-row"
>
<p class="text-sm text-smoke-700">
&copy; {{ new Date().getFullYear() }} Comfy Org. All rights reserved.
</p>
<!-- Social icons -->
<div class="flex items-center gap-4">
<a
v-for="social in socials"
:key="social.label"
:href="social.href"
:aria-label="social.label"
target="_blank"
rel="noopener noreferrer"
class="text-smoke-700 transition-colors hover:text-white"
>
<svg
class="h-5 w-5"
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
>
<path :d="social.icon" />
</svg>
</a>
</div>
</div>
</div>
</footer>
</template>

View File

@@ -1,127 +0,0 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
const mobileMenuOpen = ref(false)
const navLinks = [
{ label: 'ENTERPRISE', href: '/enterprise' },
{ label: 'GALLERY', href: '/gallery' },
{ label: 'ABOUT', href: '/about' },
{ label: 'CAREERS', href: '/careers' }
]
function onKeydown(e: KeyboardEvent) {
if (e.key === 'Escape' && mobileMenuOpen.value) {
mobileMenuOpen.value = false
}
}
onMounted(() => {
document.addEventListener('keydown', onKeydown)
document.addEventListener('astro:after-swap', () => {
mobileMenuOpen.value = false
})
})
onUnmounted(() => {
document.removeEventListener('keydown', onKeydown)
})
</script>
<template>
<nav
class="fixed top-0 left-0 right-0 z-50 bg-black/80 backdrop-blur-md"
aria-label="Main navigation"
>
<div class="mx-auto flex max-w-7xl items-center justify-between px-6 py-4">
<!-- Logo -->
<a href="/" class="text-2xl font-bold italic text-brand-yellow">
Comfy
</a>
<!-- Desktop nav links -->
<div class="hidden items-center gap-8 md:flex">
<a
v-for="link in navLinks"
:key="link.href"
:href="link.href"
class="text-sm font-medium tracking-wide text-white transition-colors hover:text-brand-yellow"
>
{{ link.label }}
</a>
<!-- CTA buttons -->
<div class="flex items-center gap-3">
<a
href="https://app.comfy.org"
class="rounded-full bg-brand-yellow px-5 py-2 text-sm font-semibold text-black transition-opacity hover:opacity-90"
>
COMFY CLOUD
</a>
<a
href="https://hub.comfy.org"
class="rounded-full border border-brand-yellow px-5 py-2 text-sm font-semibold text-brand-yellow transition-colors hover:bg-brand-yellow hover:text-black"
>
COMFY HUB
</a>
</div>
</div>
<!-- Mobile hamburger -->
<button
class="flex flex-col gap-1.5 md:hidden"
aria-label="Toggle menu"
aria-controls="site-mobile-menu"
:aria-expanded="mobileMenuOpen"
@click="mobileMenuOpen = !mobileMenuOpen"
>
<span
class="block h-0.5 w-6 bg-white transition-transform"
:class="mobileMenuOpen && 'translate-y-2 rotate-45'"
/>
<span
class="block h-0.5 w-6 bg-white transition-opacity"
:class="mobileMenuOpen && 'opacity-0'"
/>
<span
class="block h-0.5 w-6 bg-white transition-transform"
:class="mobileMenuOpen && '-translate-y-2 -rotate-45'"
/>
</button>
</div>
<!-- Mobile menu -->
<div
v-show="mobileMenuOpen"
id="site-mobile-menu"
class="border-t border-white/10 bg-black px-6 pb-6 md:hidden"
>
<div class="flex flex-col gap-4 pt-4">
<a
v-for="link in navLinks"
:key="link.href"
:href="link.href"
class="text-sm font-medium tracking-wide text-white transition-colors hover:text-brand-yellow"
@click="mobileMenuOpen = false"
>
{{ link.label }}
</a>
<div class="flex flex-col gap-3 pt-2">
<a
href="https://app.comfy.org"
class="rounded-full bg-brand-yellow px-5 py-2 text-center text-sm font-semibold text-black transition-opacity hover:opacity-90"
>
COMFY CLOUD
</a>
<a
href="https://hub.comfy.org"
class="rounded-full border border-brand-yellow px-5 py-2 text-center text-sm font-semibold text-brand-yellow transition-colors hover:bg-brand-yellow hover:text-black"
>
COMFY HUB
</a>
</div>
</div>
</div>
</nav>
</template>

View File

@@ -1 +0,0 @@
/// <reference types="astro/client" />

View File

@@ -1,81 +0,0 @@
---
import { ClientRouter } from 'astro:transitions'
import Analytics from '@vercel/analytics/astro'
import '../styles/global.css'
interface Props {
title: string
description?: string
ogImage?: string
}
const {
title,
description = 'Comfy is the AI creation engine for visual professionals who demand control.',
ogImage = '/og-default.png',
} = Astro.props
const siteBase = Astro.site ?? 'https://comfy.org'
const canonicalURL = new URL(Astro.url.pathname, siteBase)
const ogImageURL = new URL(ogImage, siteBase)
const locale = Astro.currentLocale ?? 'en'
---
<!doctype html>
<html lang={locale}>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content={description} />
<title>{title}</title>
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="canonical" href={canonicalURL.href} />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImageURL.href} />
<meta property="og:url" content={canonicalURL.href} />
<meta property="og:locale" content={locale} />
<meta property="og:site_name" content="Comfy" />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={ogImageURL.href} />
<!-- Google Tag Manager -->
<script is:inline>
;(function (w, d, s, l, i) {
w[l] = w[l] || []
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' })
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : ''
j.async = true
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl
f.parentNode.insertBefore(j, f)
})(window, document, 'script', 'dataLayer', 'GTM-NP9JM6K7')
</script>
<ClientRouter />
</head>
<body class="bg-black text-white font-inter antialiased">
<!-- Google Tag Manager (noscript) -->
<noscript>
<iframe
src="https://www.googletagmanager.com/ns.html?id=GTM-NP9JM6K7"
height="0"
width="0"
style="display:none;visibility:hidden"
></iframe>
</noscript>
<slot />
<Analytics />
</body>
</html>

View File

@@ -1,2 +0,0 @@
@import 'tailwindcss';
@import '@comfyorg/design-system/css/base.css';

View File

@@ -1,9 +0,0 @@
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*", "astro.config.mjs"]
}

View File

@@ -27,17 +27,6 @@ const config: KnipConfig = {
},
'packages/ingest-types': {
project: ['src/**/*.{js,ts}']
},
'apps/website': {
entry: [
'src/pages/**/*.astro',
'src/layouts/**/*.astro',
'src/components/**/*.vue',
'src/styles/global.css',
'astro.config.ts'
],
project: ['src/**/*.{astro,vue,ts}', '*.{js,ts,mjs}'],
ignoreDependencies: ['@comfyorg/design-system', '@vercel/analytics']
}
},
ignoreBinaries: ['python3'],

View File

@@ -1,46 +0,0 @@
/*
* Design System Base — Brand tokens + fonts only.
* For marketing sites that don't use PrimeVue or the node editor.
* Import the full style.css instead for the desktop app.
*/
@import './fonts.css';
@theme {
/* Font Families */
--font-inter: 'Inter', sans-serif;
/* Palette Colors */
--color-charcoal-100: #55565e;
--color-charcoal-200: #494a50;
--color-charcoal-300: #3c3d42;
--color-charcoal-400: #313235;
--color-charcoal-500: #2d2e32;
--color-charcoal-600: #262729;
--color-charcoal-700: #202121;
--color-charcoal-800: #171718;
--color-neutral-550: #636363;
--color-ash-300: #bbbbbb;
--color-ash-500: #828282;
--color-ash-800: #444444;
--color-smoke-100: #f3f3f3;
--color-smoke-200: #e9e9e9;
--color-smoke-300: #e1e1e1;
--color-smoke-400: #d9d9d9;
--color-smoke-500: #c5c5c5;
--color-smoke-600: #b4b4b4;
--color-smoke-700: #a0a0a0;
--color-smoke-800: #8a8a8a;
--color-white: #ffffff;
--color-black: #000000;
/* Brand Colors */
--color-electric-400: #f0ff41;
--color-sapphire-700: #172dd7;
--color-brand-yellow: var(--color-electric-400);
--color-brand-blue: var(--color-sapphire-700);
}

1665
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@ packages:
catalog:
'@alloc/quick-lru': ^5.2.0
'@astrojs/vue': ^5.0.0
'@comfyorg/comfyui-electron-types': 0.6.2
'@eslint/js': ^9.39.1
'@formkit/auto-animate': ^0.9.0
@@ -51,7 +50,6 @@ catalog:
'@types/node': ^24.1.0
'@types/semver': ^7.7.0
'@types/three': ^0.169.0
'@vercel/analytics': ^2.0.1
'@vitejs/plugin-vue': ^6.0.0
'@vitest/coverage-v8': ^4.0.16
'@vitest/ui': ^4.0.16
@@ -60,7 +58,6 @@ catalog:
'@vueuse/integrations': ^14.2.0
'@webgpu/types': ^0.1.66
algoliasearch: ^5.21.0
astro: ^5.10.0
axios: ^1.13.5
cross-env: ^10.1.0
cva: 1.0.0-beta.4

View File

@@ -71,8 +71,8 @@ vi.mock('@/workbench/extensions/manager/composables/useManagerState', () => ({
})
}))
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => ({
currentUser: null,
loading: false
}))

View File

@@ -32,8 +32,8 @@ const mockBalance = vi.hoisted(() => ({
const mockIsFetchingBalance = vi.hoisted(() => ({ value: false }))
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => ({
balance: mockBalance.value,
isFetchingBalance: mockIsFetchingBalance.value
}))

View File

@@ -30,14 +30,14 @@ import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { formatCreditsFromCents } from '@/base/credits/comfyCredits'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
const { textClass, showCreditsOnly } = defineProps<{
textClass?: string
showCreditsOnly?: boolean
}>()
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
const balanceLoading = computed(() => authStore.isFetchingBalance)
const { t, locale } = useI18n()

View File

@@ -147,7 +147,7 @@ import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { getComfyPlatformBaseUrl } from '@/config/comfyApi'
import {
configValueOrDefault,
@@ -167,7 +167,7 @@ const { onSuccess } = defineProps<{
}>()
const { t } = useI18n()
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const isSecureContext = window.isSecureContext
const isSignIn = ref(true)
const showApiKeyForm = ref(false)

View File

@@ -156,7 +156,7 @@ import { useI18n } from 'vue-i18n'
import { creditsToUsd, usdToCredits } from '@/base/credits/comfyCredits'
import Button from '@/components/ui/button/Button.vue'
import FormattedNumberStepper from '@/components/ui/stepper/FormattedNumberStepper.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { useExternalLink } from '@/composables/useExternalLink'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
@@ -171,7 +171,7 @@ const { isInsufficientCredits = false } = defineProps<{
}>()
const { t } = useI18n()
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const dialogStore = useDialogStore()
const settingsDialog = useSettingsDialog()
const telemetry = useTelemetry()

View File

@@ -21,10 +21,10 @@ import { ref } from 'vue'
import PasswordFields from '@/components/dialog/content/signin/PasswordFields.vue'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { updatePasswordSchema } from '@/schemas/signInSchema'
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const loading = ref(false)
const { onSuccess } = defineProps<{

View File

@@ -116,12 +116,12 @@ import UserCredit from '@/components/common/UserCredit.vue'
import UsageLogsTable from '@/components/dialog/content/setting/UsageLogsTable.vue'
import Button from '@/components/ui/button/Button.vue'
import { useBillingContext } from '@/composables/billing/useBillingContext'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { useExternalLink } from '@/composables/useExternalLink'
import { useTelemetry } from '@/platform/telemetry'
import { useDialogService } from '@/services/dialogService'
import { useCommandStore } from '@/stores/commandStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import { formatMetronomeCurrency } from '@/utils/formatUtil'
interface CreditHistoryItemData {
@@ -133,8 +133,8 @@ interface CreditHistoryItemData {
const { buildDocsUrl, docsPaths } = useExternalLink()
const dialogService = useDialogService()
const authStore = useFirebaseAuthStore()
const authActions = useFirebaseAuthActions()
const authStore = useAuthStore()
const authActions = useAuthActions()
const commandStore = useCommandStore()
const telemetry = useTelemetry()
const { isActiveSubscription } = useBillingContext()

View File

@@ -18,8 +18,8 @@ import ApiKeyForm from './ApiKeyForm.vue'
const mockStoreApiKey = vi.fn()
const mockLoading = vi.fn(() => false)
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => ({
loading: mockLoading()
}))
}))

View File

@@ -100,9 +100,9 @@ import {
} from '@/platform/remoteConfig/remoteConfig'
import { apiKeySchema } from '@/schemas/signInSchema'
import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
const apiKeyStore = useApiKeyAuthStore()
const loading = computed(() => authStore.loading)
const comfyPlatformBaseUrl = computed(() =>

View File

@@ -35,15 +35,15 @@ vi.mock('firebase/auth', () => ({
// Mock the auth composables and stores
const mockSendPasswordReset = vi.fn()
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
useFirebaseAuthActions: vi.fn(() => ({
vi.mock('@/composables/auth/useAuthActions', () => ({
useAuthActions: vi.fn(() => ({
sendPasswordReset: mockSendPasswordReset
}))
}))
let mockLoading = false
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => ({
get loading() {
return mockLoading
}

View File

@@ -88,14 +88,14 @@ import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { signInSchema } from '@/schemas/signInSchema'
import type { SignInData } from '@/schemas/signInSchema'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import { cn } from '@/utils/tailwindUtil'
const authStore = useFirebaseAuthStore()
const firebaseAuthActions = useFirebaseAuthActions()
const authStore = useAuthStore()
const firebaseAuthActions = useAuthActions()
const loading = computed(() => authStore.loading)
const toast = useToast()

View File

@@ -54,12 +54,12 @@ import { useI18n } from 'vue-i18n'
import Button from '@/components/ui/button/Button.vue'
import { signUpSchema } from '@/schemas/signInSchema'
import type { SignUpData } from '@/schemas/signInSchema'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import PasswordFields from './PasswordFields.vue'
const { t } = useI18n()
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
const loading = computed(() => authStore.loading)
const emit = defineEmits<{

View File

@@ -61,10 +61,10 @@ vi.mock('@/composables/auth/useCurrentUser', () => ({
}))
}))
// Mock the useFirebaseAuthActions composable
// Mock the useAuthActions composable
const mockLogout = vi.fn()
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
useFirebaseAuthActions: vi.fn(() => ({
vi.mock('@/composables/auth/useAuthActions', () => ({
useAuthActions: vi.fn(() => ({
fetchBalance: vi.fn().mockResolvedValue(undefined),
logout: mockLogout
}))
@@ -77,7 +77,7 @@ vi.mock('@/services/dialogService', () => ({
}))
}))
// Mock the firebaseAuthStore with hoisted state for per-test manipulation
// Mock the authStore with hoisted state for per-test manipulation
const mockAuthStoreState = vi.hoisted(() => ({
balance: {
amount_micros: 100_000,
@@ -91,8 +91,8 @@ const mockAuthStoreState = vi.hoisted(() => ({
isFetchingBalance: false
}))
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => ({
getAuthHeader: vi
.fn()
.mockResolvedValue({ Authorization: 'Bearer mock-token' }),

View File

@@ -159,7 +159,7 @@ import { formatCreditsFromCents } from '@/base/credits/comfyCredits'
import UserAvatar from '@/components/common/UserAvatar.vue'
import Button from '@/components/ui/button/Button.vue'
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { useExternalLink } from '@/composables/useExternalLink'
import SubscribeButton from '@/platform/cloud/subscription/components/SubscribeButton.vue'
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
@@ -168,7 +168,7 @@ import { isCloud } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog'
import { useDialogService } from '@/services/dialogService'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
const emit = defineEmits<{
close: []
@@ -178,8 +178,8 @@ const { buildDocsUrl, docsPaths } = useExternalLink()
const { userDisplayName, userEmail, userPhotoUrl, handleSignOut } =
useCurrentUser()
const authActions = useFirebaseAuthActions()
const authStore = useFirebaseAuthStore()
const authActions = useAuthActions()
const authStore = useAuthStore()
const settingsDialog = useSettingsDialog()
const dialogService = useDialogService()
const {

View File

@@ -11,8 +11,8 @@ import { useTelemetry } from '@/platform/telemetry'
import { useToastStore } from '@/platform/updates/common/toastStore'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import { useDialogService } from '@/services/dialogService'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import type { BillingPortalTargetTier } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import type { BillingPortalTargetTier } from '@/stores/authStore'
import { usdToMicros } from '@/utils/formatUtil'
/**
@@ -20,8 +20,8 @@ import { usdToMicros } from '@/utils/formatUtil'
* All actions are wrapped with error handling.
* @returns {Object} - Object containing all Firebase Auth actions
*/
export const useFirebaseAuthActions = () => {
const authStore = useFirebaseAuthStore()
export const useAuthActions = () => {
const authStore = useAuthStore()
const toastStore = useToastStore()
const { wrapWithErrorHandlingAsync, toastErrorHandler } = useErrorHandling()

View File

@@ -3,11 +3,11 @@ import { computed, watch } from 'vue'
import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore'
import { useCommandStore } from '@/stores/commandStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import type { AuthUserInfo } from '@/types/authTypes'
export const useCurrentUser = () => {
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
const commandStore = useCommandStore()
const apiKeyStore = useApiKeyAuthStore()

View File

@@ -70,8 +70,8 @@ vi.mock(
})
)
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: () => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: () => ({
balance: { amount_micros: 5000000 },
fetchBalance: vi.fn().mockResolvedValue({ amount_micros: 5000000 })
})

View File

@@ -5,7 +5,7 @@ import type {
PreviewSubscribeResponse,
SubscribeResponse
} from '@/platform/workspace/api/workspaceApi'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import type {
BalanceInfo,
@@ -33,7 +33,7 @@ export function useLegacyBilling(): BillingState & BillingActions {
showSubscriptionDialog: legacyShowSubscriptionDialog
} = useSubscription()
const firebaseAuthStore = useFirebaseAuthStore()
const firebaseAuthStore = useAuthStore()
const isInitialized = ref(false)
const isLoading = ref(false)

View File

@@ -56,8 +56,8 @@ vi.mock('@/scripts/api', () => ({
vi.mock('@/platform/settings/settingStore')
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => ({}))
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => ({}))
}))
vi.mock('@/composables/auth/useFirebaseAuth', () => ({
@@ -123,8 +123,8 @@ vi.mock('@/stores/workspace/colorPaletteStore', () => ({
useColorPaletteStore: vi.fn(() => ({}))
}))
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
useFirebaseAuthActions: vi.fn(() => ({}))
vi.mock('@/composables/auth/useAuthActions', () => ({
useAuthActions: vi.fn(() => ({}))
}))
vi.mock('@/platform/cloud/subscription/composables/useSubscription', () => ({

View File

@@ -1,5 +1,5 @@
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { useSelectedLiteGraphItems } from '@/composables/canvas/useSelectedLiteGraphItems'
import { useSubgraphOperations } from '@/composables/graph/useSubgraphOperations'
import { useExternalLink } from '@/composables/useExternalLink'
@@ -78,7 +78,7 @@ export function useCoreCommands(): ComfyCommand[] {
const settingsDialog = useSettingsDialog()
const dialogService = useDialogService()
const colorPaletteStore = useColorPaletteStore()
const firebaseAuthActions = useFirebaseAuthActions()
const firebaseAuthActions = useAuthActions()
const toastStore = useToastStore()
const canvasStore = useCanvasStore()
const executionStore = useExecutionStore()

View File

@@ -1,7 +1,7 @@
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import { isCloud } from '@/platform/distribution/types'
import { api } from '@/scripts/api'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
/**
* Session cookie management for cloud authentication.
@@ -21,7 +21,7 @@ export const useSessionCookie = () => {
const { flags } = useFeatureFlags()
try {
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
let authHeader: Record<string, string>

View File

@@ -74,7 +74,7 @@ import { ref } from 'vue'
import { useRouter } from 'vue-router'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
interface Props {
errorMessage?: string
@@ -83,7 +83,7 @@ interface Props {
defineProps<Props>()
const router = useRouter()
const { logout } = useFirebaseAuthActions()
const { logout } = useAuthActions()
const showTechnicalDetails = ref(false)
const handleRestart = async () => {

View File

@@ -76,11 +76,11 @@ import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
const { t } = useI18n()
const router = useRouter()
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const email = ref('')
const loading = ref(false)

View File

@@ -110,7 +110,7 @@ import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import CloudSignInForm from '@/platform/cloud/onboarding/components/CloudSignInForm.vue'
import { useFreeTierOnboarding } from '@/platform/cloud/onboarding/composables/useFreeTierOnboarding'
import { getSafePreviousFullPath } from '@/platform/cloud/onboarding/utils/previousFullPath'
@@ -120,7 +120,7 @@ import type { SignInData } from '@/schemas/signInSchema'
const { t } = useI18n()
const router = useRouter()
const route = useRoute()
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const isSecureContext = globalThis.isSecureContext
const authError = ref('')
const toastStore = useToastStore()

View File

@@ -133,7 +133,7 @@ import { useRoute, useRouter } from 'vue-router'
import SignUpForm from '@/components/dialog/content/signin/SignUpForm.vue'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { useFreeTierOnboarding } from '@/platform/cloud/onboarding/composables/useFreeTierOnboarding'
import { getSafePreviousFullPath } from '@/platform/cloud/onboarding/utils/previousFullPath'
import { isCloud } from '@/platform/distribution/types'
@@ -145,7 +145,7 @@ import { isInChina } from '@/utils/networkUtil'
const { t } = useI18n()
const router = useRouter()
const route = useRoute()
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const isSecureContext = globalThis.isSecureContext
const authError = ref('')
const userIsInChina = ref(false)

View File

@@ -25,8 +25,8 @@ const authActionMocks = vi.hoisted(() => ({
accessBillingPortal: vi.fn()
}))
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
useFirebaseAuthActions: () => authActionMocks
vi.mock('@/composables/auth/useAuthActions', () => ({
useAuthActions: () => authActionMocks
}))
vi.mock('@/composables/useErrorHandling', () => ({

View File

@@ -6,7 +6,7 @@ import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import { useBillingContext } from '@/composables/billing/useBillingContext'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { useErrorHandling } from '@/composables/useErrorHandling'
import type { TierKey } from '@/platform/cloud/subscription/constants/tierPricing'
import { performSubscriptionCheckout } from '@/platform/cloud/subscription/utils/subscriptionCheckoutUtil'
@@ -16,7 +16,7 @@ import type { BillingCycle } from '../subscription/utils/subscriptionTierRank'
const { t } = useI18n()
const route = useRoute()
const router = useRouter()
const { reportError, accessBillingPortal } = useFirebaseAuthActions()
const { reportError, accessBillingPortal } = useAuthActions()
const { wrapWithErrorHandlingAsync } = useErrorHandling()
const { isActiveSubscription, isInitialized, initialize } = useBillingContext()

View File

@@ -89,9 +89,9 @@ import { useI18n } from 'vue-i18n'
import Button from '@/components/ui/button/Button.vue'
import { signInSchema } from '@/schemas/signInSchema'
import type { SignInData } from '@/schemas/signInSchema'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
const loading = computed(() => authStore.loading)
const { t } = useI18n()

View File

@@ -31,8 +31,8 @@ vi.mock('@/platform/cloud/subscription/composables/useSubscription', () => ({
})
}))
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
useFirebaseAuthActions: () => ({
vi.mock('@/composables/auth/useAuthActions', () => ({
useAuthActions: () => ({
accessBillingPortal: mockAccessBillingPortal,
reportError: mockReportError
})
@@ -56,13 +56,13 @@ vi.mock('@/composables/useErrorHandling', () => ({
})
}))
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: () =>
vi.mock('@/stores/authStore', () => ({
useAuthStore: () =>
reactive({
getAuthHeader: mockGetAuthHeader,
userId: computed(() => mockUserId.value)
}),
FirebaseAuthStoreError: class extends Error {}
AuthStoreError: class extends Error {}
}))
vi.mock('@/platform/telemetry', () => ({

View File

@@ -262,7 +262,7 @@ import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
import {
@@ -279,7 +279,7 @@ import type { BillingCycle } from '@/platform/cloud/subscription/utils/subscript
import { isCloud } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import type { CheckoutAttributionMetadata } from '@/platform/telemetry/types'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import type { components } from '@/types/comfyRegistryTypes'
type SubscriptionTier = components['schemas']['SubscriptionTier']
@@ -365,8 +365,8 @@ const {
isYearlySubscription
} = useSubscription()
const telemetry = useTelemetry()
const { userId } = storeToRefs(useFirebaseAuthStore())
const { accessBillingPortal, reportError } = useFirebaseAuthActions()
const { userId } = storeToRefs(useAuthStore())
const { accessBillingPortal, reportError } = useAuthActions()
const { wrapWithErrorHandlingAsync } = useErrorHandling()
const isLoading = ref(false)

View File

@@ -82,8 +82,8 @@ vi.mock(
})
)
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
useFirebaseAuthActions: vi.fn(() => ({
vi.mock('@/composables/auth/useAuthActions', () => ({
useAuthActions: vi.fn(() => ({
authActions: vi.fn(() => ({
accessBillingPortal: vi.fn()
}))

View File

@@ -211,7 +211,7 @@ import { computed, onBeforeUnmount, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import Button from '@/components/ui/button/Button.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import SubscribeButton from '@/platform/cloud/subscription/components/SubscribeButton.vue'
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
import { useSubscriptionActions } from '@/platform/cloud/subscription/composables/useSubscriptionActions'
@@ -227,7 +227,7 @@ import type { TierBenefit } from '@/platform/cloud/subscription/utils/tierBenefi
import { getCommonTierBenefits } from '@/platform/cloud/subscription/utils/tierBenefits'
import { cn } from '@/utils/tailwindUtil'
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const { t, n } = useI18n()
const {

View File

@@ -65,8 +65,8 @@ vi.mock('@/platform/telemetry', () => ({
useTelemetry: vi.fn(() => mockTelemetry)
}))
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
useFirebaseAuthActions: vi.fn(() => ({
vi.mock('@/composables/auth/useAuthActions', () => ({
useAuthActions: vi.fn(() => ({
reportError: mockReportError,
accessBillingPortal: mockAccessBillingPortal
}))
@@ -106,14 +106,14 @@ vi.mock('@/services/dialogService', () => ({
}))
}))
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => ({
getAuthHeader: mockGetAuthHeader,
get userId() {
return mockUserId.value
}
})),
FirebaseAuthStoreError: class extends Error {}
AuthStoreError: class extends Error {}
}))
// Mock fetch

View File

@@ -2,7 +2,7 @@ import { computed, ref, watch } from 'vue'
import { createSharedComposable } from '@vueuse/core'
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { getComfyApiBaseUrl, getComfyPlatformBaseUrl } from '@/config/comfyApi'
import { t } from '@/i18n'
@@ -10,10 +10,7 @@ import { isCloud } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import type { SubscriptionDialogReason } from '@/platform/cloud/subscription/composables/useSubscriptionDialog'
import type { CheckoutAttributionMetadata } from '@/platform/telemetry/types'
import {
FirebaseAuthStoreError,
useFirebaseAuthStore
} from '@/stores/firebaseAuthStore'
import { AuthStoreError, useAuthStore } from '@/stores/authStore'
import { useDialogService } from '@/services/dialogService'
import { TIER_TO_KEY } from '@/platform/cloud/subscription/constants/tierPricing'
import type { operations } from '@/types/comfyRegistryTypes'
@@ -37,10 +34,10 @@ function useSubscriptionInternal() {
return subscriptionStatus.value?.is_active ?? false
})
const { reportError, accessBillingPortal } = useFirebaseAuthActions()
const { reportError, accessBillingPortal } = useAuthActions()
const { showSubscriptionRequiredDialog } = useDialogService()
const firebaseAuthStore = useFirebaseAuthStore()
const firebaseAuthStore = useAuthStore()
const { getAuthHeader } = firebaseAuthStore
const { wrapWithErrorHandlingAsync } = useErrorHandling()
@@ -194,7 +191,7 @@ function useSubscriptionInternal() {
async function fetchSubscriptionStatus(): Promise<CloudSubscriptionStatusResponse | null> {
const authHeader = await getAuthHeader()
if (!authHeader) {
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
const response = await fetch(
@@ -209,7 +206,7 @@ function useSubscriptionInternal() {
if (!response.ok) {
const errorData = await response.json()
throw new FirebaseAuthStoreError(
throw new AuthStoreError(
t('toastMessages.failedToFetchSubscription', {
error: errorData.message
})
@@ -248,9 +245,7 @@ function useSubscriptionInternal() {
async (): Promise<CloudSubscriptionCheckoutResponse> => {
const authHeader = await getAuthHeader()
if (!authHeader) {
throw new FirebaseAuthStoreError(
t('toastMessages.userNotAuthenticated')
)
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
const checkoutAttribution = await getCheckoutAttributionForCloud()
@@ -268,7 +263,7 @@ function useSubscriptionInternal() {
if (!response.ok) {
const errorData = await response.json()
throw new FirebaseAuthStoreError(
throw new AuthStoreError(
t('toastMessages.failedToInitiateSubscription', {
error: errorData.message
})

View File

@@ -8,8 +8,8 @@ const mockFetchStatus = vi.fn()
const mockShowTopUpCreditsDialog = vi.fn()
const mockExecute = vi.fn()
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
useFirebaseAuthActions: () => ({
vi.mock('@/composables/auth/useAuthActions', () => ({
useAuthActions: () => ({
fetchBalance: mockFetchBalance
})
}))

View File

@@ -1,7 +1,7 @@
import { onMounted, ref } from 'vue'
import { useBillingContext } from '@/composables/billing/useBillingContext'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import { isCloud } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import { useDialogService } from '@/services/dialogService'
@@ -12,7 +12,7 @@ import { useCommandStore } from '@/stores/commandStore'
*/
export function useSubscriptionActions() {
const dialogService = useDialogService()
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const commandStore = useCommandStore()
const telemetry = useTelemetry()
const { fetchStatus } = useBillingContext()

View File

@@ -36,14 +36,14 @@ vi.mock('@/platform/telemetry', () => ({
useTelemetry: vi.fn(() => mockTelemetry)
}))
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() =>
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() =>
reactive({
getAuthHeader: mockGetAuthHeader,
userId: computed(() => mockUserId.value)
})
),
FirebaseAuthStoreError: class extends Error {}
AuthStoreError: class extends Error {}
}))
vi.mock('@/platform/distribution/types', () => ({

View File

@@ -4,10 +4,7 @@ import { getComfyApiBaseUrl } from '@/config/comfyApi'
import { t } from '@/i18n'
import { isCloud } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import {
FirebaseAuthStoreError,
useFirebaseAuthStore
} from '@/stores/firebaseAuthStore'
import { AuthStoreError, useAuthStore } from '@/stores/authStore'
import type { CheckoutAttributionMetadata } from '@/platform/telemetry/types'
import type { TierKey } from '@/platform/cloud/subscription/constants/tierPricing'
import type { BillingCycle } from './subscriptionTierRank'
@@ -51,13 +48,13 @@ export async function performSubscriptionCheckout(
): Promise<void> {
if (!isCloud) return
const firebaseAuthStore = useFirebaseAuthStore()
const firebaseAuthStore = useAuthStore()
const { userId } = storeToRefs(firebaseAuthStore)
const telemetry = useTelemetry()
const authHeader = await firebaseAuthStore.getAuthHeader()
if (!authHeader) {
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
const checkoutTier = getCheckoutTier(tierKey, currentBillingCycle)
@@ -97,7 +94,7 @@ export async function performSubscriptionCheckout(
}
}
throw new FirebaseAuthStoreError(
throw new AuthStoreError(
t('toastMessages.failedToInitiateSubscription', {
error: errorMessage
})

View File

@@ -90,7 +90,7 @@ import CurrentUserMessage from '@/components/dialog/content/setting/CurrentUserM
import BaseModalLayout from '@/components/widget/layout/BaseModalLayout.vue'
import NavItem from '@/components/widget/nav/NavItem.vue'
import NavTitle from '@/components/widget/nav/NavTitle.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useAuthActions } from '@/composables/auth/useAuthActions'
import ColorPaletteMessage from '@/platform/settings/components/ColorPaletteMessage.vue'
import SettingsPanel from '@/platform/settings/components/SettingsPanel.vue'
import { useSettingSearch } from '@/platform/settings/composables/useSettingSearch'
@@ -129,7 +129,7 @@ const {
getSearchResults
} = useSettingSearch()
const authActions = useFirebaseAuthActions()
const authActions = useAuthActions()
const navRef = ref<HTMLElement | null>(null)
const activeCategoryKey = ref<string | null>(defaultCategory.value?.key ?? null)

View File

@@ -6,7 +6,7 @@ type MockApiKeyUser = {
email?: string
} | null
type MockFirebaseUser = {
type MockAuthUser = {
uid: string
email?: string | null
} | null
@@ -14,19 +14,19 @@ type MockFirebaseUser = {
const {
mockCaptureCheckoutAttributionFromSearch,
mockUseApiKeyAuthStore,
mockUseFirebaseAuthStore,
mockUseAuthStore,
mockApiKeyAuthStore,
mockFirebaseAuthStore
mockAuthStore
} = vi.hoisted(() => ({
mockCaptureCheckoutAttributionFromSearch: vi.fn(),
mockUseApiKeyAuthStore: vi.fn(),
mockUseFirebaseAuthStore: vi.fn(),
mockUseAuthStore: vi.fn(),
mockApiKeyAuthStore: {
isAuthenticated: false,
currentUser: null as MockApiKeyUser
},
mockFirebaseAuthStore: {
currentUser: null as MockFirebaseUser
mockAuthStore: {
currentUser: null as MockAuthUser
}
}))
@@ -38,8 +38,8 @@ vi.mock('@/stores/apiKeyAuthStore', () => ({
useApiKeyAuthStore: mockUseApiKeyAuthStore
}))
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: mockUseFirebaseAuthStore
vi.mock('@/stores/authStore', () => ({
useAuthStore: mockUseAuthStore
}))
import { ImpactTelemetryProvider } from './ImpactTelemetryProvider'
@@ -64,14 +64,14 @@ describe('ImpactTelemetryProvider', () => {
beforeEach(() => {
mockCaptureCheckoutAttributionFromSearch.mockReset()
mockUseApiKeyAuthStore.mockReset()
mockUseFirebaseAuthStore.mockReset()
mockUseAuthStore.mockReset()
mockApiKeyAuthStore.isAuthenticated = false
mockApiKeyAuthStore.currentUser = null
mockFirebaseAuthStore.currentUser = null
mockAuthStore.currentUser = null
vi.restoreAllMocks()
vi.unstubAllGlobals()
mockUseApiKeyAuthStore.mockReturnValue(mockApiKeyAuthStore)
mockUseFirebaseAuthStore.mockReturnValue(mockFirebaseAuthStore)
mockUseAuthStore.mockReturnValue(mockAuthStore)
const queueFn: NonNullable<Window['ire']> = (...args: unknown[]) => {
;(queueFn.a ??= []).push(args)
@@ -93,7 +93,7 @@ describe('ImpactTelemetryProvider', () => {
})
it('captures attribution and invokes identify with hashed email', async () => {
mockFirebaseAuthStore.currentUser = {
mockAuthStore.currentUser = {
uid: 'user-123',
email: ' User@Example.com '
}
@@ -153,7 +153,7 @@ describe('ImpactTelemetryProvider', () => {
})
it('invokes identify on each page view even with identical identity payloads', async () => {
mockFirebaseAuthStore.currentUser = {
mockAuthStore.currentUser = {
uid: 'user-123',
email: 'user@example.com'
}
@@ -189,7 +189,7 @@ describe('ImpactTelemetryProvider', () => {
id: 'api-key-user-123',
email: 'apikey@example.com'
}
mockFirebaseAuthStore.currentUser = {
mockAuthStore.currentUser = {
uid: 'firebase-user-123',
email: 'firebase@example.com'
}
@@ -228,7 +228,7 @@ describe('ImpactTelemetryProvider', () => {
id: 'api-key-user-123',
email: 'apikey@example.com'
}
mockFirebaseAuthStore.currentUser = null
mockAuthStore.currentUser = null
vi.stubGlobal('crypto', {
subtle: {
digest: vi.fn(

View File

@@ -1,6 +1,6 @@
import { captureCheckoutAttributionFromSearch } from '@/platform/telemetry/utils/checkoutAttribution'
import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import type { PageViewMetadata, TelemetryProvider } from '../../types'
@@ -17,7 +17,7 @@ export class ImpactTelemetryProvider implements TelemetryProvider {
private initialized = false
private stores: {
apiKeyAuthStore: ReturnType<typeof useApiKeyAuthStore>
firebaseAuthStore: ReturnType<typeof useFirebaseAuthStore>
firebaseAuthStore: ReturnType<typeof useAuthStore>
} | null = null
constructor() {
@@ -135,7 +135,7 @@ export class ImpactTelemetryProvider implements TelemetryProvider {
private resolveAuthStores(): {
apiKeyAuthStore: ReturnType<typeof useApiKeyAuthStore>
firebaseAuthStore: ReturnType<typeof useFirebaseAuthStore>
firebaseAuthStore: ReturnType<typeof useAuthStore>
} | null {
if (this.stores) {
return this.stores
@@ -144,7 +144,7 @@ export class ImpactTelemetryProvider implements TelemetryProvider {
try {
const stores = {
apiKeyAuthStore: useApiKeyAuthStore(),
firebaseAuthStore: useFirebaseAuthStore()
firebaseAuthStore: useAuthStore()
}
this.stores = stores
return stores

View File

@@ -1,8 +1,7 @@
import axios from 'axios'
import { t } from '@/i18n'
import { api } from '@/scripts/api'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
export type WorkspaceType = 'personal' | 'team'
export type WorkspaceRole = 'owner' | 'member'
@@ -288,27 +287,11 @@ const workspaceApiClient = axios.create({
})
async function getAuthHeaderOrThrow() {
const authHeader = await useFirebaseAuthStore().getAuthHeader()
if (!authHeader) {
throw new WorkspaceApiError(
t('toastMessages.userNotAuthenticated'),
401,
'NOT_AUTHENTICATED'
)
}
return authHeader
return useAuthStore().getAuthHeaderOrThrow()
}
async function getFirebaseHeaderOrThrow() {
const authHeader = await useFirebaseAuthStore().getFirebaseAuthHeader()
if (!authHeader) {
throw new WorkspaceApiError(
t('toastMessages.userNotAuthenticated'),
401,
'NOT_AUTHENTICATED'
)
}
return authHeader
return useAuthStore().getFirebaseAuthHeaderOrThrow()
}
function handleAxiosError(err: unknown): never {

View File

@@ -8,8 +8,8 @@ import WorkspaceAuthGate from './WorkspaceAuthGate.vue'
const mockIsInitialized = ref(false)
const mockCurrentUser = ref<object | null>(null)
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: () => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: () => ({
isInitialized: mockIsInitialized,
currentUser: mockCurrentUser
})

View File

@@ -27,7 +27,7 @@ import { isCloud } from '@/platform/distribution/types'
import { useSubscriptionDialog } from '@/platform/cloud/subscription/composables/useSubscriptionDialog'
import { refreshRemoteConfig } from '@/platform/remoteConfig/refreshRemoteConfig'
import { useTeamWorkspaceStore } from '@/platform/workspace/stores/teamWorkspaceStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
const FIREBASE_INIT_TIMEOUT_MS = 16_000
const CONFIG_REFRESH_TIMEOUT_MS = 10_000
@@ -38,7 +38,7 @@ const subscriptionDialog = useSubscriptionDialog()
async function initialize(): Promise<void> {
if (!isCloud) return
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
const { isInitialized, currentUser } = storeToRefs(authStore)
try {

View File

@@ -10,8 +10,8 @@ import { WORKSPACE_STORAGE_KEYS } from '@/platform/workspace/workspaceConstants'
const mockGetIdToken = vi.fn()
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: () => ({
vi.mock('@/stores/authStore', () => ({
useAuthStore: () => ({
getIdToken: mockGetIdToken
})
}))

View File

@@ -9,7 +9,7 @@ import {
WORKSPACE_STORAGE_KEYS
} from '@/platform/workspace/workspaceConstants'
import { api } from '@/scripts/api'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import type { AuthHeader } from '@/types/authTypes'
import type { WorkspaceWithRole } from '@/platform/workspace/workspaceTypes'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
@@ -181,7 +181,7 @@ export const useWorkspaceAuthStore = defineStore('workspaceAuth', () => {
error.value = null
try {
const firebaseAuthStore = useFirebaseAuthStore()
const firebaseAuthStore = useAuthStore()
const firebaseToken = await firebaseAuthStore.getIdToken()
if (!firebaseToken) {
throw new WorkspaceAuthError(
@@ -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

@@ -38,9 +38,9 @@ vi.mock('@/platform/distribution/types', () => ({
}
}))
vi.mock('@/stores/firebaseAuthStore', async () => {
vi.mock('@/stores/authStore', async () => {
return {
useFirebaseAuthStore: vi.fn(() => ({
useAuthStore: vi.fn(() => ({
getAuthHeader: vi.fn(() => Promise.resolve(mockCloudAuth.authHeader))
}))
}

View File

@@ -5,7 +5,7 @@ import type { IWidget, LGraphNode } from '@/lib/litegraph/src/litegraph'
import { isCloud } from '@/platform/distribution/types'
import type { RemoteWidgetConfig } from '@/schemas/nodeDefSchema'
import { api } from '@/scripts/api'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
const MAX_RETRIES = 5
const TIMEOUT = 4096
@@ -23,7 +23,7 @@ interface CacheEntry<T> {
async function getAuthHeaders() {
if (isCloud) {
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
const authHeader = await authStore.getAuthHeader()
return {
...(authHeader && { headers: authHeader })

View File

@@ -11,7 +11,7 @@ import { useFeatureFlags } from '@/composables/useFeatureFlags'
import { isCloud, isDesktop } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import { useDialogService } from '@/services/dialogService'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import { useUserStore } from '@/stores/userStore'
import LayoutDefault from '@/views/layouts/LayoutDefault.vue'
@@ -140,7 +140,7 @@ if (isCloud) {
}
// Global authentication guard
router.beforeEach(async (to, _from, next) => {
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
// Wait for Firebase auth to initialize
// Timeout after 16 seconds

View File

@@ -60,7 +60,7 @@ import type {
JobListItem
} from '@/platform/remote/comfyui/jobs/jobTypes'
import type { ComfyNodeDef } from '@/schemas/nodeDefSchema'
import type { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import type { useAuthStore } from '@/stores/authStore'
import type { AuthHeader } from '@/types/authTypes'
import type { NodeExecutionId } from '@/types/nodeIdentification'
import {
@@ -332,7 +332,7 @@ export class ComfyApi extends EventTarget {
/**
* Cache Firebase auth store composable function.
*/
private authStoreComposable?: typeof useFirebaseAuthStore
private authStoreComposable?: typeof useAuthStore
reportedUnknownMessageTypes = new Set<string>()
@@ -399,8 +399,8 @@ export class ComfyApi extends EventTarget {
private async getAuthStore() {
if (isCloud) {
if (!this.authStoreComposable) {
const module = await import('@/stores/firebaseAuthStore')
this.authStoreComposable = module.useFirebaseAuthStore
const module = await import('@/stores/authStore')
this.authStoreComposable = module.useAuthStore
}
return this.authStoreComposable()

View File

@@ -67,7 +67,7 @@ import { useExecutionStore } from '@/stores/executionStore'
import { useExecutionErrorStore } from '@/stores/executionErrorStore'
import { useMissingNodesErrorStore } from '@/platform/nodeReplacement/missingNodesErrorStore'
import { useExtensionStore } from '@/stores/extensionStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import { useNodeOutputStore } from '@/stores/nodeOutputStore'
import { useJobPreviewStore } from '@/stores/jobPreviewStore'
import { KeyComboImpl } from '@/platform/keybindings/keyCombo'
@@ -1591,7 +1591,7 @@ export class ComfyApp {
executionErrorStore.clearAllErrors()
// Get auth token for backend nodes - uses workspace token if enabled, otherwise Firebase token
const comfyOrgAuthToken = await useFirebaseAuthStore().getAuthToken()
const comfyOrgAuthToken = await useAuthStore().getAuthToken()
const comfyOrgApiKey = useApiKeyAuthStore().getApiKey()
try {

View File

@@ -11,7 +11,7 @@ const mockAxiosInstance = vi.hoisted(() => ({
get: vi.fn()
}))
const mockFirebaseAuthStore = vi.hoisted(() => ({
const mockAuthStore = vi.hoisted(() => ({
getAuthHeader: vi.fn()
}))
@@ -27,8 +27,8 @@ vi.mock('axios', () => ({
}
}))
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => mockFirebaseAuthStore)
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => mockAuthStore)
}))
vi.mock('@/i18n', () => ({
@@ -81,7 +81,7 @@ describe('useCustomerEventsService', () => {
vi.clearAllMocks()
// Setup default mocks
mockFirebaseAuthStore.getAuthHeader.mockResolvedValue(mockAuthHeaders)
mockAuthStore.getAuthHeader.mockResolvedValue(mockAuthHeaders)
mockI18n.d.mockImplementation((date, options) => {
// Mock i18n date formatting
if (options?.month === 'short') {
@@ -118,7 +118,7 @@ describe('useCustomerEventsService', () => {
limit: 10
})
expect(mockFirebaseAuthStore.getAuthHeader).toHaveBeenCalled()
expect(mockAuthStore.getAuthHeader).toHaveBeenCalled()
expect(mockAxiosInstance.get).toHaveBeenCalledWith('/customers/events', {
params: { page: 1, limit: 10 },
headers: mockAuthHeaders
@@ -141,7 +141,7 @@ describe('useCustomerEventsService', () => {
})
it('should return null when auth headers are missing', async () => {
mockFirebaseAuthStore.getAuthHeader.mockResolvedValue(null)
mockAuthStore.getAuthHeader.mockResolvedValue(null)
const result = await service.getMyEvents()

View File

@@ -4,7 +4,7 @@ import { ref, watch } from 'vue'
import { getComfyApiBaseUrl } from '@/config/comfyApi'
import { d } from '@/i18n'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import type { components, operations } from '@/types/comfyRegistryTypes'
import { isAbortError } from '@/utils/typeGuardUtil'
@@ -179,7 +179,7 @@ export const useCustomerEventsService = () => {
}
// Get auth headers
const authHeaders = await useFirebaseAuthStore().getAuthHeader()
const authHeaders = await useAuthStore().getAuthHeader()
if (!authHeaders) {
error.value = 'Authentication header is missing'
return null

View File

@@ -0,0 +1,42 @@
import { describe, expect, it } from 'vitest'
import { createAuthStoreMock, mockAuthStoreModule } from './authStoreMock'
describe('authStoreMock', () => {
it('creates a mock with reactive computed properties', () => {
const { mock, controls } = createAuthStoreMock()
expect(mock.isAuthenticated).toBe(false)
expect(mock.userEmail).toBeNull()
expect(mock.userId).toBeNull()
controls.currentUser.value = { uid: 'u1', email: 'a@b.com' }
expect(mock.isAuthenticated).toBe(true)
expect(mock.userEmail).toBe('a@b.com')
expect(mock.userId).toBe('u1')
})
it('starts with clean defaults', () => {
const { controls } = createAuthStoreMock()
expect(controls.currentUser.value).toBeNull()
expect(controls.isInitialized.value).toBe(false)
expect(controls.loading.value).toBe(false)
expect(controls.balance.value).toBeNull()
expect(controls.isFetchingBalance.value).toBe(false)
})
it('creates independent instances per call', () => {
const a = createAuthStoreMock()
const b = createAuthStoreMock()
a.controls.currentUser.value = { uid: 'a' }
expect(b.mock.isAuthenticated).toBe(false)
})
it('mockAuthStoreModule wraps mock correctly', () => {
const { mock } = createAuthStoreMock()
const module = mockAuthStoreModule(mock)
expect(module.useAuthStore()).toBe(mock)
expect(new module.AuthStoreError('test').name).toBe('AuthStoreError')
})
})

View File

@@ -0,0 +1,110 @@
import type { Mock } from 'vitest'
import { computed, reactive, ref } from 'vue'
/**
* Shared mock factory for useAuthStore.
*
* Usage in test files:
* import { createAuthStoreMock, mockAuthStoreModule } from '@/stores/__tests__/authStoreMock'
*
* const { mock, controls } = createAuthStoreMock()
* vi.mock('@/stores/authStore', () => mockAuthStoreModule(mock))
*
* // Per-test customization:
* controls.currentUser.value = { uid: 'test-123', email: 'a@b.com' }
* controls.getAuthHeader.mockResolvedValue({ Authorization: 'Bearer tok' })
*/
export interface AuthStoreMockControls {
currentUser: ReturnType<typeof ref<Record<string, unknown> | null>>
isInitialized: ReturnType<typeof ref<boolean>>
loading: ReturnType<typeof ref<boolean>>
balance: ReturnType<typeof ref<Record<string, unknown> | null>>
isFetchingBalance: ReturnType<typeof ref<boolean>>
tokenRefreshTrigger: ReturnType<typeof ref<number>>
login: Mock
register: Mock
logout: Mock
getIdToken: Mock
getAuthHeader: Mock
getAuthHeaderOrThrow: Mock
getFirebaseAuthHeader: Mock
getFirebaseAuthHeaderOrThrow: Mock
getAuthToken: Mock
createCustomer: Mock
fetchBalance: Mock
accessBillingPortal: Mock
loginWithGoogle: Mock
loginWithGithub: Mock
sendPasswordReset: Mock
updatePassword: Mock
initiateCreditPurchase: Mock
}
export function createAuthStoreMock(): {
mock: Record<string, unknown>
controls: AuthStoreMockControls
} {
const currentUser = ref<Record<string, unknown> | null>(null)
const isInitialized = ref(false)
const loading = ref(false)
const balance = ref<Record<string, unknown> | null>(null)
const isFetchingBalance = ref(false)
const tokenRefreshTrigger = ref(0)
const controls: AuthStoreMockControls = {
currentUser,
isInitialized,
loading,
balance,
isFetchingBalance,
tokenRefreshTrigger,
login: vi.fn(),
register: vi.fn(),
logout: vi.fn(),
getIdToken: vi.fn().mockResolvedValue('mock-id-token'),
getAuthHeader: vi.fn().mockResolvedValue(null),
getAuthHeaderOrThrow: vi.fn().mockResolvedValue({
Authorization: 'Bearer mock-id-token'
}),
getFirebaseAuthHeader: vi.fn().mockResolvedValue(null),
getFirebaseAuthHeaderOrThrow: vi.fn().mockResolvedValue({
Authorization: 'Bearer mock-id-token'
}),
getAuthToken: vi.fn().mockResolvedValue(undefined),
createCustomer: vi.fn(),
fetchBalance: vi.fn(),
accessBillingPortal: vi.fn(),
loginWithGoogle: vi.fn(),
loginWithGithub: vi.fn(),
sendPasswordReset: vi.fn(),
updatePassword: vi.fn(),
initiateCreditPurchase: vi.fn()
}
const mock = reactive({
...controls,
isAuthenticated: computed(() => !!currentUser.value),
userEmail: computed(
() => (currentUser.value as Record<string, unknown> | null)?.email ?? null
),
userId: computed(
() => (currentUser.value as Record<string, unknown> | null)?.uid ?? null
)
})
return { mock, controls }
}
export function mockAuthStoreModule(mock: Record<string, unknown>) {
return {
useAuthStore: () => mock,
AuthStoreError: class extends Error {
constructor(message: string) {
super(message)
this.name = 'AuthStoreError'
}
}
}
}

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

@@ -5,7 +5,7 @@ import { computed, ref, watch } from 'vue'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { t } from '@/i18n'
import { useToastStore } from '@/platform/updates/common/toastStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import type { ApiKeyAuthHeader } from '@/types/authTypes'
import type { operations } from '@/types/comfyRegistryTypes'
@@ -15,7 +15,7 @@ type ComfyApiUser =
const STORAGE_KEY = 'comfy_api_key'
export const useApiKeyAuthStore = defineStore('apiKeyAuth', () => {
const firebaseAuthStore = useFirebaseAuthStore()
const firebaseAuthStore = useAuthStore()
const apiKey = useLocalStorage<string | null>(STORAGE_KEY, null)
const toastStore = useToastStore()
const { wrapWithErrorHandlingAsync, toastErrorHandler } = useErrorHandling()

View File

@@ -7,7 +7,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import * as vuefire from 'vuefire'
import { useDialogService } from '@/services/dialogService'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import { createTestingPinia } from '@pinia/testing'
// Hoisted mocks for dynamic imports
@@ -122,8 +122,8 @@ vi.mock('@/stores/apiKeyAuthStore', () => ({
})
}))
describe('useFirebaseAuthStore', () => {
let store: ReturnType<typeof useFirebaseAuthStore>
describe('useAuthStore', () => {
let store: ReturnType<typeof useAuthStore>
let authStateCallback: (user: User | null) => void
let idTokenCallback: (user: User | null) => void
@@ -182,7 +182,7 @@ describe('useFirebaseAuthStore', () => {
// Initialize Pinia
setActivePinia(createTestingPinia({ stubActions: false }))
store = useFirebaseAuthStore()
store = useAuthStore()
// Reset and set up getIdToken mock
mockUser.getIdToken.mockReset()
@@ -210,8 +210,8 @@ describe('useFirebaseAuthStore', () => {
)
setActivePinia(createTestingPinia({ stubActions: false }))
const storeModule = await import('@/stores/firebaseAuthStore')
store = storeModule.useFirebaseAuthStore()
const storeModule = await import('@/stores/authStore')
store = storeModule.useAuthStore()
})
it("should not increment tokenRefreshTrigger on the user's first ID token event", () => {
@@ -730,6 +730,37 @@ describe('useFirebaseAuthStore', () => {
})
})
describe('getAuthHeaderOrThrow', () => {
it('returns auth header when authenticated', async () => {
const header = await store.getAuthHeaderOrThrow()
expect(header).toEqual({ Authorization: 'Bearer mock-id-token' })
})
it('throws AuthStoreError when not authenticated', async () => {
authStateCallback(null)
mockApiKeyGetAuthHeader.mockReturnValue(null)
await expect(store.getAuthHeaderOrThrow()).rejects.toThrow(
'toastMessages.userNotAuthenticated'
)
})
})
describe('getFirebaseAuthHeaderOrThrow', () => {
it('returns Firebase auth header when authenticated', async () => {
const header = await store.getFirebaseAuthHeaderOrThrow()
expect(header).toEqual({ Authorization: 'Bearer mock-id-token' })
})
it('throws AuthStoreError when not authenticated', async () => {
authStateCallback(null)
await expect(store.getFirebaseAuthHeaderOrThrow()).rejects.toThrow(
'toastMessages.userNotAuthenticated'
)
})
})
describe('createCustomer', () => {
it('should succeed with API key auth when no Firebase user is present', async () => {
authStateCallback(null)

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'
@@ -49,14 +49,14 @@ export type BillingPortalTargetTier = NonNullable<
>['application/json']
>['target_tier']
export class FirebaseAuthStoreError extends Error {
export class AuthStoreError extends Error {
constructor(message: string) {
super(message)
this.name = 'FirebaseAuthStoreError'
this.name = 'AuthStoreError'
}
}
export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
export const useAuthStore = defineStore('auth', () => {
const { flags } = useFeatureFlags()
// State
@@ -110,15 +110,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
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 useFirebaseAuthStore = defineStore('firebaseAuth', () => {
*/
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,32 +197,35 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
*/
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()
}
const getAuthHeaderOrThrow = async (): Promise<AuthHeader> => {
const authHeader = await getAuthHeader()
if (!authHeader) {
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
return authHeader
}
const getFirebaseAuthHeaderOrThrow = async (): Promise<AuthHeader> => {
const authHeader = await getFirebaseAuthHeader()
if (!authHeader) {
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
return authHeader
}
const fetchBalance = async (): Promise<GetCustomerBalanceResponse | null> => {
isFetchingBalance.value = true
try {
const authHeader = await getAuthHeader()
if (!authHeader) {
throw new FirebaseAuthStoreError(
t('toastMessages.userNotAuthenticated')
)
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
const response = await fetch(buildApiUrl('/customers/balance'), {
@@ -259,7 +241,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
return null
}
const errorData = await response.json()
throw new FirebaseAuthStoreError(
throw new AuthStoreError(
t('toastMessages.failedToFetchBalance', {
error: errorData.message
})
@@ -279,7 +261,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
const createCustomer = async (): Promise<CreateCustomerResponse> => {
const authHeader = await getAuthHeader()
if (!authHeader) {
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
const createCustomerRes = await fetch(buildApiUrl('/customers'), {
@@ -290,7 +272,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
}
})
if (!createCustomerRes.ok) {
throw new FirebaseAuthStoreError(
throw new AuthStoreError(
t('toastMessages.failedToCreateCustomer', {
error: createCustomerRes.statusText
})
@@ -300,7 +282,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
const createCustomerResJson: CreateCustomerResponse =
await createCustomerRes.json()
if (!createCustomerResJson?.id) {
throw new FirebaseAuthStoreError(
throw new AuthStoreError(
t('toastMessages.failedToCreateCustomer', {
error: 'No customer ID returned'
})
@@ -431,7 +413,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
/** Update password for current user */
const _updatePassword = async (newPassword: string): Promise<void> => {
if (!currentUser.value) {
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
await updatePassword(currentUser.value, newPassword)
}
@@ -441,7 +423,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
): Promise<CreditPurchaseResponse> => {
const authHeader = await getAuthHeader()
if (!authHeader) {
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
// Ensure customer was created during login/registration
@@ -461,7 +443,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
if (!response.ok) {
const errorData = await response.json()
throw new FirebaseAuthStoreError(
throw new AuthStoreError(
t('toastMessages.failedToInitiateCreditPurchase', {
error: errorData.message
})
@@ -481,7 +463,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
): Promise<AccessBillingPortalResponse> => {
const authHeader = await getAuthHeader()
if (!authHeader) {
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
throw new AuthStoreError(t('toastMessages.userNotAuthenticated'))
}
const response = await fetch(buildApiUrl('/customers/billing'), {
@@ -497,7 +479,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
if (!response.ok) {
const errorData = await response.json()
throw new FirebaseAuthStoreError(
throw new AuthStoreError(
t('toastMessages.failedToAccessBillingPortal', {
error: errorData.message
})
@@ -536,7 +518,9 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
sendPasswordReset,
updatePassword: _updatePassword,
getAuthHeader,
getAuthHeaderOrThrow,
getFirebaseAuthHeader,
getFirebaseAuthHeaderOrThrow,
getAuthToken
}
})

View File

@@ -50,12 +50,12 @@ vi.mock('@/stores/userStore', () => ({
}))
}))
const mockIsFirebaseInitialized = ref(false)
const mockIsFirebaseAuthenticated = ref(false)
vi.mock('@/stores/firebaseAuthStore', () => ({
useFirebaseAuthStore: vi.fn(() => ({
isInitialized: mockIsFirebaseInitialized,
isAuthenticated: mockIsFirebaseAuthenticated
const mockIsAuthInitialized = ref(false)
const mockIsAuthAuthenticated = ref(false)
vi.mock('@/stores/authStore', () => ({
useAuthStore: vi.fn(() => ({
isInitialized: mockIsAuthInitialized,
isAuthenticated: mockIsAuthAuthenticated
}))
}))
@@ -67,8 +67,8 @@ vi.mock('@/platform/distribution/types', () => mockDistributionTypes)
describe('bootstrapStore', () => {
beforeEach(() => {
mockIsSettingsReady.value = false
mockIsFirebaseInitialized.value = false
mockIsFirebaseAuthenticated.value = false
mockIsAuthInitialized.value = false
mockIsAuthAuthenticated.value = false
mockNeedsLogin.value = false
mockDistributionTypes.isCloud = false
setActivePinia(createTestingPinia({ stubActions: false }))
@@ -107,14 +107,14 @@ describe('bootstrapStore', () => {
expect(settingStore.isReady).toBe(false)
// Firebase initialized but user not yet authenticated
mockIsFirebaseInitialized.value = true
mockIsAuthInitialized.value = true
await nextTick()
expect(store.isI18nReady).toBe(false)
expect(settingStore.isReady).toBe(false)
// User authenticates (e.g. signs in on login page)
mockIsFirebaseAuthenticated.value = true
mockIsAuthAuthenticated.value = true
await bootstrapPromise
await vi.waitFor(() => {

View File

@@ -5,7 +5,7 @@ import { isCloud } from '@/platform/distribution/types'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import { api } from '@/scripts/api'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import { useUserStore } from '@/stores/userStore'
export const useBootstrapStore = defineStore('bootstrap', () => {
@@ -37,9 +37,7 @@ export const useBootstrapStore = defineStore('bootstrap', () => {
async function startStoreBootstrap() {
if (isCloud) {
const { isInitialized, isAuthenticated } = storeToRefs(
useFirebaseAuthStore()
)
const { isInitialized, isAuthenticated } = storeToRefs(useAuthStore())
await until(isInitialized).toBe(true)
await until(isAuthenticated).toBe(true)
}

View File

@@ -13,7 +13,7 @@ import type { SidebarTabExtension, ToastManager } from '@/types/extensionTypes'
import { useApiKeyAuthStore } from './apiKeyAuthStore'
import { useCommandStore } from './commandStore'
import { useExecutionErrorStore } from './executionErrorStore'
import { useFirebaseAuthStore } from './firebaseAuthStore'
import { useAuthStore } from './authStore'
import { useQueueSettingsStore } from './queueStore'
import { useBottomPanelStore } from './workspace/bottomPanelStore'
import { useSidebarTabStore } from './workspace/sidebarTabStore'
@@ -48,7 +48,7 @@ function workspaceStoreSetup() {
const dialog = useDialogService()
const bottomPanel = useBottomPanelStore()
const authStore = useFirebaseAuthStore()
const authStore = useAuthStore()
const apiKeyStore = useApiKeyAuthStore()
const firebaseUser = computed(() => authStore.currentUser)

View File

@@ -78,7 +78,7 @@ import { useAppMode } from '@/composables/useAppMode'
import { useAssetsStore } from '@/stores/assetsStore'
import { useCommandStore } from '@/stores/commandStore'
import { useExecutionStore } from '@/stores/executionStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useAuthStore } from '@/stores/authStore'
import { useMenuItemStore } from '@/stores/menuItemStore'
import { useModelStore } from '@/stores/modelStore'
import { useNodeDefStore, useNodeFrequencyStore } from '@/stores/nodeDefStore'
@@ -120,7 +120,7 @@ watch(linearMode, (isLinear) => {
})
const telemetry = useTelemetry()
const firebaseAuthStore = useFirebaseAuthStore()
const firebaseAuthStore = useAuthStore()
let hasTrackedLogin = false
watch(