jsgui3-server 0.0.138 → 0.0.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +87 -0
- package/README.md +12 -0
- package/docs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md +19 -0
- package/docs/advanced-usage-examples.md +1360 -0
- package/docs/agent-development-guide.md +386 -0
- package/docs/api-reference.md +916 -0
- package/docs/broken-functionality-tracker.md +285 -0
- package/docs/bundling-system-deep-dive.md +525 -0
- package/docs/cli-reference.md +393 -0
- package/docs/comprehensive-documentation.md +1403 -0
- package/docs/configuration-reference.md +808 -0
- package/docs/controls-development.md +859 -0
- package/docs/documentation-review/CURRENT_REVIEW.md +95 -0
- package/docs/function-publishers-json-apis.md +847 -0
- package/docs/getting-started-with-json.md +518 -0
- package/docs/minification-compression-sourcemaps-status.md +482 -0
- package/docs/minification-compression-sourcemaps-test-results.md +205 -0
- package/docs/publishers-guide.md +313 -0
- package/docs/resources-guide.md +615 -0
- package/docs/serve-helpers.md +406 -0
- package/docs/simple-server-api-design.md +13 -0
- package/docs/system-architecture.md +275 -0
- package/docs/troubleshooting.md +698 -0
- package/examples/json/README.md +115 -0
- package/examples/json/basic-api/README.md +345 -0
- package/examples/json/basic-api/server.js +199 -0
- package/examples/json/simple-api/README.md +125 -0
- package/examples/json/simple-api/diagnostic-report.json +73 -0
- package/examples/json/simple-api/diagnostic-test.js +433 -0
- package/examples/json/simple-api/server-debug.md +58 -0
- package/examples/json/simple-api/server.js +91 -0
- package/examples/json/simple-api/test.js +215 -0
- package/http/responders/static/Static_Route_HTTP_Responder.js +1 -2
- package/package.json +19 -8
- package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +65 -12
- package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +6 -1
- package/publishers/http-function-publisher.js +59 -38
- package/publishers/http-webpage-publisher.js +48 -1
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +38 -146
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +54 -5
- package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +36 -4
- package/serve-factory.js +36 -9
- package/server.js +10 -4
- package/test-report.json +0 -0
- package/tests/README.md +250 -0
- package/tests/assigners.test.js +316 -0
- package/tests/bundlers.test.js +329 -0
- package/tests/configuration-validation.test.js +530 -0
- package/tests/content-analysis.test.js +641 -0
- package/tests/end-to-end.test.js +496 -0
- package/tests/error-handling.test.js +746 -0
- package/tests/performance.test.js +653 -0
- package/tests/publishers.test.js +395 -0
- package/tests/temp_invalid.js +7 -0
- package/tests/temp_invalid_utf8.js +1 -0
- package/tests/temp_malformed.js +10 -0
- package/tests/test-runner.js +261 -0
|
@@ -0,0 +1,1403 @@
|
|
|
1
|
+
# JSGUI3 Server - Comprehensive Documentation
|
|
2
|
+
|
|
3
|
+
## When to Read
|
|
4
|
+
|
|
5
|
+
This document provides detailed technical documentation for the JSGUI3 Server framework. Read this when:
|
|
6
|
+
- You need comprehensive API references and technical specifications
|
|
7
|
+
**Split Recommendation:** This document (1346 lines) is very large and covers many topics. Consider splitting into focused documents:
|
|
8
|
+
- Core API reference and examples
|
|
9
|
+
- Advanced configuration and deployment
|
|
10
|
+
- Control development guide
|
|
11
|
+
- Troubleshooting and performance optimization
|
|
12
|
+
|
|
13
|
+
- You're implementing advanced features or custom integrations
|
|
14
|
+
- You want detailed examples of control creation and server configuration
|
|
15
|
+
- You're troubleshooting complex issues or performance problems
|
|
16
|
+
- You need to understand deployment, security, and production considerations
|
|
17
|
+
|
|
18
|
+
**Note:** Start with [README.md](../README.md) for project overview and basic usage. For server API design principles, see [docs/simple-server-api-design.md](docs/simple-server-api-design.md).
|
|
19
|
+
|
|
20
|
+
# JSGUI3 Server - Comprehensive Documentation
|
|
21
|
+
|
|
22
|
+
## Overview
|
|
23
|
+
|
|
24
|
+
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.
|
|
25
|
+
|
|
26
|
+
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.
|
|
27
|
+
|
|
28
|
+
## Table of Contents
|
|
29
|
+
|
|
30
|
+
1. [Quick Start](#quick-start)
|
|
31
|
+
2. [Architecture Overview](#architecture-overview)
|
|
32
|
+
3. [Core Components](#core-components)
|
|
33
|
+
4. [Installation and Setup](#installation-and-setup)
|
|
34
|
+
5. [Configuration](#configuration)
|
|
35
|
+
6. [API Reference](#api-reference)
|
|
36
|
+
7. [Examples](#examples)
|
|
37
|
+
8. [Development](#development)
|
|
38
|
+
9. [Troubleshooting](#troubleshooting)
|
|
39
|
+
10. [Deployment & Production](#deployment--production)
|
|
40
|
+
11. [Contributing](#contributing)
|
|
41
|
+
12. [Code Style Guidelines](#code-style-guidelines)
|
|
42
|
+
13. [License](#license)
|
|
43
|
+
14. [Changelog](#changelog)
|
|
44
|
+
15. [Support](#support)
|
|
45
|
+
16. [Roadmap](#roadmap)
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
### Minimal Server Setup
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
// server.js
|
|
53
|
+
const Server = require('jsgui3-server');
|
|
54
|
+
const { MyControl } = require('./client').controls;
|
|
55
|
+
|
|
56
|
+
Server.serve({
|
|
57
|
+
ctrl: MyControl,
|
|
58
|
+
src_path_client_js: require.resolve('./client.js')
|
|
59
|
+
});
|
|
60
|
+
// Server runs at http://localhost:8080
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### With Port Configuration
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
Server.serve({
|
|
67
|
+
ctrl: MyControl,
|
|
68
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
69
|
+
port: 3000
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Multi-Page Application
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
Server.serve({
|
|
77
|
+
pages: {
|
|
78
|
+
'/': {
|
|
79
|
+
content: HomeControl,
|
|
80
|
+
title: 'Home',
|
|
81
|
+
src_path_client_js: require.resolve('./client.js')
|
|
82
|
+
},
|
|
83
|
+
'/about': {
|
|
84
|
+
content: AboutControl,
|
|
85
|
+
title: 'About',
|
|
86
|
+
src_path_client_js: require.resolve('./client.js')
|
|
87
|
+
},
|
|
88
|
+
'/contact': {
|
|
89
|
+
content: ContactControl,
|
|
90
|
+
title: 'Contact',
|
|
91
|
+
src_path_client_js: require.resolve('./client.js')
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
port: 3000
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### With API Endpoints
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
Server.serve({
|
|
102
|
+
ctrl: DashboardControl,
|
|
103
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
104
|
+
api: {
|
|
105
|
+
'metrics': () => ({ users: 1234, revenue: 56789 }),
|
|
106
|
+
'data': async ({ range }) => await fetchAnalytics(range)
|
|
107
|
+
},
|
|
108
|
+
port: 3000
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Architecture Overview
|
|
113
|
+
|
|
114
|
+
### Core Architecture
|
|
115
|
+
|
|
116
|
+
JSGUI3 Server follows a modular architecture with several key components:
|
|
117
|
+
|
|
118
|
+
- **Server Core**: Main HTTP server handling requests and responses
|
|
119
|
+
- **Publishers**: Specialized handlers for different content types (HTML, JS, CSS, images, etc.)
|
|
120
|
+
- **Resources**: Abstractions for accessing data sources (file system, databases, APIs)
|
|
121
|
+
- **Bundlers**: Tools for processing and optimizing client-side code
|
|
122
|
+
- **Controls**: Reusable UI components that can be served to browsers
|
|
123
|
+
|
|
124
|
+
### Asynchronous Programming Model
|
|
125
|
+
|
|
126
|
+
JSGUI3 Server uses the `fnl` library for observable-based asynchronous programming. Unlike traditional Promises, `fnl` observables use an event-driven model:
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
// Observable pattern used throughout the codebase
|
|
130
|
+
const observable = someAsyncOperation();
|
|
131
|
+
observable.on({
|
|
132
|
+
next: (data) => {
|
|
133
|
+
// Handle data emission
|
|
134
|
+
console.log('Received:', data);
|
|
135
|
+
},
|
|
136
|
+
complete: (result) => {
|
|
137
|
+
// Handle completion
|
|
138
|
+
console.log('Operation complete:', result);
|
|
139
|
+
},
|
|
140
|
+
error: (err) => {
|
|
141
|
+
// Handle errors
|
|
142
|
+
console.error('Error:', err);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Observables are also thenable (compatible with async/await)
|
|
147
|
+
const result = await observable;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
This pattern provides better control flow for complex asynchronous operations while maintaining compatibility with modern JavaScript async/await syntax.
|
|
151
|
+
|
|
152
|
+
### Request Flow
|
|
153
|
+
|
|
154
|
+
1. **Client Request**: Browser requests a page or resource
|
|
155
|
+
2. **Routing**: Server determines appropriate publisher based on URL
|
|
156
|
+
3. **Resource Loading**: Publisher accesses required resources (files, data, controls)
|
|
157
|
+
4. **Processing**: Content is processed (bundling, rendering, etc.)
|
|
158
|
+
5. **Response**: Formatted content is sent to client
|
|
159
|
+
|
|
160
|
+
### Data Flow
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Client Browser ↔ HTTP Server ↔ Publishers ↔ Resources ↔ Data Sources
|
|
164
|
+
↕
|
|
165
|
+
Bundlers/Processors
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Core Components
|
|
169
|
+
|
|
170
|
+
### Server Class
|
|
171
|
+
|
|
172
|
+
The main server class handles HTTP requests and coordinates between publishers and resources.
|
|
173
|
+
|
|
174
|
+
**Key Methods:**
|
|
175
|
+
- `start(port, callback)`: Start the HTTP server
|
|
176
|
+
- `publish(route, handler)`: Add API endpoints
|
|
177
|
+
- `use(middleware)`: Add middleware functions
|
|
178
|
+
|
|
179
|
+
### Publishers
|
|
180
|
+
|
|
181
|
+
Publishers handle specific types of content:
|
|
182
|
+
|
|
183
|
+
- **HTTP_Webpage_Publisher**: Serves HTML pages with embedded controls
|
|
184
|
+
- **HTTP_JS_Publisher**: Serves JavaScript bundles
|
|
185
|
+
- **HTTP_CSS_Publisher**: Serves CSS stylesheets
|
|
186
|
+
- **HTTP_Image_Publisher**: Serves image files
|
|
187
|
+
- **HTTP_API_Publisher**: Handles API endpoints
|
|
188
|
+
|
|
189
|
+
### Resources
|
|
190
|
+
|
|
191
|
+
Resources provide access to different data sources:
|
|
192
|
+
|
|
193
|
+
- **File_System_Resource**: Local file system access
|
|
194
|
+
- **Database_Resource**: Database connectivity
|
|
195
|
+
- **API_Resource**: External API integration
|
|
196
|
+
- **Memory_Resource**: In-memory data storage
|
|
197
|
+
|
|
198
|
+
### Bundlers
|
|
199
|
+
|
|
200
|
+
Bundlers process and optimize client-side code:
|
|
201
|
+
|
|
202
|
+
- **JS_Bundler**: Combines and minifies JavaScript
|
|
203
|
+
- **CSS_Bundler**: Processes and optimizes CSS
|
|
204
|
+
- **HTML_Bundler**: Renders HTML templates
|
|
205
|
+
|
|
206
|
+
### Controls
|
|
207
|
+
|
|
208
|
+
JSGUI3 provides a rich set of UI controls:
|
|
209
|
+
|
|
210
|
+
- **Window**: Draggable, resizable container
|
|
211
|
+
- **Panel**: Basic container control
|
|
212
|
+
- **Button**: Interactive button control
|
|
213
|
+
- **Text_Input**: Text input field
|
|
214
|
+
- **Checkbox**: Boolean input control
|
|
215
|
+
- **Date_Picker**: Date selection control
|
|
216
|
+
- **Month_View**: Calendar display
|
|
217
|
+
- **Menu**: Dropdown menu control
|
|
218
|
+
|
|
219
|
+
## Installation and Setup
|
|
220
|
+
|
|
221
|
+
### Prerequisites
|
|
222
|
+
|
|
223
|
+
- Node.js >= 15.0.0
|
|
224
|
+
- npm or yarn package manager
|
|
225
|
+
|
|
226
|
+
### Installation
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
npm install jsgui3-server
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Basic Setup
|
|
233
|
+
|
|
234
|
+
1. Create a client-side control:
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
// client.js
|
|
238
|
+
const jsgui = require('jsgui3-client');
|
|
239
|
+
const { controls, Control, mixins } = jsgui;
|
|
240
|
+
const Active_HTML_Document = require('jsgui3-server/controls/Active_HTML_Document');
|
|
241
|
+
|
|
242
|
+
class MyControl extends Active_HTML_Document {
|
|
243
|
+
constructor(spec = {}) {
|
|
244
|
+
spec.__type_name = spec.__type_name || 'my_control';
|
|
245
|
+
super(spec);
|
|
246
|
+
const { context } = this;
|
|
247
|
+
|
|
248
|
+
if (typeof this.body.add_class === 'function') {
|
|
249
|
+
this.body.add_class('my-control');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const compose = () => {
|
|
253
|
+
// Your UI composition logic here
|
|
254
|
+
const button = new controls.Button({
|
|
255
|
+
context,
|
|
256
|
+
text: 'Click Me'
|
|
257
|
+
});
|
|
258
|
+
this.body.add(button);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
if (!spec.el) { compose(); }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
activate() {
|
|
265
|
+
if (!this.__active) {
|
|
266
|
+
super.activate();
|
|
267
|
+
const { context } = this;
|
|
268
|
+
// Activation logic here
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
MyControl.css = `
|
|
274
|
+
* { margin: 0; padding: 0; }
|
|
275
|
+
body {
|
|
276
|
+
overflow-x: hidden;
|
|
277
|
+
overflow-y: hidden;
|
|
278
|
+
background-color: #E0E0E0;
|
|
279
|
+
}
|
|
280
|
+
.my-control {
|
|
281
|
+
padding: 20px;
|
|
282
|
+
background: #f0f0f0;
|
|
283
|
+
border: 1px solid #ccc;
|
|
284
|
+
}
|
|
285
|
+
`;
|
|
286
|
+
|
|
287
|
+
controls.MyControl = MyControl;
|
|
288
|
+
module.exports = jsgui;
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
2. Create server:
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
// server.js
|
|
295
|
+
const Server = require('jsgui3-server');
|
|
296
|
+
const { MyControl } = require('./client').controls;
|
|
297
|
+
|
|
298
|
+
Server.serve({
|
|
299
|
+
ctrl: MyControl,
|
|
300
|
+
src_path_client_js: require.resolve('./client.js')
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
3. Start the server:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
node server.js
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Configuration
|
|
311
|
+
|
|
312
|
+
### Environment Variables
|
|
313
|
+
|
|
314
|
+
- `PORT`: Server port (default: 8080)
|
|
315
|
+
- `HOST`: Server host (default: all IPv4 interfaces)
|
|
316
|
+
- `JSGUI_DEBUG`: Enable debug mode (default: false)
|
|
317
|
+
|
|
318
|
+
### Configuration Object
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
const config = {
|
|
322
|
+
port: 3000,
|
|
323
|
+
host: 'localhost',
|
|
324
|
+
debug: true,
|
|
325
|
+
pages: {
|
|
326
|
+
'/': { content: HomeControl, title: 'Home' }
|
|
327
|
+
},
|
|
328
|
+
api: {
|
|
329
|
+
'status': () => ({ uptime: process.uptime() })
|
|
330
|
+
},
|
|
331
|
+
static: {
|
|
332
|
+
'/assets': './public'
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
Server.serve(config);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Configuration File
|
|
340
|
+
|
|
341
|
+
Create `jsgui.config.js`:
|
|
342
|
+
|
|
343
|
+
```javascript
|
|
344
|
+
module.exports = {
|
|
345
|
+
port: 3000,
|
|
346
|
+
pages: {
|
|
347
|
+
'/': require('./controls/home'),
|
|
348
|
+
'/about': require('./controls/about')
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## API Reference
|
|
354
|
+
|
|
355
|
+
### Server.serve(options)
|
|
356
|
+
|
|
357
|
+
Main entry point for starting the server.
|
|
358
|
+
|
|
359
|
+
**Parameters:**
|
|
360
|
+
- `options` (object): Server configuration object
|
|
361
|
+
|
|
362
|
+
**Options:**
|
|
363
|
+
- `ctrl` or `Ctrl`: Main control class constructor
|
|
364
|
+
- `pages`: Object defining multiple pages with routes as keys
|
|
365
|
+
- `api`: Object defining API endpoints
|
|
366
|
+
- `src_path_client_js`: Path to client-side JavaScript file
|
|
367
|
+
- `port`: Server port (default: 8080)
|
|
368
|
+
- `host`: Server host (default: all IPv4 interfaces)
|
|
369
|
+
- `debug`: Enable debug mode (default: false)
|
|
370
|
+
|
|
371
|
+
**Returns:** Promise that resolves to the server instance
|
|
372
|
+
|
|
373
|
+
**Examples:**
|
|
374
|
+
|
|
375
|
+
```javascript
|
|
376
|
+
// Simple control serving
|
|
377
|
+
const server = await Server.serve({
|
|
378
|
+
ctrl: MyControl,
|
|
379
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
380
|
+
port: 3000
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// Multi-page application
|
|
384
|
+
const server = await Server.serve({
|
|
385
|
+
pages: {
|
|
386
|
+
'/': {
|
|
387
|
+
content: HomeControl,
|
|
388
|
+
title: 'Home Page',
|
|
389
|
+
src_path_client_js: require.resolve('./client.js')
|
|
390
|
+
},
|
|
391
|
+
'/about': {
|
|
392
|
+
content: AboutControl,
|
|
393
|
+
title: 'About Page',
|
|
394
|
+
src_path_client_js: require.resolve('./client.js')
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
port: 3000
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// With API endpoints
|
|
401
|
+
const server = await Server.serve({
|
|
402
|
+
ctrl: DashboardControl,
|
|
403
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
404
|
+
api: {
|
|
405
|
+
'status': () => ({ uptime: process.uptime() }),
|
|
406
|
+
'users': async () => await getUsers()
|
|
407
|
+
},
|
|
408
|
+
port: 3000
|
|
409
|
+
});
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Publishers API
|
|
413
|
+
|
|
414
|
+
#### Creating Custom Publishers
|
|
415
|
+
|
|
416
|
+
```javascript
|
|
417
|
+
class CustomPublisher extends Publisher {
|
|
418
|
+
constructor(spec) {
|
|
419
|
+
super(spec);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
serve(request, response) {
|
|
423
|
+
// Custom serving logic
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## Examples
|
|
429
|
+
|
|
430
|
+
### Basic Window Control
|
|
431
|
+
|
|
432
|
+
Based on the actual example in `examples/controls/8) window, checkbox/a)/`:
|
|
433
|
+
|
|
434
|
+
```javascript
|
|
435
|
+
// client.js
|
|
436
|
+
const jsgui = require('jsgui3-client');
|
|
437
|
+
const { controls, Control, mixins } = jsgui;
|
|
438
|
+
const { dragable } = mixins;
|
|
439
|
+
const { Checkbox } = controls;
|
|
440
|
+
const Active_HTML_Document = require('jsgui3-server/controls/Active_HTML_Document');
|
|
441
|
+
|
|
442
|
+
class Demo_UI extends Active_HTML_Document {
|
|
443
|
+
constructor(spec = {}) {
|
|
444
|
+
spec.__type_name = spec.__type_name || 'demo_ui';
|
|
445
|
+
super(spec);
|
|
446
|
+
const { context } = this;
|
|
447
|
+
|
|
448
|
+
if (typeof this.body.add_class === 'function') {
|
|
449
|
+
this.body.add_class('demo-ui');
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const compose = () => {
|
|
453
|
+
// Compose window with a checkbox control
|
|
454
|
+
const window = new controls.Window({
|
|
455
|
+
context,
|
|
456
|
+
title: 'JSGUI3 Checkbox Control',
|
|
457
|
+
pos: [10, 10]
|
|
458
|
+
});
|
|
459
|
+
const checkbox = new Checkbox({
|
|
460
|
+
context,
|
|
461
|
+
label: { text: 'A checkbox' }
|
|
462
|
+
});
|
|
463
|
+
window.inner.add(checkbox);
|
|
464
|
+
this.body.add(window);
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
if (!spec.el) { compose(); }
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
activate() {
|
|
471
|
+
if (!this.__active) {
|
|
472
|
+
super.activate();
|
|
473
|
+
const { context } = this;
|
|
474
|
+
// Handle window resize events
|
|
475
|
+
context.on('window-resize', e_resize => { });
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
Demo_UI.css = `
|
|
481
|
+
* { margin: 0; padding: 0; }
|
|
482
|
+
body {
|
|
483
|
+
overflow-x: hidden;
|
|
484
|
+
overflow-y: hidden;
|
|
485
|
+
background-color: #E0E0E0;
|
|
486
|
+
}
|
|
487
|
+
.demo-ui {
|
|
488
|
+
/* Control-specific styles */
|
|
489
|
+
}
|
|
490
|
+
`;
|
|
491
|
+
|
|
492
|
+
controls.Demo_UI = Demo_UI;
|
|
493
|
+
module.exports = jsgui;
|
|
494
|
+
|
|
495
|
+
// server.js - NEW SIMPLIFIED API (Recommended)
|
|
496
|
+
const Server = require('jsgui3-server');
|
|
497
|
+
|
|
498
|
+
// Auto-discovers client.js and control
|
|
499
|
+
Server.serve({ port: 52000 });
|
|
500
|
+
|
|
501
|
+
// server.js - LEGACY API (Still supported)
|
|
502
|
+
// Uncomment below and comment above for legacy usage
|
|
503
|
+
/*
|
|
504
|
+
const jsgui = require('./client');
|
|
505
|
+
const { Demo_UI } = jsgui.controls;
|
|
506
|
+
const Server = require('jsgui3-server');
|
|
507
|
+
|
|
508
|
+
if (require.main === module) {
|
|
509
|
+
const server = new Server({
|
|
510
|
+
Ctrl: Demo_UI,
|
|
511
|
+
src_path_client_js: require.resolve('./client.js')
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
console.log('waiting for server ready event');
|
|
515
|
+
server.on('ready', () => {
|
|
516
|
+
console.log('server ready');
|
|
517
|
+
server.start(52000, (err) => {
|
|
518
|
+
if (err) throw err;
|
|
519
|
+
console.log('server started');
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
*/
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Data-Bound Controls
|
|
527
|
+
|
|
528
|
+
Example with shared data models:
|
|
529
|
+
|
|
530
|
+
```javascript
|
|
531
|
+
class DataBindingExample extends Active_HTML_Document {
|
|
532
|
+
constructor(spec = {}) {
|
|
533
|
+
spec.__type_name = spec.__type_name || 'data_binding_example';
|
|
534
|
+
super(spec);
|
|
535
|
+
const { context } = this;
|
|
536
|
+
|
|
537
|
+
if (typeof this.body.add_class === 'function') {
|
|
538
|
+
this.body.add_class('data-binding-example');
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Create shared data model
|
|
542
|
+
this.data = { model: new Data_Object({ context }) };
|
|
543
|
+
field(this.data.model, 'name');
|
|
544
|
+
field(this.data.model, 'email');
|
|
545
|
+
context.register_control(this.data.model);
|
|
546
|
+
|
|
547
|
+
const compose = () => {
|
|
548
|
+
// Create input controls bound to shared model
|
|
549
|
+
const nameInput = new controls.Text_Input({
|
|
550
|
+
context,
|
|
551
|
+
label: { text: 'Name:' },
|
|
552
|
+
data: { model: this.data.model, field_name: 'name' }
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
const emailInput = new controls.Text_Input({
|
|
556
|
+
context,
|
|
557
|
+
label: { text: 'Email:' },
|
|
558
|
+
data: { model: this.data.model, field_name: 'email' }
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
this.body.add(nameInput);
|
|
562
|
+
this.body.add(emailInput);
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
if (!spec.el) { compose(); }
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
activate() {
|
|
569
|
+
if (!this.__active) {
|
|
570
|
+
super.activate();
|
|
571
|
+
const { context } = this;
|
|
572
|
+
// Model synchronization logic can go here
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
DataBindingExample.css = `
|
|
578
|
+
* { margin: 0; padding: 0; }
|
|
579
|
+
body {
|
|
580
|
+
overflow-x: hidden;
|
|
581
|
+
overflow-y: hidden;
|
|
582
|
+
background-color: #E0E0E0;
|
|
583
|
+
}
|
|
584
|
+
.data-binding-example {
|
|
585
|
+
padding: 20px;
|
|
586
|
+
}
|
|
587
|
+
`;
|
|
588
|
+
|
|
589
|
+
controls.DataBindingExample = DataBindingExample;
|
|
590
|
+
module.exports = jsgui;
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### API Integration
|
|
594
|
+
|
|
595
|
+
```javascript
|
|
596
|
+
// server.js with API - NEW SIMPLIFIED API
|
|
597
|
+
const Server = require('jsgui3-server');
|
|
598
|
+
|
|
599
|
+
Server.serve({
|
|
600
|
+
// Auto-discovers client.js and control
|
|
601
|
+
api: {
|
|
602
|
+
'users': async () => {
|
|
603
|
+
return await database.getUsers();
|
|
604
|
+
},
|
|
605
|
+
'metrics': () => ({
|
|
606
|
+
activeUsers: 1234,
|
|
607
|
+
totalRevenue: 56789,
|
|
608
|
+
serverUptime: process.uptime()
|
|
609
|
+
}),
|
|
610
|
+
'update': async ({ id, data }) => {
|
|
611
|
+
return await database.updateUser(id, data);
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
port: 3000
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
// API endpoints available at:
|
|
618
|
+
// GET/POST /api/users
|
|
619
|
+
// GET/POST /api/metrics
|
|
620
|
+
// GET/POST /api/update
|
|
621
|
+
|
|
622
|
+
// server.js - LEGACY API (Still supported)
|
|
623
|
+
// Uncomment below for legacy usage
|
|
624
|
+
/*
|
|
625
|
+
const Server = require('jsgui3-server');
|
|
626
|
+
const { DashboardControl } = require('./client').controls;
|
|
627
|
+
|
|
628
|
+
Server.serve({
|
|
629
|
+
ctrl: DashboardControl,
|
|
630
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
631
|
+
api: {
|
|
632
|
+
'users': async () => {
|
|
633
|
+
return await database.getUsers();
|
|
634
|
+
},
|
|
635
|
+
'metrics': () => ({
|
|
636
|
+
activeUsers: 1234,
|
|
637
|
+
totalRevenue: 56789,
|
|
638
|
+
serverUptime: process.uptime()
|
|
639
|
+
}),
|
|
640
|
+
'update': async ({ id, data }) => {
|
|
641
|
+
return await database.updateUser(id, data);
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
port: 3000
|
|
645
|
+
});
|
|
646
|
+
*/
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
## Development
|
|
650
|
+
|
|
651
|
+
### Project Structure
|
|
652
|
+
|
|
653
|
+
```
|
|
654
|
+
jsgui3-server/
|
|
655
|
+
├── cli.js # Command-line interface
|
|
656
|
+
├── server.js # Main server implementation
|
|
657
|
+
├── module.js # Module exports
|
|
658
|
+
├── controls/ # UI control classes
|
|
659
|
+
├── publishers/ # Content publishers
|
|
660
|
+
├── resources/ # Data resource handlers
|
|
661
|
+
├── bundlers/ # Code bundling utilities
|
|
662
|
+
├── examples/ # Example applications
|
|
663
|
+
├── tests/ # Test suites
|
|
664
|
+
└── docs/ # Documentation
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### Development Workflow
|
|
668
|
+
|
|
669
|
+
1. **Setup Development Environment**
|
|
670
|
+
```bash
|
|
671
|
+
git clone https://github.com/metabench/jsgui3-server.git
|
|
672
|
+
cd jsgui3-server
|
|
673
|
+
npm install
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
2. **Run Tests**
|
|
677
|
+
```bash
|
|
678
|
+
npm test
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
3. **Start Development Server**
|
|
682
|
+
```bash
|
|
683
|
+
npm run serve
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
4. **Run CLI**
|
|
687
|
+
```bash
|
|
688
|
+
npm run cli
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
### CLI Commands
|
|
692
|
+
|
|
693
|
+
```bash
|
|
694
|
+
# Start server
|
|
695
|
+
node cli.js serve --port 3000
|
|
696
|
+
|
|
697
|
+
# Show help
|
|
698
|
+
node cli.js --help
|
|
699
|
+
|
|
700
|
+
# Show version
|
|
701
|
+
node cli.js --version
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### Testing
|
|
705
|
+
|
|
706
|
+
The project uses Mocha for testing:
|
|
707
|
+
|
|
708
|
+
```bash
|
|
709
|
+
# Run all tests
|
|
710
|
+
npm test
|
|
711
|
+
|
|
712
|
+
# Run specific test file
|
|
713
|
+
npx mocha tests/cli.test.js
|
|
714
|
+
|
|
715
|
+
# Run with coverage
|
|
716
|
+
npx nyc npm test
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
### Code Style
|
|
720
|
+
|
|
721
|
+
- Use `snake_case` for variables, functions, and utilities
|
|
722
|
+
- Use `PascalCase` for classes and constructors
|
|
723
|
+
- Follow existing patterns for control creation and lifecycle
|
|
724
|
+
- Include comprehensive error handling
|
|
725
|
+
- Add JSDoc comments for public APIs
|
|
726
|
+
|
|
727
|
+
## Deployment
|
|
728
|
+
|
|
729
|
+
### Production Deployment
|
|
730
|
+
|
|
731
|
+
1. **Build Optimization**
|
|
732
|
+
```bash
|
|
733
|
+
# Enable production bundling
|
|
734
|
+
NODE_ENV=production node server.js
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
2. **Environment Configuration**
|
|
738
|
+
```bash
|
|
739
|
+
PORT=80 HOST=0.0.0.0 node server.js
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
3. **Process Management**
|
|
743
|
+
```bash
|
|
744
|
+
# Using PM2
|
|
745
|
+
npm install -g pm2
|
|
746
|
+
pm2 start server.js --name jsgui3-server
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
### Docker Deployment
|
|
750
|
+
|
|
751
|
+
```dockerfile
|
|
752
|
+
FROM node:16-alpine
|
|
753
|
+
|
|
754
|
+
WORKDIR /app
|
|
755
|
+
COPY package*.json ./
|
|
756
|
+
RUN npm ci --only=production
|
|
757
|
+
|
|
758
|
+
COPY . .
|
|
759
|
+
EXPOSE 8080
|
|
760
|
+
|
|
761
|
+
CMD ["node", "server.js"]
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Cloud Deployment
|
|
765
|
+
|
|
766
|
+
#### Heroku
|
|
767
|
+
|
|
768
|
+
```javascript
|
|
769
|
+
// server.js
|
|
770
|
+
const port = process.env.PORT || 8080;
|
|
771
|
+
Server.serve({ ctrl: MyControl, port });
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
#### Vercel
|
|
775
|
+
|
|
776
|
+
```javascript
|
|
777
|
+
// api/server.js
|
|
778
|
+
const Server = require('jsgui3-server');
|
|
779
|
+
|
|
780
|
+
module.exports = (req, res) => {
|
|
781
|
+
// Handle Vercel serverless function
|
|
782
|
+
};
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
## Troubleshooting
|
|
786
|
+
|
|
787
|
+
### Common Issues
|
|
788
|
+
|
|
789
|
+
#### Server Won't Start
|
|
790
|
+
|
|
791
|
+
**Problem:** Port already in use
|
|
792
|
+
**Solution:**
|
|
793
|
+
```bash
|
|
794
|
+
# Find process using port (Linux/macOS)
|
|
795
|
+
lsof -i :8080
|
|
796
|
+
|
|
797
|
+
# Find process using port (Windows)
|
|
798
|
+
netstat -ano | findstr :8080
|
|
799
|
+
|
|
800
|
+
# Kill process or use different port
|
|
801
|
+
PORT=3000 node server.js
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
**Problem:** Missing client.js file
|
|
805
|
+
**Solution:** Ensure `src_path_client_js` points to a valid file:
|
|
806
|
+
```javascript
|
|
807
|
+
Server.serve({
|
|
808
|
+
ctrl: MyControl,
|
|
809
|
+
src_path_client_js: require.resolve('./client.js') // Must resolve to actual file
|
|
810
|
+
});
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
#### Controls Not Rendering
|
|
814
|
+
|
|
815
|
+
**Problem:** CSS or JavaScript not loading
|
|
816
|
+
**Solution:**
|
|
817
|
+
- Check browser developer tools for 404 errors
|
|
818
|
+
- Ensure bundling completed successfully (look for "server ready" message)
|
|
819
|
+
- Verify control CSS is properly defined as static property
|
|
820
|
+
|
|
821
|
+
**Problem:** Control constructor errors
|
|
822
|
+
**Solution:** Check server logs for JavaScript errors in control initialization
|
|
823
|
+
|
|
824
|
+
#### API Endpoints Not Working
|
|
825
|
+
|
|
826
|
+
**Problem:** Incorrect route configuration
|
|
827
|
+
**Solution:**
|
|
828
|
+
- API routes are automatically prefixed with `/api/`
|
|
829
|
+
- Verify function returns correct data type (object/array for JSON, string for text)
|
|
830
|
+
- Check server logs for routing errors
|
|
831
|
+
|
|
832
|
+
**Problem:** Async API functions not working
|
|
833
|
+
**Solution:** Ensure async functions are properly awaited:
|
|
834
|
+
```javascript
|
|
835
|
+
api: {
|
|
836
|
+
'data': async () => {
|
|
837
|
+
return await someAsyncOperation(); // Must return Promise
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
#### Bundling Errors
|
|
843
|
+
|
|
844
|
+
**Problem:** ESBuild bundling fails
|
|
845
|
+
**Solution:**
|
|
846
|
+
- Check for syntax errors in client.js
|
|
847
|
+
- Ensure all dependencies are properly installed
|
|
848
|
+
- Try with `debug: true` for more detailed error messages
|
|
849
|
+
|
|
850
|
+
**Problem:** CSS extraction issues
|
|
851
|
+
**Solution:** Verify control classes have proper CSS static properties
|
|
852
|
+
|
|
853
|
+
### Debug Mode
|
|
854
|
+
|
|
855
|
+
Enable debug mode for detailed logging:
|
|
856
|
+
|
|
857
|
+
```bash
|
|
858
|
+
JSGUI_DEBUG=1 node server.js
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
Or in code:
|
|
862
|
+
|
|
863
|
+
```javascript
|
|
864
|
+
Server.serve({
|
|
865
|
+
ctrl: MyControl,
|
|
866
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
867
|
+
debug: true
|
|
868
|
+
});
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
### Logging
|
|
872
|
+
|
|
873
|
+
The server provides comprehensive logging:
|
|
874
|
+
|
|
875
|
+
- **Server startup**: Bundling progress and server initialization
|
|
876
|
+
- **Request handling**: HTTP requests and responses
|
|
877
|
+
- **Bundling**: ESBuild compilation status
|
|
878
|
+
- **Errors**: Detailed error messages and stack traces
|
|
879
|
+
|
|
880
|
+
### Performance Issues
|
|
881
|
+
|
|
882
|
+
**Problem:** Slow server startup
|
|
883
|
+
**Solution:**
|
|
884
|
+
- Bundling is the most time-consuming part
|
|
885
|
+
- Use debug mode sparingly (disables minification)
|
|
886
|
+
- Cache bundled assets in production
|
|
887
|
+
|
|
888
|
+
**Problem:** High memory usage
|
|
889
|
+
**Solution:**
|
|
890
|
+
- Monitor for memory leaks in controls
|
|
891
|
+
- Use `context.register_control()` properly for cleanup
|
|
892
|
+
- Avoid large data models in memory
|
|
893
|
+
|
|
894
|
+
### Development Tips
|
|
895
|
+
|
|
896
|
+
#### Hot Reloading
|
|
897
|
+
|
|
898
|
+
For development, you may need to restart the server when changing controls. The server doesn't currently support hot reloading.
|
|
899
|
+
|
|
900
|
+
#### Debugging Controls
|
|
901
|
+
|
|
902
|
+
```javascript
|
|
903
|
+
// Add debug logging to controls
|
|
904
|
+
class MyControl extends Active_HTML_Document {
|
|
905
|
+
constructor(spec = {}) {
|
|
906
|
+
super(spec);
|
|
907
|
+
console.log('Control created:', spec);
|
|
908
|
+
|
|
909
|
+
// Add debugging to activation
|
|
910
|
+
this.activate = () => {
|
|
911
|
+
console.log('Control activating');
|
|
912
|
+
// ... rest of activation logic
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
#### Browser Developer Tools
|
|
919
|
+
|
|
920
|
+
- Use browser dev tools to inspect generated HTML/CSS/JS
|
|
921
|
+
- Check Network tab for failed asset requests
|
|
922
|
+
- Use Console tab for client-side JavaScript errors
|
|
923
|
+
- Source maps are available in debug mode for easier debugging
|
|
924
|
+
|
|
925
|
+
## Deployment & Production
|
|
926
|
+
|
|
927
|
+
### Production Configuration
|
|
928
|
+
|
|
929
|
+
#### Environment Variables
|
|
930
|
+
|
|
931
|
+
```bash
|
|
932
|
+
# Production settings
|
|
933
|
+
NODE_ENV=production
|
|
934
|
+
PORT=80
|
|
935
|
+
JSGUI_DEBUG=0
|
|
936
|
+
|
|
937
|
+
# SSL/TLS (if using HTTPS)
|
|
938
|
+
SSL_KEY_PATH=/path/to/ssl/key.pem
|
|
939
|
+
SSL_CERT_PATH=/path/to/ssl/cert.pem
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
#### Server Configuration
|
|
943
|
+
|
|
944
|
+
```javascript
|
|
945
|
+
const server = Server.serve({
|
|
946
|
+
ctrl: MyControl,
|
|
947
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
948
|
+
port: process.env.PORT || 80,
|
|
949
|
+
debug: false, // Disable for production
|
|
950
|
+
// Additional production settings
|
|
951
|
+
max_age: 86400, // Cache static assets for 24 hours
|
|
952
|
+
compress: true // Enable gzip compression
|
|
953
|
+
});
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
### Process Management
|
|
957
|
+
|
|
958
|
+
#### Using PM2
|
|
959
|
+
|
|
960
|
+
```bash
|
|
961
|
+
# Install PM2
|
|
962
|
+
npm install -g pm2
|
|
963
|
+
|
|
964
|
+
# Start server with PM2
|
|
965
|
+
pm2 start server.js --name "jsgui3-server"
|
|
966
|
+
|
|
967
|
+
# Save PM2 configuration
|
|
968
|
+
pm2 save
|
|
969
|
+
|
|
970
|
+
# Set up auto-restart
|
|
971
|
+
pm2 startup
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
#### PM2 Ecosystem File
|
|
975
|
+
|
|
976
|
+
Create `ecosystem.config.js`:
|
|
977
|
+
|
|
978
|
+
```javascript
|
|
979
|
+
module.exports = {
|
|
980
|
+
apps: [{
|
|
981
|
+
name: 'jsgui3-server',
|
|
982
|
+
script: 'server.js',
|
|
983
|
+
instances: 1,
|
|
984
|
+
autorestart: true,
|
|
985
|
+
watch: false,
|
|
986
|
+
max_memory_restart: '1G',
|
|
987
|
+
env: {
|
|
988
|
+
NODE_ENV: 'production',
|
|
989
|
+
PORT: 80
|
|
990
|
+
},
|
|
991
|
+
env_production: {
|
|
992
|
+
NODE_ENV: 'production',
|
|
993
|
+
PORT: 80
|
|
994
|
+
}
|
|
995
|
+
}]
|
|
996
|
+
};
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
### Docker Deployment
|
|
1000
|
+
|
|
1001
|
+
#### Dockerfile
|
|
1002
|
+
|
|
1003
|
+
```dockerfile
|
|
1004
|
+
FROM node:18-alpine
|
|
1005
|
+
|
|
1006
|
+
WORKDIR /app
|
|
1007
|
+
|
|
1008
|
+
# Copy package files
|
|
1009
|
+
COPY package*.json ./
|
|
1010
|
+
RUN npm ci --only=production
|
|
1011
|
+
|
|
1012
|
+
# Copy application code
|
|
1013
|
+
COPY . .
|
|
1014
|
+
|
|
1015
|
+
# Create non-root user
|
|
1016
|
+
RUN addgroup -g 1001 -S nodejs
|
|
1017
|
+
RUN adduser -S jsgui -u 1001
|
|
1018
|
+
|
|
1019
|
+
USER jsgui
|
|
1020
|
+
|
|
1021
|
+
EXPOSE 8080
|
|
1022
|
+
|
|
1023
|
+
CMD ["node", "server.js"]
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
#### Docker Compose
|
|
1027
|
+
|
|
1028
|
+
```yaml
|
|
1029
|
+
version: '3.8'
|
|
1030
|
+
services:
|
|
1031
|
+
jsgui3-server:
|
|
1032
|
+
build: .
|
|
1033
|
+
ports:
|
|
1034
|
+
- "80:8080"
|
|
1035
|
+
environment:
|
|
1036
|
+
- NODE_ENV=production
|
|
1037
|
+
restart: unless-stopped
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
### Reverse Proxy Setup
|
|
1041
|
+
|
|
1042
|
+
#### Nginx Configuration
|
|
1043
|
+
|
|
1044
|
+
```nginx
|
|
1045
|
+
server {
|
|
1046
|
+
listen 80;
|
|
1047
|
+
server_name your-domain.com;
|
|
1048
|
+
|
|
1049
|
+
location / {
|
|
1050
|
+
proxy_pass http://localhost:8080;
|
|
1051
|
+
proxy_http_version 1.1;
|
|
1052
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
1053
|
+
proxy_set_header Connection 'upgrade';
|
|
1054
|
+
proxy_set_header Host $host;
|
|
1055
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
1056
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
1057
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
1058
|
+
proxy_cache_bypass $http_upgrade;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
#### Apache Configuration
|
|
1064
|
+
|
|
1065
|
+
```apache
|
|
1066
|
+
<VirtualHost *:80>
|
|
1067
|
+
ServerName your-domain.com
|
|
1068
|
+
|
|
1069
|
+
ProxyPass / http://localhost:8080/
|
|
1070
|
+
ProxyPassReverse / http://localhost:8080/
|
|
1071
|
+
|
|
1072
|
+
# WebSocket support
|
|
1073
|
+
RewriteEngine On
|
|
1074
|
+
RewriteCond %{HTTP:Upgrade} =websocket [NC]
|
|
1075
|
+
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]
|
|
1076
|
+
</VirtualHost>
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
### SSL/TLS Setup
|
|
1080
|
+
|
|
1081
|
+
#### Let's Encrypt (Certbot)
|
|
1082
|
+
|
|
1083
|
+
```bash
|
|
1084
|
+
# Install Certbot
|
|
1085
|
+
sudo apt install certbot
|
|
1086
|
+
|
|
1087
|
+
# Get SSL certificate
|
|
1088
|
+
sudo certbot certonly --webroot -w /var/www/html -d your-domain.com
|
|
1089
|
+
|
|
1090
|
+
# Configure server for HTTPS
|
|
1091
|
+
const https = require('https');
|
|
1092
|
+
const fs = require('fs');
|
|
1093
|
+
|
|
1094
|
+
const options = {
|
|
1095
|
+
key: fs.readFileSync('/etc/letsencrypt/live/your-domain.com/privkey.pem'),
|
|
1096
|
+
cert: fs.readFileSync('/etc/letsencrypt/live/your-domain.com/fullchain.pem')
|
|
1097
|
+
};
|
|
1098
|
+
|
|
1099
|
+
const server = Server.serve({
|
|
1100
|
+
ctrl: MyControl,
|
|
1101
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
1102
|
+
https: options
|
|
1103
|
+
});
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
### Monitoring & Logging
|
|
1107
|
+
|
|
1108
|
+
#### Health Check Endpoint
|
|
1109
|
+
|
|
1110
|
+
```javascript
|
|
1111
|
+
// Add health check to your control
|
|
1112
|
+
class MyControl extends Active_HTML_Document {
|
|
1113
|
+
static api = {
|
|
1114
|
+
'health': () => ({
|
|
1115
|
+
status: 'ok',
|
|
1116
|
+
timestamp: new Date().toISOString(),
|
|
1117
|
+
uptime: process.uptime()
|
|
1118
|
+
})
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
#### Log Rotation
|
|
1124
|
+
|
|
1125
|
+
```bash
|
|
1126
|
+
# Using PM2
|
|
1127
|
+
pm2 install pm2-logrotate
|
|
1128
|
+
pm2 set pm2-logrotate:max_size 10M
|
|
1129
|
+
pm2 set pm2-logrotate:retain 7
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1132
|
+
### Performance Optimization
|
|
1133
|
+
|
|
1134
|
+
#### Caching Strategy
|
|
1135
|
+
|
|
1136
|
+
```javascript
|
|
1137
|
+
Server.serve({
|
|
1138
|
+
ctrl: MyControl,
|
|
1139
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
1140
|
+
// Cache static assets
|
|
1141
|
+
max_age: 86400, // 24 hours
|
|
1142
|
+
// Enable compression
|
|
1143
|
+
compress: true,
|
|
1144
|
+
// Optimize bundling
|
|
1145
|
+
debug: false
|
|
1146
|
+
});
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
#### Database Connection Pooling
|
|
1150
|
+
|
|
1151
|
+
If using databases, implement connection pooling:
|
|
1152
|
+
|
|
1153
|
+
```javascript
|
|
1154
|
+
const mysql = require('mysql2/promise');
|
|
1155
|
+
|
|
1156
|
+
const pool = mysql.createPool({
|
|
1157
|
+
host: 'localhost',
|
|
1158
|
+
user: 'user',
|
|
1159
|
+
password: 'password',
|
|
1160
|
+
database: 'mydb',
|
|
1161
|
+
waitForConnections: true,
|
|
1162
|
+
connectionLimit: 10,
|
|
1163
|
+
queueLimit: 0
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
// Use in API functions
|
|
1167
|
+
static api = {
|
|
1168
|
+
'data': async () => {
|
|
1169
|
+
const [rows] = await pool.execute('SELECT * FROM table');
|
|
1170
|
+
return rows;
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
```
|
|
1174
|
+
|
|
1175
|
+
### Security Considerations
|
|
1176
|
+
|
|
1177
|
+
#### Input Validation
|
|
1178
|
+
|
|
1179
|
+
```javascript
|
|
1180
|
+
static api = {
|
|
1181
|
+
'user': async (params) => {
|
|
1182
|
+
// Validate input
|
|
1183
|
+
if (!params.id || typeof params.id !== 'number') {
|
|
1184
|
+
throw new Error('Invalid user ID');
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// Sanitize data
|
|
1188
|
+
const userId = Math.floor(params.id);
|
|
1189
|
+
|
|
1190
|
+
return await getUserById(userId);
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
```
|
|
1194
|
+
|
|
1195
|
+
#### Rate Limiting
|
|
1196
|
+
|
|
1197
|
+
Implement rate limiting for API endpoints:
|
|
1198
|
+
|
|
1199
|
+
```javascript
|
|
1200
|
+
const rateLimit = require('express-rate-limit');
|
|
1201
|
+
|
|
1202
|
+
// In your server setup
|
|
1203
|
+
const limiter = rateLimit({
|
|
1204
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
1205
|
+
max: 100 // limit each IP to 100 requests per windowMs
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
// Apply to API routes (requires custom integration)
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
#### CORS Configuration
|
|
1212
|
+
|
|
1213
|
+
```javascript
|
|
1214
|
+
Server.serve({
|
|
1215
|
+
ctrl: MyControl,
|
|
1216
|
+
src_path_client_js: require.resolve('./client.js'),
|
|
1217
|
+
cors: {
|
|
1218
|
+
origin: ['https://yourdomain.com'],
|
|
1219
|
+
methods: ['GET', 'POST'],
|
|
1220
|
+
credentials: true
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
```
|
|
1224
|
+
|
|
1225
|
+
## Contributing
|
|
1226
|
+
|
|
1227
|
+
### Development Setup
|
|
1228
|
+
|
|
1229
|
+
1. Fork the repository
|
|
1230
|
+
2. Clone your fork
|
|
1231
|
+
3. Install dependencies: `npm install`
|
|
1232
|
+
4. Create a feature branch: `git checkout -b feature/my-feature`
|
|
1233
|
+
5. Make your changes
|
|
1234
|
+
6. Run tests: `npm test`
|
|
1235
|
+
7. Submit a pull request
|
|
1236
|
+
|
|
1237
|
+
### Code Guidelines
|
|
1238
|
+
|
|
1239
|
+
- Follow existing code style and patterns
|
|
1240
|
+
- Add tests for new features
|
|
1241
|
+
- Update documentation as needed
|
|
1242
|
+
- Ensure backwards compatibility
|
|
1243
|
+
- Use meaningful commit messages
|
|
1244
|
+
|
|
1245
|
+
### Testing
|
|
1246
|
+
|
|
1247
|
+
- Write unit tests for new functionality
|
|
1248
|
+
- Ensure all existing tests pass
|
|
1249
|
+
- Test on multiple Node.js versions
|
|
1250
|
+
- Include integration tests for complex features
|
|
1251
|
+
|
|
1252
|
+
### Documentation
|
|
1253
|
+
|
|
1254
|
+
- Update README for API changes
|
|
1255
|
+
- Add JSDoc comments for new methods
|
|
1256
|
+
- Include examples for new features
|
|
1257
|
+
- Update changelog for releases
|
|
1258
|
+
|
|
1259
|
+
## Code Style Guidelines
|
|
1260
|
+
|
|
1261
|
+
### Naming Conventions
|
|
1262
|
+
|
|
1263
|
+
Following the agent guidelines in `AGENTS.md`:
|
|
1264
|
+
|
|
1265
|
+
- **Variables, functions, and helper utilities**: Use `snake_case`
|
|
1266
|
+
- **Classes and constructors**: Use `PascalCase` (also called `Snake_Case` in the guidelines)
|
|
1267
|
+
|
|
1268
|
+
**Examples:**
|
|
1269
|
+
```javascript
|
|
1270
|
+
// Correct
|
|
1271
|
+
class My_Custom_Class {
|
|
1272
|
+
constructor(spec = {}) {
|
|
1273
|
+
this.some_variable = spec.some_variable;
|
|
1274
|
+
this.another_helper_function();
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
some_method() {
|
|
1278
|
+
// method implementation
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
function helper_utility_function() {
|
|
1283
|
+
// utility function
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// Avoid
|
|
1287
|
+
class my_custom_class { // Wrong: should be PascalCase
|
|
1288
|
+
constructor() {
|
|
1289
|
+
this.SomeVariable = null; // Wrong: should be snake_case
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
```
|
|
1293
|
+
|
|
1294
|
+
### Control Class Patterns
|
|
1295
|
+
|
|
1296
|
+
When creating new controls, follow these patterns:
|
|
1297
|
+
|
|
1298
|
+
```javascript
|
|
1299
|
+
const jsgui = require('jsgui3-client');
|
|
1300
|
+
const { controls, Control, Data_Object, field } = jsgui;
|
|
1301
|
+
const Active_HTML_Document = require('jsgui3-server/controls/Active_HTML_Document');
|
|
1302
|
+
|
|
1303
|
+
class My_Custom_Control extends Active_HTML_Document {
|
|
1304
|
+
constructor(spec = {}) {
|
|
1305
|
+
spec.__type_name = spec.__type_name || 'my_custom_control';
|
|
1306
|
+
super(spec);
|
|
1307
|
+
const { context } = this;
|
|
1308
|
+
|
|
1309
|
+
// Defensive programming
|
|
1310
|
+
if (typeof this.body.add_class === 'function') {
|
|
1311
|
+
this.body.add_class('my-custom-control');
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
const compose = () => {
|
|
1315
|
+
// UI composition logic
|
|
1316
|
+
};
|
|
1317
|
+
|
|
1318
|
+
if (!spec.el) { compose(); }
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
activate() {
|
|
1322
|
+
if (!this.__active) {
|
|
1323
|
+
super.activate();
|
|
1324
|
+
const { context } = this;
|
|
1325
|
+
// Activation logic
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
My_Custom_Control.css = `
|
|
1331
|
+
/* CSS styles */
|
|
1332
|
+
`;
|
|
1333
|
+
|
|
1334
|
+
controls.My_Custom_Control = My_Custom_Control;
|
|
1335
|
+
module.exports = jsgui;
|
|
1336
|
+
```
|
|
1337
|
+
|
|
1338
|
+
### Documentation Standards
|
|
1339
|
+
|
|
1340
|
+
- Use JSDoc comments for all public methods and classes
|
|
1341
|
+
- Document parameters, return values, and thrown exceptions
|
|
1342
|
+
- Include code examples where helpful
|
|
1343
|
+
- Reference related functions and classes
|
|
1344
|
+
|
|
1345
|
+
### Error Handling
|
|
1346
|
+
|
|
1347
|
+
- Use defensive programming techniques
|
|
1348
|
+
- Provide meaningful error messages
|
|
1349
|
+
- Handle asynchronous errors properly
|
|
1350
|
+
- Log errors appropriately for debugging
|
|
1351
|
+
|
|
1352
|
+
### Reference Materials
|
|
1353
|
+
|
|
1354
|
+
For comprehensive guidance on agentic workflows and development practices, see:
|
|
1355
|
+
- [`AGENTS.md`](AGENTS.md) - Agent guidelines and naming conventions
|
|
1356
|
+
- [`docs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md`](docs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md) - Complete guide to autonomous task execution
|
|
1357
|
+
|
|
1358
|
+
## License
|
|
1359
|
+
|
|
1360
|
+
MIT License - see LICENSE file for details.
|
|
1361
|
+
|
|
1362
|
+
## Changelog
|
|
1363
|
+
|
|
1364
|
+
### Version 0.0.138
|
|
1365
|
+
- Enhanced server API with `Server.serve()` method
|
|
1366
|
+
- Improved CSS extraction and bundling
|
|
1367
|
+
- Added comprehensive CLI interface
|
|
1368
|
+
- Fixed source map consistency issues
|
|
1369
|
+
|
|
1370
|
+
### Version 0.0.137
|
|
1371
|
+
- Bug fixes and stability improvements
|
|
1372
|
+
- Enhanced publisher system
|
|
1373
|
+
- Improved error handling
|
|
1374
|
+
|
|
1375
|
+
### Version 0.0.136
|
|
1376
|
+
- Server function publishing improvements
|
|
1377
|
+
- Better JSON API support
|
|
1378
|
+
- Enhanced resource management
|
|
1379
|
+
|
|
1380
|
+
## Support
|
|
1381
|
+
|
|
1382
|
+
- **Issues**: [GitHub Issues](https://github.com/metabench/jsgui3-server/issues)
|
|
1383
|
+
- **Discussions**: [GitHub Discussions](https://github.com/metabench/jsgui3-server/discussions)
|
|
1384
|
+
- **Documentation**: [Project Wiki](https://github.com/metabench/jsgui3-server/wiki)
|
|
1385
|
+
|
|
1386
|
+
## Roadmap
|
|
1387
|
+
|
|
1388
|
+
### Current Focus
|
|
1389
|
+
- CLI improvements and reliability
|
|
1390
|
+
- Admin interface development
|
|
1391
|
+
- Enhanced control suite
|
|
1392
|
+
- Documentation and examples
|
|
1393
|
+
|
|
1394
|
+
### Future Plans
|
|
1395
|
+
- File manager interface
|
|
1396
|
+
- Deployment workflows
|
|
1397
|
+
- Advanced bundling options
|
|
1398
|
+
- Performance optimizations
|
|
1399
|
+
|
|
1400
|
+
---
|
|
1401
|
+
|
|
1402
|
+
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/`.</content>
|
|
1403
|
+
<parameter name="filePath">c:\\Users\\james\\Documents\\repos\\jsgui3-server\\docs\\comprehensive-documentation.md
|