feat(desktop): embed BoosAPI Desktop client as a subproject

Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as
a monorepo subdirectory under desktop/. Source only — node_modules,
dist, Cargo target and the upstream .git history are excluded.

desktop/ keeps its own independent Cargo workspace (desktop/src-tauri
with crates/*); it is not part of the backend boosapi crate, so a
`cargo check` at the metapi root still compiles only the backend. Build
the desktop app from desktop/src-tauri per desktop/README.md.

Note: app icons are still placeholder assets pending the final BoosAPI
logo. The updater signing keys live outside the repo and are not
included.
This commit is contained in:
boos
2026-06-22 11:32:57 +08:00
parent d9c78ecc73
commit e0a5f57793
2305 changed files with 449355 additions and 0 deletions
@@ -0,0 +1,127 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
// Mock the local monaco shim so tests don't try to resolve the real
// 'monaco-editor' package entry via vite.
vi.mock('../src/monaco-shim', () => {
const setTheme = vi.fn()
const setModelLanguage = vi.fn()
const editor = {
setTheme,
setModelLanguage,
IStandaloneCodeEditor: class {},
EditorOption: { lineHeight: 16 },
}
const languages = {
getLanguages: () => [],
register: () => {},
}
const Range = class {}
return { default: { editor, languages, Range }, editor, languages, Range }
})
describe('setTheme behavior', () => {
beforeEach(() => {
// src/index.ts keeps theme state at module scope; isolate each test.
vi.resetModules()
vi.clearAllMocks()
})
afterEach(() => {
vi.restoreAllMocks()
})
it('should not call monaco.editor.setTheme when theme is already applied', async () => {
const monaco = await import('../src/monaco-shim')
const mod = await import('../src/index')
const { setTheme } = mod.useMonaco({ themes: ['vitesse-dark', 'vitesse-light'] })
// apply once
await setTheme('vitesse-dark')
// applying same theme again without force should be no-op
await setTheme('vitesse-dark')
expect(monaco.editor.setTheme).toHaveBeenCalled()
// should only have been called once by the first application
expect((monaco.editor.setTheme as any).mock.calls.length).toBe(1)
})
it('should call monaco.editor.setTheme when force=true even if same theme', async () => {
const monaco = await import('../src/monaco-shim')
const mod = await import('../src/index')
const { setTheme } = mod.useMonaco({ themes: ['vitesse-dark', 'vitesse-light'] })
await setTheme('vitesse-dark')
// force reapplication
await setTheme('vitesse-dark', true)
expect((monaco.editor.setTheme as any).mock.calls.length).toBe(2)
})
it('should not no-op when another instance changed the global theme', async () => {
const monaco = await import('../src/monaco-shim')
const mod = await import('../src/index')
const a = mod.useMonaco({ themes: ['vitesse-dark', 'vitesse-light'] })
const b = mod.useMonaco({ themes: ['vitesse-dark', 'vitesse-light'] })
await a.setTheme('vitesse-dark')
await b.setTheme('vitesse-light')
await a.setTheme('vitesse-dark')
expect((monaco.editor.setTheme as any).mock.calls.length).toBe(3)
})
it('auto-loads missing shiki theme when highlighter is cached', async () => {
vi.resetModules()
// Mock shiki/monaco registration layer: always returns the same highlighter
// instance (simulating singleton caching), and requires explicit loadTheme
// before setTheme will succeed.
const loadedThemes = new Set<string>(['vitesse-dark', 'vitesse-light'])
const highlighter = {
loadTheme: vi.fn(async (t: string) => {
loadedThemes.add(t)
}),
setTheme: vi.fn(async (t: string) => {
if (!loadedThemes.has(t)) {
const err: any = new Error(`Theme ${t} not found, you may need to load it first`)
err.name = 'ShikiError'
throw err
}
}),
codeToHtml: vi.fn(() => ''),
}
vi.doMock('../src/utils/registerMonacoThemes', () => {
return {
clearHighlighterCache: () => {},
getOrCreateHighlighter: async () => highlighter,
registerMonacoThemes: async () => highlighter,
setThemeRegisterPromise: (p: any) => p,
}
})
// re-mock monaco shim for this resetModules scope
vi.doMock('../src/monaco-shim', () => {
const setTheme = vi.fn()
const setModelLanguage = vi.fn()
const editor = {
setTheme,
setModelLanguage,
IStandaloneCodeEditor: class {},
EditorOption: { lineHeight: 16 },
}
const languages = {
getLanguages: () => [],
register: () => {},
}
const Range = class {}
return { default: { editor, languages, Range }, editor, languages, Range }
})
const monaco = await import('../src/monaco-shim')
const mod = await import('../src/index')
const { setTheme } = mod.useMonaco({ themes: ['vitesse-dark', 'vitesse-light'] })
await setTheme('andromeeda')
expect(highlighter.loadTheme).toHaveBeenCalledWith('andromeeda')
expect(monaco.editor.setTheme).toHaveBeenCalledWith('andromeeda')
})
})