Skip to content

Commit cfa43c7

Browse files
authored
express api (#836)
- **bump: version 0.1.8** - **bump: version 0.1.9** - **add mcp build prereq** - **embed standalone-ui from src into cli dist...** - **bump: version 0.1.10** - **add common dep...** - **update embed script to include index.html...** - **bump: version 0.1.11-0** - **include studio-ui in version tagging** - **add express-api config types** - **add app-factory...** - **refactor: use app-factory isntance to execute main** - **add exports of appfactory** - **update todos**
2 parents f52a54a + a960f8b commit cfa43c7

File tree

24 files changed

+823
-278
lines changed

24 files changed

+823
-278
lines changed

.github/workflows/cli-regression-test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ jobs:
3131

3232
- name: Build CLI package
3333
run: |
34-
yarn build
34+
yarn build:lib
35+
yarn workspace @vue-skuilder/mcp build
3536
yarn workspace @vue-skuilder/cli build
3637
3738
- name: Create test directory

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ User often uses dictation software, which, in context, mangles things like `vue`
99
## Commands
1010

1111
### Project Setup & Development
12-
- Setup: `yarn setup` (install dependencies, git submodules)
12+
- Setup: `yarn setup` (install dependencies, git submodules, build library packages)
1313
- Dev: `yarn dev` (starts CouchDB, platform-ui, express)
1414
- Build: `yarn build` (builds all packages in dependency order)
1515
- Clean: `yarn clean` (removes dist and node_modules)

express-api-plan.md

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# Express API Refactoring Plan
2+
3+
## Motivation
4+
5+
The Vue-Skuilder Express server serves as the **primary backend infrastructure** for the full Vue-Skuilder platform. However, the CLI's studio mode needs to reuse the same API endpoints for course editing functionality.
6+
7+
Currently, the CLI embeds the Express server by copying built files and assets, but this approach fails at runtime because the embedded Express server cannot resolve its Node.js dependencies (like `cookie-parser`, `cors`, etc.) through normal module resolution.
8+
9+
The CLI's `yarn studio` command fails with:
10+
```
11+
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'cookie-parser' imported from .../node_modules/@vue-skuilder/cli/dist/express-assets/app.js
12+
```
13+
14+
This occurs because the embedded Express files expect their dependencies to be available through `node_modules` resolution, but when the CLI is installed via `npx` in an external project, those dependencies aren't available.
15+
16+
**Key Point**: Express's primary role as platform backend infrastructure should remain unchanged. We need to add a secondary programmatic API for CLI studio reuse.
17+
18+
## Requirements
19+
20+
1. **Add Programmatic API**: Add an importable class/module alongside the existing standalone server
21+
2. **Dependency Resolution**: Ensure Express dependencies are properly available when CLI is used
22+
3. **Flexible Configuration**: Support both environment-based config (platform) and runtime config (studio)
23+
4. **Lifecycle Management**: Provide start/stop methods for integration with CLI studio command
24+
5. **Port Management**: Support dynamic port assignment for concurrent studio sessions
25+
6. **Primary Use Case Preservation**: Maintain existing Express standalone functionality for platform usage
26+
27+
## Current Architecture Analysis
28+
29+
### Entry Point (`src/app.ts`)
30+
- **Main Structure**: Classic Express app with immediate execution
31+
- **Port**: Hardcoded to 3000
32+
- **Dependencies**: 11 runtime dependencies including `cookie-parser`, `cors`, `express`, `morgan`, `nano`
33+
- **Initialization**: Two-phase: server startup + async `init()` function
34+
- **Environment**: Relies on `src/utils/env.ts` for configuration via environment variables
35+
36+
### Configuration (`src/utils/env.ts`)
37+
- **Environment Variables**: Requires `COUCHDB_SERVER`, `COUCHDB_PROTOCOL`, `COUCHDB_ADMIN`, `COUCHDB_PASSWORD`, `VERSION`, `NODE_ENV`
38+
- **Data Layer**: Automatically initializes `@vue-skuilder/db` with CouchDB connection
39+
- **Dotenv**: Loads from `.env.development` by default
40+
41+
### Key Dependencies (package.json)
42+
**Runtime (11 deps):**
43+
- `express` - Web framework
44+
- `cookie-parser` - Cookie middleware
45+
- `cors` - CORS middleware
46+
- `morgan` - HTTP logging
47+
- `nano` - CouchDB client
48+
- `@vue-skuilder/common` - Shared types
49+
- `@vue-skuilder/db` - Database layer
50+
- `axios`, `ffmpeg-static`, `fs-extra`, `winston`, etc.
51+
52+
## Proposed Solution
53+
54+
### 1. Add Programmatic API Class
55+
56+
**Keep existing `src/app.ts` as-is** for platform usage, and **add** an exportable `SkuilderExpressServer` class:
57+
58+
```typescript
59+
export class SkuilderExpressServer {
60+
private app: Express;
61+
private server: http.Server | null = null;
62+
private port: number;
63+
64+
constructor(config: ExpressServerConfig) { ... }
65+
66+
async start(): Promise<{ port: number; url: string }> { ... }
67+
68+
async stop(): Promise<void> { ... }
69+
70+
isRunning(): boolean { ... }
71+
}
72+
```
73+
74+
### 2. Dual Configuration Support
75+
76+
**Add** programmatic configuration interface **alongside** existing environment-based config:
77+
78+
```typescript
79+
export interface ExpressServerConfig {
80+
port?: number; // Auto-assign if not provided
81+
couchdb: {
82+
protocol: string;
83+
server: string;
84+
username: string;
85+
password: string;
86+
};
87+
version: string;
88+
nodeEnv?: string;
89+
cors?: {
90+
credentials: boolean;
91+
origin: boolean | string | string[];
92+
};
93+
}
94+
```
95+
96+
### 3. CLI Integration
97+
98+
Update CLI's studio command to use the new API:
99+
100+
```typescript
101+
import { SkuilderExpressServer } from '@vue-skuilder/express';
102+
103+
// In studio command
104+
const expressServer = new SkuilderExpressServer({
105+
couchdb: {
106+
protocol: 'http',
107+
server: `localhost:${couchdbPort}`,
108+
username: 'admin',
109+
password: 'password'
110+
},
111+
version: VERSION,
112+
nodeEnv: 'studio'
113+
});
114+
115+
const { port, url } = await expressServer.start();
116+
console.log(`Express API running at ${url}`);
117+
```
118+
119+
### 4. Dependency Management
120+
121+
Add Express as a direct dependency in CLI's `package.json`:
122+
123+
```json
124+
{
125+
"dependencies": {
126+
"@vue-skuilder/express": "workspace:*",
127+
// ... other deps
128+
}
129+
}
130+
```
131+
132+
This ensures all Express dependencies are properly resolved through normal npm dependency tree.
133+
134+
## Entry/Exposure Points
135+
136+
### New Public API (src/index.ts)
137+
```typescript
138+
export { SkuilderExpressServer } from './server.js';
139+
export type { ExpressServerConfig } from './types.js';
140+
export { createExpressApp } from './app.js'; // For advanced users
141+
```
142+
143+
### New Files Added
144+
1. **src/server.ts** - New programmatic server class
145+
2. **src/types.ts** - Configuration interfaces
146+
3. **src/index.ts** - Main export file for programmatic usage
147+
148+
### Existing Files (Unchanged)
149+
- **src/app.ts** - Primary standalone server (platform usage)
150+
- **src/utils/env.ts** - Environment-based configuration (platform usage)
151+
- All other existing files maintain current functionality
152+
153+
### Dual Usage Support
154+
- **Platform usage**: `yarn dev` or `node dist/app.js` (unchanged)
155+
- **Studio usage**: `import { SkuilderExpressServer } from '@vue-skuilder/express'`
156+
157+
## Build Script Modifications
158+
159+
### Express Package Changes
160+
```json
161+
{
162+
"main": "dist/index.js",
163+
"types": "dist/index.d.ts",
164+
"exports": {
165+
".": {
166+
"types": "./dist/index.d.ts",
167+
"import": "./dist/index.js"
168+
},
169+
"./app": {
170+
"types": "./dist/app.d.ts",
171+
"import": "./dist/app.js"
172+
}
173+
}
174+
}
175+
```
176+
177+
### CLI Package Changes
178+
Remove embedding scripts:
179+
```json
180+
{
181+
"scripts": {
182+
"build": "rm -rf dist && tsc && npm run embed:studio-ui-src && npm run embed:templates && npm run embed:standalone-ui"
183+
}
184+
}
185+
```
186+
187+
Remove these lines:
188+
- `"build:express": "cd ../express && npm run build"`
189+
- `"embed:express": "mkdir -p dist/express-assets && cp -r ../express/dist/* dist/express-assets/ && cp -r ../express/assets dist/express-assets/"`
190+
191+
### Dependencies Update
192+
CLI package.json additions:
193+
```json
194+
{
195+
"dependencies": {
196+
"@vue-skuilder/express": "workspace:*"
197+
}
198+
}
199+
```
200+
201+
## Implementation Steps
202+
203+
1. **Create programmatic API** - Refactor app.ts into class-based architecture
204+
2. **Add configuration interface** - Replace env vars with config object
205+
3. **Update CLI integration** - Replace ExpressManager with direct API usage
206+
4. **Test in monorepo** - Ensure backwards compatibility
207+
5. **Update build scripts** - Remove embedding, add dependency
208+
6. **Test with npx** - Verify external project usage works
209+
7. **Update documentation** - Document new API and migration path
210+
211+
## Benefits
212+
213+
- **Cleaner Architecture**: Express becomes a proper Node.js module
214+
- **Better Dependency Resolution**: Standard npm dependency tree
215+
- **Reduced Bundle Size**: No more embedded assets in CLI
216+
- **Easier Maintenance**: Single source of truth for Express server
217+
- **Better Testability**: Programmatic API easier to test
218+
- **Flexible Configuration**: Runtime config vs environment vars

express-api-todo.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Express API Refactoring Todo
2+
3+
## Phase 1: Add Programmatic API (Foundation)
4+
5+
### 1.1 Create Configuration Interface
6+
- [x] Create `src/types.ts` with `ExpressServerConfig` interface
7+
- [x] Define configuration structure for CouchDB, ports, CORS, etc.
8+
- [x] Add TypeScript types for all configuration options
9+
10+
**Summary**: Created comprehensive type definitions including:
11+
- `ExpressServerConfig` - Main interface for programmatic usage with CouchDB config, optional port, version, nodeEnv, CORS settings
12+
- `EnvironmentConfig` - Internal bridge type for existing env var usage
13+
- `ServerStartResult` - Return type for server startup with port/URL info
14+
- Full JSDoc documentation for all interfaces and properties
15+
16+
### 1.2 Extract App Creation Logic
17+
- [x] **Keep existing `src/app.ts` unchanged** (platform usage)
18+
- [x] Create `src/app-factory.ts` with shared Express app creation logic
19+
- [x] Extract common app setup code from existing `src/app.ts`
20+
- [x] Ensure both standalone and programmatic modes use same logic
21+
22+
**Summary**: Created `app-factory.ts` with shared Express app creation logic:
23+
- `createExpressApp(config)` - Accepts both ExpressServerConfig and EnvironmentConfig
24+
- `initializeServices()` - Extracted async initialization logic for background services
25+
- Type guards to handle dual configuration formats (programmatic vs env vars)
26+
- Config conversion utilities to bridge between formats
27+
- All routes and middleware extracted from original app.ts
28+
- VueClientRequest interface moved to factory for shared usage
29+
30+
### 1.2b Refactor Existing App to Use Factory
31+
- [x] Refactor `src/app.ts` to use `createExpressApp()` from app-factory
32+
- [x] Replace duplicated middleware/routes with factory function call
33+
- [x] Use `initializeServices()` instead of inline init() function
34+
- [x] Ensure existing platform behavior unchanged
35+
- [x] Test that `yarn dev` still works correctly
36+
37+
**Summary**: Completely refactored standalone app.ts to eliminate duplication:
38+
- Reduced from ~264 lines to ~32 lines (87% reduction)
39+
- Uses `createExpressApp(ENV)` with environment config
40+
- Uses `initializeServices()` for background initialization
41+
- Preserves original port (3000), logging, and error handling behavior
42+
- Both modes now guaranteed to use identical Express configuration and routes
43+
44+
**Note**: This eliminates code duplication and ensures both standalone and programmatic modes use identical logic.
45+
46+
### 1.3 Révisée: Create Public API with Factory Functions
47+
- [x] Create `src/index.ts` as main package entry point
48+
- [x] Export `createExpressApp` and `initializeServices` functions
49+
- [x] Export type definitions (`ExpressServerConfig`, `VueClientRequest`, etc.)
50+
- [x] Update `package.json` main/types entries to point to index
51+
- [x] Add exports map for subpath compatibility (`./app` for standalone usage)
52+
- [x] Test build and verify API exports work correctly
53+
54+
**Summary**: Created clean factory-based public API:
55+
- Main entry: `src/index.ts` with `createExpressApp()` and `initializeServices()`
56+
- Type exports: `ExpressServerConfig`, `VueClientRequest`, `AppConfig`, `ServerStartResult`
57+
- Backwards compatibility: `./app` export for direct standalone server access
58+
- Package.json updated: main/types point to dist/index.js/d.ts
59+
- Build successful, dev mode still works correctly
60+
61+
### 1.4 Add Dual Configuration Support
62+
- [x] **Keep existing `src/utils/env.ts` unchanged** (platform usage)
63+
- [x] Add config object support to app factory
64+
- [x] Create utility to convert between env vars and config objects
65+
- [x] Ensure both configuration methods work with same app logic
66+
67+
**Summary**: Dual configuration already implemented in app-factory.ts:
68+
- `AppConfig` type accepts both `ExpressServerConfig` and `EnvironmentConfig`
69+
- Type guards (`isExpressServerConfig()`) distinguish between formats
70+
- `convertToEnvConfig()` utility bridges programmatic → environment format
71+
- Both standalone (env vars) and programmatic (config objects) modes supported
72+
73+
## Phase 2: Package Structure (Exports) ✅ COMPLETED
74+
75+
### 2.1 Create Main Export File
76+
- [x] Create `src/index.ts` as main package entry point
77+
- [x] Export factory functions (`createExpressApp`, `initializeServices`)
78+
- [x] Export type definitions (`ExpressServerConfig`, `VueClientRequest`, etc.)
79+
- [x] Export utility types for both programmatic and environment usage
80+
81+
### 2.2 Update Package Configuration
82+
- [x] Update `package.json` main entry to `dist/index.js`
83+
- [x] Update `package.json` types entry to `dist/index.d.ts`
84+
- [x] Add proper exports map for subpath exports
85+
- [x] Ensure backwards compatibility exports for `./app`
86+
87+
### 2.3 Platform Compatibility
88+
- [x] Verify existing `src/app.ts` standalone execution still works
89+
- [x] Preserve current `yarn dev` behavior for monorepo usage
90+
- [x] Test that existing platform Express usage unchanged
91+
92+
**Phase 2 Summary**: Package structure complete with clean exports and full backwards compatibility.
93+
94+
## Phase 3: CLI Integration (Remove Embedding)
95+
96+
### 3.1 Update CLI Dependencies
97+
- [ ] Add `@vue-skuilder/express` to CLI's `package.json` dependencies
98+
- [ ] Remove Express from devDependencies (it was in there for embedding)
99+
- [ ] Update CLI's TypeScript imports to use new API
100+
101+
### 3.2 Refactor Studio Command
102+
- [ ] Replace `ExpressManager` embedded approach with direct import
103+
- [ ] Update `src/commands/studio.ts` to use `SkuilderExpressServer`
104+
- [ ] Pass CouchDB configuration dynamically to Express server
105+
- [ ] Handle port assignment and URL reporting
106+
107+
### 3.3 Remove Embedding Infrastructure
108+
- [ ] Remove `embed:express` script from CLI's `package.json`
109+
- [ ] Remove `build:express` script from CLI's `package.json`
110+
- [ ] Update main build script to exclude Express embedding
111+
- [ ] Clean up `ExpressManager.js` utility (if no longer needed)
112+
113+
## Phase 4: Testing & Validation
114+
115+
### 4.1 Monorepo Testing
116+
- [ ] Test Express server directly: `yarn workspace @vue-skuilder/express dev`
117+
- [ ] Test CLI studio command in monorepo: `yarn studio`
118+
- [ ] Verify CouchDB integration still works
119+
- [ ] Verify all Express endpoints respond correctly
120+
121+
### 4.2 External Package Testing
122+
- [ ] Build and publish packages locally for testing
123+
- [ ] Test CLI via `npx` in external project directory
124+
- [ ] Verify `yarn studio` works without embedding errors
125+
- [ ] Test that all Express dependencies resolve correctly
126+
127+
### 4.3 Edge Case Testing
128+
- [ ] Test multiple concurrent studio sessions (port conflicts)
129+
- [ ] Test Express server shutdown and cleanup
130+
- [ ] Test error handling for invalid configurations
131+
- [ ] Verify memory leaks don't occur with start/stop cycles
132+
133+
## Phase 5: Documentation & Cleanup
134+
135+
### 5.1 Update Documentation
136+
- [ ] Update Express package `CLAUDE.md` with new API usage
137+
- [ ] Update CLI package `CLAUDE.md` with Express integration changes
138+
- [ ] Document migration path for any external users
139+
- [ ] Add JSDoc comments to public API methods
140+
141+
### 5.2 Code Cleanup
142+
- [ ] Remove old embedded Express assets from CLI dist
143+
- [ ] Clean up any unused utility files
144+
- [ ] Update TypeScript build configs if needed
145+
- [ ] Run linting and fix any issues
146+
147+
### 5.3 Version Management
148+
- [ ] Coordinate version bumps for both Express and CLI packages
149+
- [ ] Update `vtag.js` if needed for new dependency relationship
150+
- [ ] Test that version transformations still work correctly
151+
152+
## Success Criteria
153+
154+
- [ ] CLI can be used via `npx @vue-skuilder/cli studio` without dependency errors
155+
- [ ] Express server starts and stops programmatically via CLI
156+
- [ ] All existing Express API endpoints work correctly
157+
- [ ] Monorepo development workflow unchanged
158+
- [ ] No increase in CLI package size (should decrease)
159+
- [ ] Express server supports concurrent sessions with different ports
160+
- [ ] Studio mode workflow functions end-to-end

0 commit comments

Comments
 (0)