- Consolidated middleware setup into a dedicated setup file for better organization. - Introduced API proxy middleware to handle requests to the backend API. - Registered well-known, merge, and SSR routes in separate files for improved modularity. - Removed unused HTML and SSR layout files to streamline the codebase. - Implemented a utility for HTML escaping to prevent XSS vulnerabilities. - Updated the main server entry point to utilize the new middleware and route structure.
13 KiB
AGENTS.md
This file provides guidance for AI coding agents working with the Holistream codebase.
Project Overview
Holistream is a Vue 3 streaming application with Server-Side Rendering (SSR) deployed on Cloudflare Workers. It provides video upload, management, and streaming capabilities for content creators.
Key Characteristics
- Type: Full-stack web application with SSR
- Primary Language: TypeScript
- Package Manager: Bun (evident from
bun.lock) - Deployment Target: Cloudflare Workers
Technology Stack
| Category | Technology | Version |
|---|---|---|
| Framework | Vue | 3.5.27 |
| Router | Vue Router | 5.0.2 |
| Server Framework | Hono | 4.11.7 |
| Build Tool | Vite | 7.3.1 |
| CSS Framework | UnoCSS | 66.6.0 |
| UI Components | PrimeVue | 4.5.4 |
| State Management | Pinia | 3.0.4 |
| Server State | Pinia Colada | 0.21.2 |
| Meta/SEO | @unhead/vue | 2.1.2 |
| Utilities | VueUse | 14.2.0 |
| Validation | Zod | 4.3.6 |
| Deployment | Wrangler | 4.62.0 |
Project Structure
.
├── src/
│ ├── api/ # API client and HTTP adapters
│ │ ├── client.ts # Auto-generated API client from OpenAPI spec
│ │ ├── httpClientAdapter.client.ts # Client-side fetch adapter
│ │ └── httpClientAdapter.server.ts # Server-side fetch adapter
│ ├── client.ts # Client entry point (hydration)
│ ├── components/ # Vue components
│ │ ├── dashboard/ # Dashboard-specific components
│ │ ├── icons/ # Custom icon components
│ │ ├── ui/ # UI primitive components
│ │ ├── ClientOnly.tsx # SSR-safe client-only wrapper
│ │ ├── DashboardLayout.vue # Main dashboard layout
│ │ ├── GlobalUploadIndicator.vue
│ │ ├── NotificationDrawer.vue
│ │ └── RootLayout.vue # Root application layout
│ ├── composables/ # Vue composables
│ │ └── useUploadQueue.ts # Upload queue management
│ ├── index.tsx # Server entry point (Hono app)
│ ├── lib/ # Utility libraries
│ │ ├── constants.ts # Application constants
│ │ ├── directives/ # Custom Vue directives
│ │ ├── hoc/ # Higher-order components
│ │ ├── interface.ts # TypeScript interfaces
│ │ ├── liteMqtt.ts # MQTT client (browser)
│ │ ├── manifest.ts # Vite manifest utilities
│ │ ├── PiniaSharedState.ts # Pinia state hydration plugin
│ │ ├── primePassthrough.ts # PrimeVue theme configuration
│ │ ├── replateStreamText.ts
│ │ └── utils.ts # Utility functions (cn, formatters, etc.)
│ ├── main.ts # App factory function
│ ├── mocks/ # Mock data for development
│ ├── routes/ # Route components (page components)
│ │ ├── auth/ # Authentication pages
│ │ ├── home/ # Public pages (landing, terms, privacy)
│ │ ├── notification/ # Notification page
│ │ ├── overview/ # Dashboard overview
│ │ ├── plans/ # Payments & plans
│ │ ├── profile/ # User profile
│ │ ├── upload/ # Video upload
│ │ ├── video/ # Video management
│ │ ├── index.ts # Router configuration
│ │ └── NotFound.vue # 404 page
│ ├── server/ # Server-side utilities
│ │ └── modules/
│ │ └── merge.ts # Video chunk merge logic
│ ├── stores/ # Pinia stores
│ │ └── auth.ts # Authentication store
│ ├── type.d.ts # TypeScript declarations
│ └── worker/ # Worker utilities
│ ├── html.ts
│ └── ssrLayout.ts
├── bootstrap_btn.ts # Bootstrap button preset for UnoCSS
├── ssrPlugin.ts # Custom Vite SSR plugin
├── uno.config.ts # UnoCSS configuration
├── vite.config.ts # Vite configuration
├── wrangler.jsonc # Cloudflare Workers configuration
├── tsconfig.json # TypeScript configuration
├── package.json # Package dependencies
├── bun.lock # Bun lock file
├── docs.json # OpenAPI/Swagger spec for API
├── auto-imports.d.ts # Auto-generated type declarations
└── components.d.ts # Auto-generated component declarations
Build and Development Commands
# Install dependencies
bun install
# Start development server with hot reload
bun dev
# Build for production (client + worker)
bun run build
# Preview production build locally
bun preview
# Deploy to Cloudflare Workers
bun run deploy
# Generate TypeScript types from Wrangler config
bun run cf-typegen
# View Cloudflare Worker logs
bun run tail
Note
: While npm commands work (
npm run dev, etc.), the project uses Bun as its primary package manager.
Architecture Details
SSR Architecture
The application uses a custom SSR setup defined in ssrPlugin.ts:
- Build Order: Client bundle is built FIRST, then the Worker bundle
- Manifest Injection: Vite manifest is injected into the server build for asset rendering
- Environment-based Resolution:
httpClientAdapterandliteMqttresolve to different implementations based on SSR context
Entry Points:
- Server:
src/index.tsx- Hono app that renders Vue SSR stream - Client:
src/client.ts- Hydrates the SSR-rendered application - App Factory:
src/main.ts- Creates the Vue app instance (used by both)
State Management with SSR
Uses Pinia Colada for server state with SSR hydration:
- Server-side queries are fetched and serialized to
window.__APP_DATA__ - Client hydrates the query cache via
hydrateQueryCache() - Pinia state is serialized and restored via
PiniaSharedStateplugin
Module Aliases
Configured in tsconfig.json and vite.config.ts:
| Alias | Resolution |
|---|---|
@/ |
src/ |
@httpClientAdapter |
src/api/httpClientAdapter.server.ts (SSR) or .client.ts (browser) |
@liteMqtt |
src/lib/liteMqtt.server.ts (SSR) or .ts (browser) |
API Client Architecture
The API client (src/api/client.ts) is auto-generated from the OpenAPI spec (docs.json):
- Uses
customFetchadapter that differs between client/server - Server adapter (
httpClientAdapter.server.ts): Forwards cookies, merges headers, proxies toapi.pipic.fun - Client adapter (
httpClientAdapter.client.ts): Standard fetch with credentials - API proxy route:
/r/*paths proxy tohttps://api.pipic.fun
Routing Structure
Routes are defined in src/routes/index.ts with three main layout groups:
- Public (
/): Landing page, terms, privacy - Auth (
/login,/sign-up,/forgot): Authentication pages (redirects if logged in) - Dashboard: Protected routes requiring authentication
/overview- Main dashboard/upload- Video upload with queue management/video- Video list/video/:id- Video detail/edit/payments-and-plans- Billing management/notification,/profile- User settings
Route meta supports @unhead/vue for SEO:
meta: {
head: {
title: "Page Title",
meta: [{ name: "description", content: "..." }]
}
}
Styling System (UnoCSS)
Configuration in uno.config.ts:
- Presets: Wind4 (Tailwind-like), Typography, Attributify, Bootstrap buttons
- Custom Colors:
primary(#14a74b)secondary(#fd7906)accent,success,info,warning,danger
- Shortcuts:
press-animatedfor button press effects - Transformers:
transformerCompileClass(prefix:_for compiled classes)transformerVariantGroup
Use cn() from src/lib/utils.ts for conditional class merging (combines clsx + tailwind-merge).
Component Auto-Import
Components are auto-imported via unplugin-vue-components:
- PrimeVue components resolved via
PrimeVueResolver - Vue/Pinia/Vue Router APIs auto-imported via
unplugin-auto-import - Type declarations auto-generated to
components.d.tsandauto-imports.d.ts
Development Guidelines
Code Style
- TypeScript: Strict mode enabled
- JSX/TSX: Supported for components (import source:
vue) - CSS: Use UnoCSS utility classes; custom CSS in component
<style>blocks when needed
File Organization
- Page components go in
src/routes/following the route structure - Reusable components go in
src/components/ - Composables go in
src/composables/ - Stores go in
src/stores/ - Server utilities go in
src/server/
HTTP Requests
Always use the generated API client instead of raw fetch:
import { client } from '@/api/client';
// Example
const response = await client.auth.loginCreate({ email, password });
The client handles:
- Base URL resolution
- Cookie forwarding (server-side)
- Type safety
Authentication Flow
useAuthStoremanages auth state with cookie-based sessionsinit()is called on every request to fetch current user via/meendpointbeforeEachrouter guard redirects unauthenticated users from protected routes- MQTT client connects on user login for real-time notifications
File Upload Architecture
Upload queue (src/composables/useUploadQueue.ts):
- Supports both local files and remote URLs
- Presigned POST URLs fetched from API
- Parallel chunk upload (90MB chunks, max 3 parallel)
- Progress tracking with speed calculation
Type Safety
- TypeScript strict mode enabled
CloudflareBindingsinterface for environment variables (generated viacf-typegen)- API types auto-generated from backend OpenAPI spec (
docs.json)
Environment Configuration
Cloudflare Worker Bindings
Configured in wrangler.jsonc:
{
"name": "holistream",
"compatibility_date": "2025-08-03",
"compatibility_flags": ["nodejs_compat"],
"observability": { ... }
}
- No explicit secrets in code - use Wrangler secrets management
- Access environment variables via Hono context:
c.env.VAR_NAME
Local Environment
Create .dev.vars for local development secrets (do not commit):
SECRET_KEY=...
Testing and Quality
Current Status: There are currently no automated test suites (like Vitest) or linting tools (like ESLint/Prettier) configured.
When adding tests or linting:
- Add appropriate dev dependencies
- Update this section with commands and conventions
- Consider the SSR environment when writing tests
Security Considerations
- Cookie Security: Cookies are httpOnly, secure, and sameSite
- CORS: Configured via Hono's CORS middleware
- API Proxy: Backend API is never exposed directly to the browser; all requests go through
/r/*proxy - Input Validation: Use Zod for runtime validation
- XSS Protection: HTML escaping is applied to SSR data via
htmlEscape()function
Common Patterns
Creating a New Page
- Create component in
src/routes/<section>/PageName.vue - Add route to
src/routes/index.tswith appropriate meta - Use
headin route meta for SEO if needed
Using the Upload Queue
import { useUploadQueue } from '@/composables/useUploadQueue';
const { items, addFiles, addRemoteUrls, startQueue } = useUploadQueue();
Accessing Hono Context in Components
import { inject } from 'vue';
const honoContext = inject('honoContext');
Conditional Classes
import { cn } from '@/lib/utils';
const className = cn(
'base-class',
isActive && 'active-class',
variant === 'primary' ? 'text-primary' : 'text-secondary'
);
External Dependencies
- Backend API:
https://api.pipic.fun - MQTT Broker:
wss://mqtt-dashboard.com:8884/mqtt - Fonts: Google Fonts (Google Sans loaded from fonts.googleapis.com)
Important Files Reference
| Purpose | Path |
|---|---|
| Server entry | src/index.tsx |
| Client entry | src/client.ts |
| App factory | src/main.ts |
| Router config | src/routes/index.ts |
| API client | src/api/client.ts |
| Auth store | src/stores/auth.ts |
| SSR plugin | ssrPlugin.ts |
| UnoCSS config | uno.config.ts |
| Wrangler config | wrangler.jsonc |
| Vite config | vite.config.ts |
This document was generated for AI coding agents. For human contributors, see README.md.