Skip to content

Commit fb520b9

Browse files
committed
add express-api config types
1 parent fe485bb commit fb520b9

File tree

4 files changed

+399
-1
lines changed

4 files changed

+399
-1
lines changed

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: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
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+
- [ ] **Keep existing `src/app.ts` unchanged** (platform usage)
18+
- [ ] Create `src/app-factory.ts` with shared Express app creation logic
19+
- [ ] Extract common app setup code from existing `src/app.ts`
20+
- [ ] Ensure both standalone and programmatic modes use same logic
21+
22+
### 1.3 Create Programmatic Server Class
23+
- [ ] Create `src/server.ts` with `SkuilderExpressServer` class
24+
- [ ] Implement constructor accepting `ExpressServerConfig`
25+
- [ ] Add `start()` method returning `{ port: number; url: string }`
26+
- [ ] Add `stop()` method for graceful shutdown
27+
- [ ] Add `isRunning()` status method
28+
- [ ] Handle port auto-assignment if not specified
29+
30+
### 1.4 Add Dual Configuration Support
31+
- [ ] **Keep existing `src/utils/env.ts` unchanged** (platform usage)
32+
- [ ] Add config object support to app factory
33+
- [ ] Create utility to convert between env vars and config objects
34+
- [ ] Ensure both configuration methods work with same app logic
35+
36+
## Phase 2: Package Structure (Exports)
37+
38+
### 2.1 Create Main Export File
39+
- [ ] Create `src/index.ts` as main package entry point
40+
- [ ] Export `SkuilderExpressServer` class
41+
- [ ] Export `ExpressServerConfig` type
42+
- [ ] Export `createExpressApp` function for advanced usage
43+
44+
### 2.2 Update Package Configuration
45+
- [ ] Update `package.json` main entry to `dist/index.js`
46+
- [ ] Update `package.json` types entry to `dist/index.d.ts`
47+
- [ ] Add proper exports map for subpath exports
48+
- [ ] Ensure backwards compatibility exports for `./app`
49+
50+
### 2.3 Platform Compatibility
51+
- [ ] Verify existing `src/app.ts` standalone execution still works
52+
- [ ] Preserve current `yarn dev` behavior for monorepo usage
53+
- [ ] Test that existing platform Express usage unchanged
54+
55+
## Phase 3: CLI Integration (Remove Embedding)
56+
57+
### 3.1 Update CLI Dependencies
58+
- [ ] Add `@vue-skuilder/express` to CLI's `package.json` dependencies
59+
- [ ] Remove Express from devDependencies (it was in there for embedding)
60+
- [ ] Update CLI's TypeScript imports to use new API
61+
62+
### 3.2 Refactor Studio Command
63+
- [ ] Replace `ExpressManager` embedded approach with direct import
64+
- [ ] Update `src/commands/studio.ts` to use `SkuilderExpressServer`
65+
- [ ] Pass CouchDB configuration dynamically to Express server
66+
- [ ] Handle port assignment and URL reporting
67+
68+
### 3.3 Remove Embedding Infrastructure
69+
- [ ] Remove `embed:express` script from CLI's `package.json`
70+
- [ ] Remove `build:express` script from CLI's `package.json`
71+
- [ ] Update main build script to exclude Express embedding
72+
- [ ] Clean up `ExpressManager.js` utility (if no longer needed)
73+
74+
## Phase 4: Testing & Validation
75+
76+
### 4.1 Monorepo Testing
77+
- [ ] Test Express server directly: `yarn workspace @vue-skuilder/express dev`
78+
- [ ] Test CLI studio command in monorepo: `yarn studio`
79+
- [ ] Verify CouchDB integration still works
80+
- [ ] Verify all Express endpoints respond correctly
81+
82+
### 4.2 External Package Testing
83+
- [ ] Build and publish packages locally for testing
84+
- [ ] Test CLI via `npx` in external project directory
85+
- [ ] Verify `yarn studio` works without embedding errors
86+
- [ ] Test that all Express dependencies resolve correctly
87+
88+
### 4.3 Edge Case Testing
89+
- [ ] Test multiple concurrent studio sessions (port conflicts)
90+
- [ ] Test Express server shutdown and cleanup
91+
- [ ] Test error handling for invalid configurations
92+
- [ ] Verify memory leaks don't occur with start/stop cycles
93+
94+
## Phase 5: Documentation & Cleanup
95+
96+
### 5.1 Update Documentation
97+
- [ ] Update Express package `CLAUDE.md` with new API usage
98+
- [ ] Update CLI package `CLAUDE.md` with Express integration changes
99+
- [ ] Document migration path for any external users
100+
- [ ] Add JSDoc comments to public API methods
101+
102+
### 5.2 Code Cleanup
103+
- [ ] Remove old embedded Express assets from CLI dist
104+
- [ ] Clean up any unused utility files
105+
- [ ] Update TypeScript build configs if needed
106+
- [ ] Run linting and fix any issues
107+
108+
### 5.3 Version Management
109+
- [ ] Coordinate version bumps for both Express and CLI packages
110+
- [ ] Update `vtag.js` if needed for new dependency relationship
111+
- [ ] Test that version transformations still work correctly
112+
113+
## Success Criteria
114+
115+
- [ ] CLI can be used via `npx @vue-skuilder/cli studio` without dependency errors
116+
- [ ] Express server starts and stops programmatically via CLI
117+
- [ ] All existing Express API endpoints work correctly
118+
- [ ] Monorepo development workflow unchanged
119+
- [ ] No increase in CLI package size (should decrease)
120+
- [ ] Express server supports concurrent sessions with different ports
121+
- [ ] Studio mode workflow functions end-to-end

0 commit comments

Comments
 (0)