Backend: - /api/devops/info now requires admin role (was: any authenticated user). Exposes env keys, dep checks, and socket counts — admin-only by design. - New /api/devops/version (public, no auth) returns build SHA/branch/image for ops/CI rollback verification. - Dep checks: live ping for Cosmos (trading_users) and platform-service. - Service version read dynamically via readServiceVersion(import.meta.url) — no more hardcoded '0.1.0'. - extra: socketIoConnections + tradingApiUrl for runtime debugging. - saveCurrentUserProfile no longer accepts client-supplied role — prevents drift with platform JWT (which is authoritative). Web: - DevOps tab is now admin-only (gated behind isAdmin like Bot Config and Admin Panel). Both the section list and content render are guarded. - Service version baked into bundle via Vite `define` (__WEB_SERVICE_VERSION__) read from web/package.json — no more hardcoded VERSION constant. - Bumps @bytelyst/devops dep to ^0.1.2. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
136 lines
5.1 KiB
TypeScript
136 lines
5.1 KiB
TypeScript
/// <reference types="vitest/config" />
|
|
import { defineConfig } from 'vitest/config';
|
|
import react from '@vitejs/plugin-react';
|
|
import tailwindcss from '@tailwindcss/vite';
|
|
import path from 'node:path';
|
|
import fs from 'node:fs';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
|
|
import { playwright } from '@vitest/browser-playwright';
|
|
const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
// Read service version from package.json so DevOps panel reflects the real version.
|
|
const webPackageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, 'package.json'), 'utf8')) as { version?: string };
|
|
const webServiceVersion = webPackageJson.version || '0.0.0';
|
|
|
|
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
|
|
const monacoEditorPath = path.resolve(__dirname, 'node_modules/monaco-editor');
|
|
const workspaceRoot = path.resolve(__dirname, '..', '..');
|
|
const commonPlatRoot = path.join(workspaceRoot, 'learning_ai_common_plat');
|
|
function commonPlatSourceEntry(pkg: string): string | null {
|
|
const sourceEntry = path.join(commonPlatRoot, 'packages', pkg, 'src', 'index.ts');
|
|
return fs.existsSync(sourceEntry) ? sourceEntry : null;
|
|
}
|
|
|
|
// Resolve a @bytelyst/* package: prefer web/node_modules, fall back to vendor/
|
|
function bytelystAlias(pkg: string): string {
|
|
const sourceEntry = commonPlatSourceEntry(pkg);
|
|
if (sourceEntry) return sourceEntry;
|
|
const nmPath = path.resolve(__dirname, 'node_modules/@bytelyst', pkg);
|
|
const vendorPath = path.resolve(__dirname, '../vendor/bytelyst', pkg);
|
|
if (fs.existsSync(nmPath)) return nmPath;
|
|
if (fs.existsSync(vendorPath)) return vendorPath;
|
|
return nmPath; // let Vite surface the missing-module error
|
|
}
|
|
|
|
// https://vite.dev/config/
|
|
export default defineConfig({
|
|
plugins: [react(), tailwindcss()],
|
|
define: {
|
|
__WEB_SERVICE_VERSION__: JSON.stringify(webServiceVersion),
|
|
},
|
|
// Shared files (../shared/*.ts) live outside web/ so Vite resolves their imports
|
|
// from the repo root where @bytelyst/* are not installed. Redirect all @bytelyst/*
|
|
// imports first to web/node_modules, then fall back to the monorepo vendor/ dir.
|
|
resolve: {
|
|
// Deduplicate React so the vendored react-auth dist resolves the same react instance
|
|
dedupe: ['react', 'react-dom', 'react/jsx-runtime', 'react-router-dom'],
|
|
alias: [
|
|
// Vendor packages that live only in vendor/ (not in web/node_modules/)
|
|
{
|
|
find: '@bytelyst/api-client',
|
|
replacement: bytelystAlias('api-client')
|
|
}, {
|
|
find: '@bytelyst/design-tokens',
|
|
replacement: bytelystAlias('design-tokens')
|
|
}, {
|
|
find: '@bytelyst/errors',
|
|
replacement: bytelystAlias('errors')
|
|
}, {
|
|
find: '@bytelyst/kill-switch-client',
|
|
replacement: bytelystAlias('kill-switch-client')
|
|
}, {
|
|
find: '@bytelyst/react-auth',
|
|
replacement: bytelystAlias('react-auth')
|
|
}, {
|
|
find: '@bytelyst/telemetry-client',
|
|
replacement: bytelystAlias('telemetry-client')
|
|
}, {
|
|
find: '@bytelyst/ui',
|
|
replacement: bytelystAlias('ui')
|
|
},
|
|
// Monaco is an explicit web dependency, but this workspace often runs
|
|
// against pnpm's root store without a web/node_modules symlink when the
|
|
// private mobile registry is unavailable. Keep local worker imports
|
|
// resolvable for Vite in that partially installed state.
|
|
{
|
|
find: /^monaco-editor$/,
|
|
replacement: monacoEditorPath
|
|
}, {
|
|
find: /^monaco-editor\/(.+)/,
|
|
replacement: `${monacoEditorPath}/$1`
|
|
},
|
|
// General catch-all: every other @bytelyst/* → web/node_modules.
|
|
// Restricted to single-segment scope names only, so subpath imports like
|
|
// `@bytelyst/devops/ui` go through normal package resolution (exports map).
|
|
{
|
|
find: /^@bytelyst\/([^/]+)$/,
|
|
replacement: path.resolve(__dirname, 'node_modules/@bytelyst/$1')
|
|
}]
|
|
},
|
|
build: {
|
|
chunkSizeWarningLimit: 5000,
|
|
rollupOptions: {
|
|
output: {
|
|
manualChunks(id) {
|
|
if (id.includes('monaco-editor') || id.includes('@monaco-editor')) {
|
|
return 'monaco-vendor';
|
|
}
|
|
if (id.includes('/node_modules/')) {
|
|
return 'vendor';
|
|
}
|
|
return undefined;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
test: {
|
|
projects: [{
|
|
extends: true,
|
|
test: {
|
|
environment: 'jsdom',
|
|
setupFiles: ['./src/test/setup.ts'],
|
|
include: ['src/**/*.test.ts', 'src/**/*.test.tsx', 'src/**/*.dom.test.tsx']
|
|
}
|
|
}, {
|
|
extends: true,
|
|
plugins: [
|
|
// The plugin will run tests for the stories defined in your Storybook config
|
|
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
|
|
storybookTest({
|
|
configDir: path.join(dirname, '.storybook')
|
|
})],
|
|
test: {
|
|
name: 'storybook',
|
|
browser: {
|
|
enabled: true,
|
|
headless: true,
|
|
provider: playwright({}),
|
|
instances: [{
|
|
browser: 'chromium'
|
|
}]
|
|
}
|
|
}
|
|
}]
|
|
}
|
|
}); |