This document provides detailed technical documentation for the JSGUI3 Server framework. Read this when:
-
You need comprehensive API references and technical specifications Split Recommendation: This document (1346 lines) is very large and covers many topics. Consider splitting into focused documents:
-
Core API reference and examples
-
Advanced configuration and deployment
-
Control development guide
-
Troubleshooting and performance optimization
-
You're implementing advanced features or custom integrations
-
You want detailed examples of control creation and server configuration
-
You're troubleshooting complex issues or performance problems
-
You need to understand deployment, security, and production considerations
Note: Start with README.md for project overview and basic usage. For server API design principles, see docs/simple-server-api-design.md. For bundling internals and elimination strategy research, see docs/books/jsgui3-bundling-research-book/README.md.
JSGUI3 Server is a Node.js-based web server framework designed for serving modern JavaScript GUI applications built with the JSGUI3 library. It provides a complete runtime environment for delivering dynamic, component-based user interfaces with integrated data binding, event handling, and automatic CSS/JS bundling.
The server acts as a bridge between server-side JavaScript applications and browser clients, offering sophisticated component serving, data model management, real-time synchronization, and automatic resource bundling.
- Quick Start
- AI Agent Fast Start
- Architecture Overview
- Core Components
- Installation and Setup
- Configuration
- API Reference
- Examples
- Development
- Troubleshooting
- Deployment & Production
- Contributing
- Code Style Guidelines
- License
- Changelog
- Support
- Roadmap
- MVVM and Full-Stack Controls
// server.js
const Server = require('jsgui3-server');
const { MyControl } = require('./client').controls;
Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js')
});
// Server runs at http://localhost:8080Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js'),
port: 3000
});Server.serve({
pages: {
'/': {
content: HomeControl,
title: 'Home',
src_path_client_js: require.resolve('./client.js')
},
'/about': {
content: AboutControl,
title: 'About',
src_path_client_js: require.resolve('./client.js')
},
'/contact': {
content: ContactControl,
title: 'Contact',
src_path_client_js: require.resolve('./client.js')
}
},
port: 3000
});Server.serve({
ctrl: DashboardControl,
src_path_client_js: require.resolve('./client.js'),
api: {
'metrics': () => ({ users: 1234, revenue: 56789 }),
'data': async ({ range }) => await fetchAnalytics(range)
},
port: 3000
});This section is a short, task-oriented runway for AI agents that need to act quickly with minimal overhead.
Start here:
- Identify the target subsystem: examples, bundlers, publishers, or controls.
- Jump to the focused guide:
docs/books/jsgui3-mvvm-fullstack/README.md. - For bundle-size and pruning work, use:
docs/books/jsgui3-bundling-research-book/README.md. - Make the smallest change that can pass a targeted test.
- Run the narrow test file first, then widen if needed.
Minimal commands:
rg -n "needle" path/
rg --files path/
node tests/test-runner.js --test=examples-controls.e2e.test.js
node tests/test-runner.js --test=window-examples.puppeteer.test.jsKnown fast checks:
- Render server-side quickly with
Server_Static_Page_Context. - Confirm a control is exported under
jsgui.controls. - Ensure composition happens only when
!spec.el.
JSGUI3 Server follows a modular architecture with several key components:
- Server Core: Main HTTP server handling requests and responses
- Publishers: Specialized handlers for different content types (HTML, JS, CSS, images, etc.)
- Resources: Abstractions for accessing data sources (file system, databases, APIs)
- Bundlers: Tools for processing and optimizing client-side code
- Controls: Reusable UI components that can be served to browsers
JSGUI3 Server uses the fnl library for observable-based asynchronous programming. Unlike traditional Promises, fnl observables use an event-driven model:
// Observable pattern used throughout the codebase
const observable = someAsyncOperation();
observable.on({
next: (data) => {
// Handle data emission
console.log('Received:', data);
},
complete: (result) => {
// Handle completion
console.log('Operation complete:', result);
},
error: (err) => {
// Handle errors
console.error('Error:', err);
}
});
// Observables are also thenable (compatible with async/await)
const result = await observable;This pattern provides better control flow for complex asynchronous operations while maintaining compatibility with modern JavaScript async/await syntax.
- Client Request: Browser requests a page or resource
- Routing: Server determines appropriate publisher based on URL
- Resource Loading: Publisher accesses required resources (files, data, controls)
- Processing: Content is processed (bundling, rendering, etc.)
- Response: Formatted content is sent to client
Client Browser ↔ HTTP Server ↔ Publishers ↔ Resources ↔ Data Sources
↕
Bundlers/Processors
The main server class handles HTTP requests and coordinates between publishers and resources.
Key Methods:
start(port, callback): Start the HTTP serverpublish(route, handler): Add API endpointsuse(middleware): Add middleware functions
Publishers handle specific types of content:
- HTTP_Webpage_Publisher: Serves HTML pages with embedded controls
- HTTP_JS_Publisher: Serves JavaScript bundles
- HTTP_CSS_Publisher: Serves CSS stylesheets
- HTTP_Image_Publisher: Serves image files
- HTTP_API_Publisher: Handles API endpoints
Resources provide access to different data sources:
- File_System_Resource: Local file system access
- Database_Resource: Database connectivity
- API_Resource: External API integration
- Memory_Resource: In-memory data storage
Bundlers process and optimize client-side code:
- JS_Bundler: Combines and minifies JavaScript
- CSS_Bundler: Processes and optimizes CSS
- HTML_Bundler: Renders HTML templates
JSGUI3 provides a rich set of UI controls:
- Window: Draggable, resizable container
- Panel: Basic container control
- Button: Interactive button control
- Text_Input: Text input field
- Checkbox: Boolean input control
- Date_Picker: Date selection control
- Month_View: Calendar display
- Menu: Dropdown menu control
For a complete, step-by-step walkthrough of MVVM binding and full-stack control usage, use:
docs/books/jsgui3-mvvm-fullstack/README.md
const jsgui = require('jsgui3-client');
const { controls } = jsgui;
const Active_HTML_Document = require('jsgui3-server/controls/Active_HTML_Document');
class Demo_UI extends Active_HTML_Document {
constructor(spec = {}) {
spec.__type_name = spec.__type_name || 'demo_ui';
super(spec);
const { context } = this;
if (!spec.el) {
const window_ctrl = new controls.Window({
context,
title: 'Hello JSGUI3'
});
this.body.add(window_ctrl);
}
}
}
controls.Demo_UI = Demo_UI;
module.exports = jsgui;const Server = require('jsgui3-server');
const { Demo_UI } = require('./client').controls;
Server.serve({
ctrl: Demo_UI,
src_path_client_js: require.resolve('./client.js'),
port: 3000
});const jsgui = require('jsgui3-client');
const { controls, Control } = jsgui;
const set_model_value = (model, name, value) => {
if (!model) return;
if (typeof model.set === 'function') {
model.set(name, value);
} else {
model[name] = value;
}
};
class Profile_Panel extends Control {
constructor(spec = {}) {
spec.__type_name = spec.__type_name || 'profile_panel';
super(spec);
if (!spec.el) {
const { context } = this;
const name_input = new controls.Text_Input({ context });
this.add(name_input);
this.name_input = name_input;
}
this.setup_bindings();
}
setup_bindings() {
const data_model = this.data && this.data.model;
if (!data_model || !this.name_input) return;
this.watch(data_model, 'full_name', value => {
this.name_input.set_value(value || '');
});
this.name_input.on('input', () => {
set_model_value(data_model, 'full_name', this.name_input.get_value());
});
}
}
controls.Profile_Panel = Profile_Panel;
module.exports = jsgui;- Node.js >= 15.0.0
- npm or yarn package manager
npm install jsgui3-server- Create a client-side control:
// client.js
const jsgui = require('jsgui3-client');
const { controls, Control, mixins } = jsgui;
const Active_HTML_Document = require('jsgui3-server/controls/Active_HTML_Document');
class MyControl extends Active_HTML_Document {
constructor(spec = {}) {
spec.__type_name = spec.__type_name || 'my_control';
super(spec);
const { context } = this;
if (typeof this.body.add_class === 'function') {
this.body.add_class('my-control');
}
const compose = () => {
// Your UI composition logic here
const button = new controls.Button({
context,
text: 'Click Me'
});
this.body.add(button);
};
if (!spec.el) { compose(); }
}
activate() {
if (!this.__active) {
super.activate();
const { context } = this;
// Activation logic here
}
}
}
MyControl.css = `
* { margin: 0; padding: 0; }
body {
overflow-x: hidden;
overflow-y: hidden;
background-color: #E0E0E0;
}
.my-control {
padding: 20px;
background: #f0f0f0;
border: 1px solid #ccc;
}
`;
controls.MyControl = MyControl;
module.exports = jsgui;SCSS/SASS: You can also set `MyControl.scss` or `MyControl.sass` using template literals. These are compiled to CSS during bundling and removed from the JS output, just like `.css`. CSS and SCSS blocks can be mixed in a control; the bundler preserves their order during compilation. If you mix indented `.sass` with `.scss`/`.css`, each block is compiled independently to preserve order. Inline CSS sourcemaps are emitted only when a single compilation pass is used; mixed syntax skips inline maps to keep them accurate.
To enable inline CSS sourcemaps for Sass/SCSS outputs, pass a `style` configuration:
```javascript
Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js'),
debug: true,
style: {
sourcemaps: {
enabled: true,
inline: true,
include_sources: true
}
}
});
```
- Create server:
// server.js
const Server = require('jsgui3-server');
const { MyControl } = require('./client').controls;
Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js')
});- Start the server:
node server.jsPORT: Server port (default: 8080)HOST: Server host (default: all IPv4 interfaces)JSGUI_DEBUG: Enable debug mode (default: false)
const config = {
port: 3000,
host: 'localhost',
debug: true,
pages: {
'/': { content: HomeControl, title: 'Home' }
},
api: {
'status': () => ({ uptime: process.uptime() })
},
static: {
'/assets': './public'
}
};
Server.serve(config);Create jsgui.config.js:
module.exports = {
port: 3000,
pages: {
'/': require('./controls/home'),
'/about': require('./controls/about')
}
};Main entry point for starting the server.
Parameters:
options(object): Server configuration object
Options:
ctrlorCtrl: Main control class constructorpages: Object defining multiple pages with routes as keysapi: Object defining API endpointsresources: Object/array of managed resource definitionsevents: Enable/configure built-in SSE endpoint for resource lifecycle eventssrc_path_client_js: Path to client-side JavaScript fileport: Server port (default: 8080)host: Server host (default: all IPv4 interfaces)debug: Enable debug mode (default: false)
Returns: Promise that resolves to the server instance
Examples:
// Simple control serving
const server = await Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js'),
port: 3000
});
// Multi-page application
const server = await Server.serve({
pages: {
'/': {
content: HomeControl,
title: 'Home Page',
src_path_client_js: require.resolve('./client.js')
},
'/about': {
content: AboutControl,
title: 'About Page',
src_path_client_js: require.resolve('./client.js')
}
},
port: 3000
});
// With API endpoints
const server = await Server.serve({
ctrl: DashboardControl,
src_path_client_js: require.resolve('./client.js'),
api: {
'status': () => ({ uptime: process.uptime() }),
'users': async () => await getUsers()
},
port: 3000
});
// With managed resources and SSE lifecycle events
let server_with_resources;
server_with_resources = await Server.serve({
api: {
'resources/summary': () => server_with_resources.resource_pool.summary
},
resources: {
worker_direct: {
type: 'process',
command: process.execPath,
args: ['worker.js'],
autoRestart: true
},
worker_pm2: {
type: 'process',
processManager: { type: 'pm2' }, // pm2Path optional
command: process.execPath,
args: ['worker.js']
},
remote_worker: {
type: 'remote',
host: '127.0.0.1',
port: 3400
}
},
events: true // creates /events and forwards resource lifecycle events
});class CustomPublisher extends Publisher {
constructor(spec) {
super(spec);
}
serve(request, response) {
// Custom serving logic
}
}Based on the actual example in examples/controls/8) window, checkbox/a)/:
// client.js
const jsgui = require('jsgui3-client');
const { controls, Control, mixins } = jsgui;
const { dragable } = mixins;
const { Checkbox } = controls;
const Active_HTML_Document = require('jsgui3-server/controls/Active_HTML_Document');
class Demo_UI extends Active_HTML_Document {
constructor(spec = {}) {
spec.__type_name = spec.__type_name || 'demo_ui';
super(spec);
const { context } = this;
if (typeof this.body.add_class === 'function') {
this.body.add_class('demo-ui');
}
const compose = () => {
// Compose window with a checkbox control
const window = new controls.Window({
context,
title: 'JSGUI3 Checkbox Control',
pos: [10, 10]
});
const checkbox = new Checkbox({
context,
label: { text: 'A checkbox' }
});
window.inner.add(checkbox);
this.body.add(window);
};
if (!spec.el) { compose(); }
}
activate() {
if (!this.__active) {
super.activate();
const { context } = this;
// Handle window resize events
context.on('window-resize', e_resize => { });
}
}
}
Demo_UI.css = `
* { margin: 0; padding: 0; }
body {
overflow-x: hidden;
overflow-y: hidden;
background-color: #E0E0E0;
}
.demo-ui {
/* Control-specific styles */
}
`;
controls.Demo_UI = Demo_UI;
module.exports = jsgui;
// server.js - NEW SIMPLIFIED API (Recommended)
const Server = require('jsgui3-server');
// Auto-discovers client.js and control
Server.serve({ port: 52000 });
// server.js - LEGACY API (Still supported)
// Uncomment below and comment above for legacy usage
/*
const jsgui = require('./client');
const { Demo_UI } = jsgui.controls;
const Server = require('jsgui3-server');
if (require.main === module) {
const server = new Server({
Ctrl: Demo_UI,
src_path_client_js: require.resolve('./client.js')
});
console.log('waiting for server ready event');
server.on('ready', () => {
console.log('server ready');
server.start(52000, (err) => {
if (err) throw err;
console.log('server started');
});
});
}
*/Example with shared data models:
class DataBindingExample extends Active_HTML_Document {
constructor(spec = {}) {
spec.__type_name = spec.__type_name || 'data_binding_example';
super(spec);
const { context } = this;
if (typeof this.body.add_class === 'function') {
this.body.add_class('data-binding-example');
}
// Create shared data model
this.data = { model: new Data_Object({ context }) };
field(this.data.model, 'name');
field(this.data.model, 'email');
context.register_control(this.data.model);
const compose = () => {
// Create input controls bound to shared model
const nameInput = new controls.Text_Input({
context,
label: { text: 'Name:' },
data: { model: this.data.model, field_name: 'name' }
});
const emailInput = new controls.Text_Input({
context,
label: { text: 'Email:' },
data: { model: this.data.model, field_name: 'email' }
});
this.body.add(nameInput);
this.body.add(emailInput);
};
if (!spec.el) { compose(); }
}
activate() {
if (!this.__active) {
super.activate();
const { context } = this;
// Model synchronization logic can go here
}
}
}
DataBindingExample.css = `
* { margin: 0; padding: 0; }
body {
overflow-x: hidden;
overflow-y: hidden;
background-color: #E0E0E0;
}
.data-binding-example {
padding: 20px;
}
`;
controls.DataBindingExample = DataBindingExample;
module.exports = jsgui;// server.js with API - NEW SIMPLIFIED API
const Server = require('jsgui3-server');
Server.serve({
// Auto-discovers client.js and control
api: {
'users': async () => {
return await database.getUsers();
},
'metrics': () => ({
activeUsers: 1234,
totalRevenue: 56789,
serverUptime: process.uptime()
}),
'update': async ({ id, data }) => {
return await database.updateUser(id, data);
}
},
port: 3000
});
// API endpoints available at:
// GET/POST /api/users
// GET/POST /api/metrics
// GET/POST /api/update
// server.js - LEGACY API (Still supported)
// Uncomment below for legacy usage
/*
const Server = require('jsgui3-server');
const { DashboardControl } = require('./client').controls;
Server.serve({
ctrl: DashboardControl,
src_path_client_js: require.resolve('./client.js'),
api: {
'users': async () => {
return await database.getUsers();
},
'metrics': () => ({
activeUsers: 1234,
totalRevenue: 56789,
serverUptime: process.uptime()
}),
'update': async ({ id, data }) => {
return await database.updateUser(id, data);
}
},
port: 3000
});
*/jsgui3-server/
├── cli.js # Command-line interface
├── server.js # Main server implementation
├── module.js # Module exports
├── controls/ # UI control classes
├── publishers/ # Content publishers
├── resources/ # Data resource handlers
├── bundlers/ # Code bundling utilities
├── examples/ # Example applications
├── tests/ # Test suites
└── docs/ # Documentation
-
Setup Development Environment
git clone https://github.com/metabench/jsgui3-server.git cd jsgui3-server npm install -
Run Tests
npm test -
Start Development Server
npm run serve
-
Run CLI
npm run cli
# Start server
node cli.js serve --port 3000
# Show help
node cli.js --help
# Show version
node cli.js --versionThe project uses Mocha for testing:
# Run all tests
npm test
# Run specific test file
npx mocha tests/cli.test.js
# Run with coverage
npx nyc npm test- Use
snake_casefor variables, functions, and utilities - Use
PascalCasefor classes and constructors - Follow existing patterns for control creation and lifecycle
- Include comprehensive error handling
- Add JSDoc comments for public APIs
-
Build Optimization
# Enable production bundling NODE_ENV=production node server.js -
Environment Configuration
PORT=80 HOST=0.0.0.0 node server.js
-
Process Management
# Using PM2 npm install -g pm2 pm2 start server.js --name jsgui3-server
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8080
CMD ["node", "server.js"]// server.js
const port = process.env.PORT || 8080;
Server.serve({ ctrl: MyControl, port });// api/server.js
const Server = require('jsgui3-server');
module.exports = (req, res) => {
// Handle Vercel serverless function
};Problem: Port already in use Solution:
# Find process using port (Linux/macOS)
lsof -i :8080
# Find process using port (Windows)
netstat -ano | findstr :8080
# Kill process or use different port
PORT=3000 node server.jsProblem: Missing client.js file
Solution: Ensure src_path_client_js points to a valid file:
Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js') // Must resolve to actual file
});Problem: CSS or JavaScript not loading Solution:
- Check browser developer tools for 404 errors
- Ensure bundling completed successfully (look for "server ready" message)
- Verify control CSS is properly defined as static property
Problem: Control constructor errors Solution: Check server logs for JavaScript errors in control initialization
Problem: Incorrect route configuration Solution:
- API routes are automatically prefixed with
/api/ - Verify function returns correct data type (object/array for JSON, string for text)
- Check server logs for routing errors
Problem: Async API functions not working Solution: Ensure async functions are properly awaited:
api: {
'data': async () => {
return await someAsyncOperation(); // Must return Promise
}
}Problem: ESBuild bundling fails Solution:
- Check for syntax errors in client.js
- Ensure all dependencies are properly installed
- Try with
debug: truefor more detailed error messages
Problem: CSS extraction issues Solution: Verify control classes have proper CSS static properties
Enable debug mode for detailed logging:
JSGUI_DEBUG=1 node server.jsOr in code:
Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js'),
debug: true
});The server provides comprehensive logging:
- Server startup: Bundling progress and server initialization
- Request handling: HTTP requests and responses
- Bundling: ESBuild compilation status
- Errors: Detailed error messages and stack traces
Problem: Slow server startup Solution:
- Bundling is the most time-consuming part
- Use debug mode sparingly (disables minification)
- Cache bundled assets in production
Problem: High memory usage Solution:
- Monitor for memory leaks in controls
- Use
context.register_control()properly for cleanup - Avoid large data models in memory
For development, you may need to restart the server when changing controls. The server doesn't currently support hot reloading.
// Add debug logging to controls
class MyControl extends Active_HTML_Document {
constructor(spec = {}) {
super(spec);
console.log('Control created:', spec);
// Add debugging to activation
this.activate = () => {
console.log('Control activating');
// ... rest of activation logic
};
}
}- Use browser dev tools to inspect generated HTML/CSS/JS
- Check Network tab for failed asset requests
- Use Console tab for client-side JavaScript errors
- Source maps are available in debug mode for easier debugging
# Production settings
NODE_ENV=production
PORT=80
JSGUI_DEBUG=0
# SSL/TLS (if using HTTPS)
SSL_KEY_PATH=/path/to/ssl/key.pem
SSL_CERT_PATH=/path/to/ssl/cert.pemconst server = Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js'),
port: process.env.PORT || 80,
debug: false, // Disable for production
// Additional production settings
max_age: 86400, // Cache static assets for 24 hours
compression: true // Enable gzip/deflate/brotli compression
});# Install PM2
npm install -g pm2
# Start server with PM2
pm2 start server.js --name "jsgui3-server"
# Save PM2 configuration
pm2 save
# Set up auto-restart
pm2 startupCreate ecosystem.config.js:
module.exports = {
apps: [{
name: 'jsgui3-server',
script: 'server.js',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
PORT: 80
},
env_production: {
NODE_ENV: 'production',
PORT: 80
}
}]
};FROM node:18-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
RUN npm ci --only=production
# Copy application code
COPY . .
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S jsgui -u 1001
USER jsgui
EXPOSE 8080
CMD ["node", "server.js"]version: '3.8'
services:
jsgui3-server:
build: .
ports:
- "80:8080"
environment:
- NODE_ENV=production
restart: unless-stoppedserver {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}<VirtualHost *:80>
ServerName your-domain.com
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
# WebSocket support
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]
</VirtualHost># Install Certbot
sudo apt install certbot
# Get SSL certificate
sudo certbot certonly --webroot -w /var/www/html -d your-domain.com
# Configure server for HTTPS
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('/etc/letsencrypt/live/your-domain.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/your-domain.com/fullchain.pem')
};
const server = Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js'),
https: options
});// Add health check to your control
class MyControl extends Active_HTML_Document {
static api = {
'health': () => ({
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime()
})
};
}# Using PM2
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js'),
// Cache static assets
max_age: 86400, // 24 hours
// Enable compression (gzip/deflate/brotli via built-in middleware)
compression: true,
// Optimize bundling
debug: false
});If using databases, implement connection pooling:
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'user',
password: 'password',
database: 'mydb',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// Use in API functions
static api = {
'data': async () => {
const [rows] = await pool.execute('SELECT * FROM table');
return rows;
}
};static api = {
'user': async (params) => {
// Validate input
if (!params.id || typeof params.id !== 'number') {
throw new Error('Invalid user ID');
}
// Sanitize data
const userId = Math.floor(params.id);
return await getUserById(userId);
}
};Implement rate limiting for API endpoints:
const rateLimit = require('express-rate-limit');
// In your server setup
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
// Apply to API routes (requires custom integration)Server.serve({
ctrl: MyControl,
src_path_client_js: require.resolve('./client.js'),
cors: {
origin: ['https://yourdomain.com'],
methods: ['GET', 'POST'],
credentials: true
}
});- Fork the repository
- Clone your fork
- Install dependencies:
npm install - Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run tests:
npm test - Submit a pull request
- Follow existing code style and patterns
- Add tests for new features
- Update documentation as needed
- Ensure backwards compatibility
- Use meaningful commit messages
- Write unit tests for new functionality
- Ensure all existing tests pass
- Test on multiple Node.js versions
- Include integration tests for complex features
- Update README for API changes
- Add JSDoc comments for new methods
- Include examples for new features
- Update changelog for releases
Following the agent guidelines in AGENTS.md:
- Variables, functions, and helper utilities: Use
snake_case - Classes and constructors: Use
PascalCase(also calledSnake_Casein the guidelines)
Examples:
// Correct
class My_Custom_Class {
constructor(spec = {}) {
this.some_variable = spec.some_variable;
this.another_helper_function();
}
some_method() {
// method implementation
}
}
function helper_utility_function() {
// utility function
}
// Avoid
class my_custom_class { // Wrong: should be PascalCase
constructor() {
this.SomeVariable = null; // Wrong: should be snake_case
}
}When creating new controls, follow these patterns:
const jsgui = require('jsgui3-client');
const { controls, Control, Data_Object, field } = jsgui;
const Active_HTML_Document = require('jsgui3-server/controls/Active_HTML_Document');
class My_Custom_Control extends Active_HTML_Document {
constructor(spec = {}) {
spec.__type_name = spec.__type_name || 'my_custom_control';
super(spec);
const { context } = this;
// Defensive programming
if (typeof this.body.add_class === 'function') {
this.body.add_class('my-custom-control');
}
const compose = () => {
// UI composition logic
};
if (!spec.el) { compose(); }
}
activate() {
if (!this.__active) {
super.activate();
const { context } = this;
// Activation logic
}
}
}
My_Custom_Control.css = `
/* CSS styles */
`;
controls.My_Custom_Control = My_Custom_Control;
module.exports = jsgui;- Use JSDoc comments for all public methods and classes
- Document parameters, return values, and thrown exceptions
- Include code examples where helpful
- Reference related functions and classes
- Use defensive programming techniques
- Provide meaningful error messages
- Handle asynchronous errors properly
- Log errors appropriately for debugging
For comprehensive guidance on agentic workflows and development practices, see:
AGENTS.md- Agent guidelines and naming conventionsdocs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md- Complete guide to autonomous task execution
MIT License - see LICENSE file for details.
- Enhanced server API with
Server.serve()method - Improved CSS extraction and bundling
- Added comprehensive CLI interface
- Fixed source map consistency issues
- Bug fixes and stability improvements
- Enhanced publisher system
- Improved error handling
- Server function publishing improvements
- Better JSON API support
- Enhanced resource management
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Project Wiki
- CLI improvements and reliability
- Admin interface development
- Enhanced control suite
- Documentation and examples
- File manager interface
- Deployment workflows
- Advanced bundling options
- Performance optimizations
This documentation provides a comprehensive overview of JSGUI3 Server. For more detailed information about specific components, see the individual files in the docs/ directory and the examples in examples/.
c:\Users\james\Documents\repos\jsgui3-server\docs\comprehensive-documentation.md