jsgui3-server 0.0.147 → 0.0.148
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/admin-ui/client.js +213 -0
- package/admin-ui/server.js +104 -0
- package/client/controls/auto-observable.js +207 -0
- package/docs/books/admin-ui/01-introduction.md +32 -0
- package/docs/books/admin-ui/02-architecture.md +92 -0
- package/docs/books/admin-ui/03-controls.md +194 -0
- package/docs/books/admin-ui/04-implementation-plan.md +62 -0
- package/docs/books/admin-ui/README.md +26 -0
- package/examples/controls/19) window, auto observable ui/client.js +125 -0
- package/examples/controls/19) window, auto observable ui/server.js +64 -0
- package/package.json +3 -3
- package/publishers/http-observable-publisher.js +8 -0
- package/publishers/http-webpage-publisher.js +13 -3
- package/publishers/http-webpageorsite-publisher.js +18 -0
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +54 -32
- package/server.js +72 -3
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Chapter 3: Controls
|
|
2
|
+
|
|
3
|
+
## Control Placement Strategy
|
|
4
|
+
|
|
5
|
+
| Control | Location | Rationale |
|
|
6
|
+
|---------|----------|-----------|
|
|
7
|
+
| `Property_Viewer` | jsgui3-html | General-purpose read-only property display |
|
|
8
|
+
| `Property_Editor` | jsgui3-html | Already exists - editing properties |
|
|
9
|
+
| `Object_KVP_Viewer` | jsgui3-html | Already exists - key-value pairs |
|
|
10
|
+
| `Object_KVP_Editor` | jsgui3-html | Already exists - editable KVP |
|
|
11
|
+
| `Resource_Viewer` | jsgui3-html | General-purpose for any resource with name/type/status |
|
|
12
|
+
| `Tree_View` | jsgui3-html | General-purpose hierarchical display |
|
|
13
|
+
| `Admin_Page` | jsgui3-server | Server-specific admin shell |
|
|
14
|
+
| `Resource_List` | jsgui3-server | Server-specific resource listing |
|
|
15
|
+
| `Observables_List` | jsgui3-server | Server-specific observable listing |
|
|
16
|
+
| `Observable_Monitor` | jsgui3-server | Server-specific real-time monitoring |
|
|
17
|
+
| `Resource_Detail_Page` | jsgui3-server | Server-specific resource detail view |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## General-Purpose Controls (jsgui3-html)
|
|
22
|
+
|
|
23
|
+
### Existing Controls to Leverage
|
|
24
|
+
|
|
25
|
+
1. **`Property_Editor`** - Edits properties with type-specific inputs
|
|
26
|
+
2. **`Object_KVP_Viewer`** - Displays object as key-value pairs
|
|
27
|
+
3. **`Object_KVP_Editor`** - Editable key-value pairs
|
|
28
|
+
|
|
29
|
+
### New Controls Needed in jsgui3-html
|
|
30
|
+
|
|
31
|
+
#### Property_Viewer
|
|
32
|
+
|
|
33
|
+
Read-only display of an object's properties in a clean table format.
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
const viewer = new controls.Property_Viewer({
|
|
37
|
+
context,
|
|
38
|
+
data: { name: 'MyResource', type: 'observable', status: 'active' },
|
|
39
|
+
schema: {
|
|
40
|
+
name: { label: 'Name', type: 'string' },
|
|
41
|
+
type: { label: 'Type', type: 'badge' },
|
|
42
|
+
status: { label: 'Status', type: 'status-indicator' }
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
#### Resource_Viewer
|
|
48
|
+
|
|
49
|
+
Displays a resource with icon, name, type badge, and expandable details.
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const rv = new controls.Resource_Viewer({
|
|
53
|
+
context,
|
|
54
|
+
resource: {
|
|
55
|
+
name: '/api/tick-stream',
|
|
56
|
+
type: 'observable',
|
|
57
|
+
schema: { type: 'int' },
|
|
58
|
+
status: 'active',
|
|
59
|
+
connections: 3
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Tree_View
|
|
65
|
+
|
|
66
|
+
Hierarchical tree with expand/collapse, icons, and selection.
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
const tree = new controls.Tree_View({
|
|
70
|
+
context,
|
|
71
|
+
data: [
|
|
72
|
+
{ label: 'Publishers', icon: '📡', children: [...] },
|
|
73
|
+
{ label: 'Routes', icon: '🛤️', children: [...] }
|
|
74
|
+
],
|
|
75
|
+
onSelect: (node) => console.log('Selected:', node)
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Server-Specific Controls (jsgui3-server/admin-ui)
|
|
82
|
+
|
|
83
|
+
### 1. Admin_Page
|
|
84
|
+
|
|
85
|
+
The main container control that serves as the Admin UI shell.
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
class Admin_Page extends Active_HTML_Document {
|
|
89
|
+
// Renders sidebar + main panel + header
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Layout:**
|
|
94
|
+
- Left sidebar: `Resource_List` + `Observables_List`
|
|
95
|
+
- Main panel: `Resource_Detail_Page` or selected content
|
|
96
|
+
- Header: Server name, uptime, connection count
|
|
97
|
+
|
|
98
|
+
### 2. Resource_List
|
|
99
|
+
|
|
100
|
+
Displays all registered server resources using `Tree_View`.
|
|
101
|
+
|
|
102
|
+
**Data Source:** `GET /api/admin/resources`
|
|
103
|
+
|
|
104
|
+
**Structure:**
|
|
105
|
+
```
|
|
106
|
+
├── Routes
|
|
107
|
+
│ ├── / (webpage)
|
|
108
|
+
│ ├── /admin (admin-ui)
|
|
109
|
+
│ └── /api/* (function)
|
|
110
|
+
├── Publishers
|
|
111
|
+
│ ├── HTTP_Website_Publisher
|
|
112
|
+
│ └── HTTP_Observable_Publisher
|
|
113
|
+
└── Resources
|
|
114
|
+
├── Server Router
|
|
115
|
+
└── Resource Pool
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. Observables_List
|
|
119
|
+
|
|
120
|
+
Lists all published observables with status indicators.
|
|
121
|
+
|
|
122
|
+
**Data Source:** `GET /api/admin/observables`
|
|
123
|
+
|
|
124
|
+
**Item Display:**
|
|
125
|
+
- Route path
|
|
126
|
+
- Schema type badge
|
|
127
|
+
- Status indicator (active/paused/stopped)
|
|
128
|
+
- Connection count
|
|
129
|
+
|
|
130
|
+
### 4. Observable_Monitor
|
|
131
|
+
|
|
132
|
+
Real-time display for a single observable using `Auto_Observable_UI`.
|
|
133
|
+
|
|
134
|
+
**Features:**
|
|
135
|
+
- Play/Pause controls
|
|
136
|
+
- History buffer (last N values)
|
|
137
|
+
- Schema display
|
|
138
|
+
- Export to JSON
|
|
139
|
+
|
|
140
|
+
### 5. Resource_Detail_Page
|
|
141
|
+
|
|
142
|
+
Detail view for a selected resource.
|
|
143
|
+
|
|
144
|
+
**Sections:**
|
|
145
|
+
- **Header**: Name, type badge
|
|
146
|
+
- **Properties**: Using `Property_Viewer`
|
|
147
|
+
- **Actions**: Pause, resume, stop (for observables)
|
|
148
|
+
- **Live View**: For observables, embedded monitor
|
|
149
|
+
|
|
150
|
+
### 6. Config_Panel
|
|
151
|
+
|
|
152
|
+
Form-based configuration editor using `Property_Editor`.
|
|
153
|
+
|
|
154
|
+
**Features:**
|
|
155
|
+
- Read-only by default (safety)
|
|
156
|
+
- Unlock with confirmation for editing
|
|
157
|
+
- Validation before save
|
|
158
|
+
|
|
159
|
+
### 7. Metrics_Dashboard
|
|
160
|
+
|
|
161
|
+
Displays server health metrics.
|
|
162
|
+
|
|
163
|
+
**Metrics:**
|
|
164
|
+
- Active connections
|
|
165
|
+
- Requests/second
|
|
166
|
+
- Memory usage
|
|
167
|
+
- Observable subscription count
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Styling Approach
|
|
172
|
+
|
|
173
|
+
All controls use CSS-in-JS via the static `.css` property:
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
Admin_Page.css = `
|
|
177
|
+
.admin-page {
|
|
178
|
+
display: grid;
|
|
179
|
+
grid-template-columns: 280px 1fr;
|
|
180
|
+
height: 100vh;
|
|
181
|
+
background: #1a1a2e;
|
|
182
|
+
}
|
|
183
|
+
.admin-sidebar { ... }
|
|
184
|
+
.admin-main { ... }
|
|
185
|
+
`;
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Extension Points
|
|
189
|
+
|
|
190
|
+
Custom admin panels can be registered:
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
server.admin.registerPanel('MyPanel', MyPanelControl);
|
|
194
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Chapter 4: Implementation Plan
|
|
2
|
+
|
|
3
|
+
## Phase 1: Foundation
|
|
4
|
+
|
|
5
|
+
### jsgui3-html (General-Purpose)
|
|
6
|
+
- [ ] Implement `Property_Viewer` control
|
|
7
|
+
- [ ] Implement `Resource_Viewer` control
|
|
8
|
+
- [ ] Implement `Tree_View` control
|
|
9
|
+
|
|
10
|
+
### jsgui3-server (Admin-Specific)
|
|
11
|
+
- [x] Create `admin-ui/client.js` with `Admin_Page`
|
|
12
|
+
- [x] Create `admin-ui/server.js` with API routes
|
|
13
|
+
- [x] Register `/admin` route in main server
|
|
14
|
+
|
|
15
|
+
## Phase 2: Resource Browser
|
|
16
|
+
|
|
17
|
+
- [ ] Implement `Resource_List` using `Tree_View`
|
|
18
|
+
- [x] Add API: `GET /api/admin/resources`
|
|
19
|
+
- [ ] Implement `Resource_Detail_Page`
|
|
20
|
+
- [ ] Wire up selection → detail view
|
|
21
|
+
|
|
22
|
+
## Phase 3: Observable Visibility
|
|
23
|
+
|
|
24
|
+
- [ ] Implement `Observables_List` control
|
|
25
|
+
- [x] Add API: `GET /api/admin/observables`
|
|
26
|
+
- [ ] Implement `Observable_Monitor` with `Auto_Observable_UI`
|
|
27
|
+
- [ ] Add play/pause/history features
|
|
28
|
+
|
|
29
|
+
## Phase 4: Metrics & Config
|
|
30
|
+
|
|
31
|
+
- [ ] Implement `Metrics_Dashboard`
|
|
32
|
+
- [ ] Add API: `GET /api/admin/metrics` (SSE)
|
|
33
|
+
- [ ] Implement `Config_Panel` using `Property_Editor`
|
|
34
|
+
|
|
35
|
+
## Phase 5: Polish
|
|
36
|
+
|
|
37
|
+
- [ ] Responsive design
|
|
38
|
+
- [ ] Keyboard navigation
|
|
39
|
+
- [ ] Export/import config
|
|
40
|
+
- [ ] Documentation and examples
|
|
41
|
+
|
|
42
|
+
## File Checklist
|
|
43
|
+
|
|
44
|
+
| File | Location | Status |
|
|
45
|
+
|------|----------|--------|
|
|
46
|
+
| `Property_Viewer.js` | jsgui3-html | Planned |
|
|
47
|
+
| `Resource_Viewer.js` | jsgui3-html | Planned |
|
|
48
|
+
| `Tree_View.js` | jsgui3-html | Planned |
|
|
49
|
+
| `admin-ui/client.js` | jsgui3-server | ✅ Done |
|
|
50
|
+
| `admin-ui/server.js` | jsgui3-server | ✅ Done |
|
|
51
|
+
| `admin-ui/controls/Resource_List.js` | jsgui3-server | Planned |
|
|
52
|
+
| `admin-ui/controls/Observables_List.js` | jsgui3-server | Planned |
|
|
53
|
+
| `admin-ui/controls/Observable_Monitor.js` | jsgui3-server | Planned |
|
|
54
|
+
| `admin-ui/controls/Resource_Detail_Page.js` | jsgui3-server | Planned |
|
|
55
|
+
|
|
56
|
+
## Success Criteria
|
|
57
|
+
|
|
58
|
+
1. Navigate to `/admin` and see the Admin UI
|
|
59
|
+
2. Browse all server resources in tree view
|
|
60
|
+
3. Select a resource to see its properties
|
|
61
|
+
4. View live observable streams with auto-generated UIs
|
|
62
|
+
5. See basic metrics (connections, uptime)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Admin UI Book
|
|
2
|
+
|
|
3
|
+
This folder contains documentation for the `jsgui3-server` Admin UI system.
|
|
4
|
+
|
|
5
|
+
## Chapters
|
|
6
|
+
|
|
7
|
+
1. [Introduction](./01-introduction.md) - Vision and goals
|
|
8
|
+
2. [Architecture](./02-architecture.md) - High-level design
|
|
9
|
+
3. [Controls](./03-controls.md) - UI components
|
|
10
|
+
4. [Implementation Plan](./04-implementation-plan.md) - Phases and tasks
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
The Admin UI provides a web-based interface to administer and monitor `jsgui3-server` instances. Key features include:
|
|
15
|
+
|
|
16
|
+
- **Resource Viewer**: Browse server-side resources (publishers, routes, etc.)
|
|
17
|
+
- **Observable Monitor**: Real-time visibility into observable server processes
|
|
18
|
+
- **Configuration Editor**: Modify server settings
|
|
19
|
+
- **Performance Dashboard**: View metrics and health
|
|
20
|
+
|
|
21
|
+
## Design Principles
|
|
22
|
+
|
|
23
|
+
1. **Dogfooding**: Built entirely with jsgui3 controls
|
|
24
|
+
2. **Real-time**: Uses `Remote_Observable` for live updates
|
|
25
|
+
3. **Extensible**: Plugin architecture for custom panels
|
|
26
|
+
4. **Polished UX**: Modern dark theme, smooth transitions
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const jsgui = require('jsgui3-client');
|
|
2
|
+
const { controls, Control } = jsgui;
|
|
3
|
+
const Auto_Observable_UI = require('../../../client/controls/auto-observable');
|
|
4
|
+
controls.Auto_Observable_UI = Auto_Observable_UI;
|
|
5
|
+
|
|
6
|
+
const Active_HTML_Document = require('../../../controls/Active_HTML_Document');
|
|
7
|
+
|
|
8
|
+
class Demo_Page extends Active_HTML_Document {
|
|
9
|
+
constructor(spec = {}) {
|
|
10
|
+
spec.__type_name = spec.__type_name || 'demo_page';
|
|
11
|
+
super(spec);
|
|
12
|
+
const { context } = this;
|
|
13
|
+
|
|
14
|
+
if (typeof this.body.add_class === 'function') {
|
|
15
|
+
this.body.add_class('demo-page');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const compose = () => {
|
|
19
|
+
const h1 = new controls.h1({ context });
|
|
20
|
+
h1.add('Auto Observable UI Demo');
|
|
21
|
+
this.body.add(h1);
|
|
22
|
+
|
|
23
|
+
const container = new controls.div({ context, class: 'params-container' });
|
|
24
|
+
this.body.add(container);
|
|
25
|
+
|
|
26
|
+
// 1. Tick Counter (Int)
|
|
27
|
+
const ui_tick = new Auto_Observable_UI({
|
|
28
|
+
context,
|
|
29
|
+
url: '/api/tick',
|
|
30
|
+
class: 'param-ui'
|
|
31
|
+
});
|
|
32
|
+
container.add(ui_tick);
|
|
33
|
+
|
|
34
|
+
// 2. CPU Load (Gauge)
|
|
35
|
+
const ui_cpu = new Auto_Observable_UI({
|
|
36
|
+
context,
|
|
37
|
+
url: '/api/cpu',
|
|
38
|
+
class: 'param-ui'
|
|
39
|
+
});
|
|
40
|
+
container.add(ui_cpu);
|
|
41
|
+
|
|
42
|
+
// 3. System Logs (Log)
|
|
43
|
+
const ui_log = new Auto_Observable_UI({
|
|
44
|
+
context,
|
|
45
|
+
url: '/api/logs',
|
|
46
|
+
class: 'param-ui span-2'
|
|
47
|
+
});
|
|
48
|
+
container.add(ui_log);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if (!spec.el) {
|
|
52
|
+
compose();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Demo_Page.css = `
|
|
58
|
+
body {
|
|
59
|
+
background: #222;
|
|
60
|
+
color: #eee;
|
|
61
|
+
font-family: sans-serif;
|
|
62
|
+
padding: 20px;
|
|
63
|
+
}
|
|
64
|
+
.params-container {
|
|
65
|
+
display: grid;
|
|
66
|
+
grid-template-columns: 1fr 1fr;
|
|
67
|
+
gap: 20px;
|
|
68
|
+
max-width: 800px;
|
|
69
|
+
}
|
|
70
|
+
.param-ui {
|
|
71
|
+
background: #333;
|
|
72
|
+
padding: 15px;
|
|
73
|
+
border-radius: 8px;
|
|
74
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.5);
|
|
75
|
+
}
|
|
76
|
+
.span-2 {
|
|
77
|
+
grid-column: span 2;
|
|
78
|
+
}
|
|
79
|
+
.value-display {
|
|
80
|
+
text-align: center;
|
|
81
|
+
}
|
|
82
|
+
.value-text {
|
|
83
|
+
font-size: 3em;
|
|
84
|
+
font-weight: bold;
|
|
85
|
+
color: #4facfe;
|
|
86
|
+
}
|
|
87
|
+
.progress-bg {
|
|
88
|
+
background: #444;
|
|
89
|
+
height: 20px;
|
|
90
|
+
border-radius: 10px;
|
|
91
|
+
overflow: hidden;
|
|
92
|
+
margin: 10px 0;
|
|
93
|
+
}
|
|
94
|
+
.progress-fill {
|
|
95
|
+
background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);
|
|
96
|
+
height: 100%;
|
|
97
|
+
width: 0%;
|
|
98
|
+
transition: width 0.3s ease;
|
|
99
|
+
}
|
|
100
|
+
.log-area {
|
|
101
|
+
height: 150px;
|
|
102
|
+
background: #111;
|
|
103
|
+
overflow-y: auto;
|
|
104
|
+
text-align: left;
|
|
105
|
+
padding: 10px;
|
|
106
|
+
font-family: monospace;
|
|
107
|
+
font-size: 0.9em;
|
|
108
|
+
border: 1px solid #444;
|
|
109
|
+
}
|
|
110
|
+
.log-entry {
|
|
111
|
+
margin-bottom: 4px;
|
|
112
|
+
border-bottom: 1px solid #222;
|
|
113
|
+
}
|
|
114
|
+
.status-indicator {
|
|
115
|
+
font-size: 0.8em;
|
|
116
|
+
text-transform: uppercase;
|
|
117
|
+
margin-bottom: 5px;
|
|
118
|
+
color: #888;
|
|
119
|
+
}
|
|
120
|
+
.status-connected { color: #0f0; }
|
|
121
|
+
.status-error { color: #f00; }
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
module.exports = jsgui;
|
|
125
|
+
controls.Demo_Page = Demo_Page;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const jsgui = require('./client');
|
|
2
|
+
const Server = require('../../../server');
|
|
3
|
+
const { Demo_Page } = jsgui.controls;
|
|
4
|
+
const { observable } = require('fnl');
|
|
5
|
+
|
|
6
|
+
if (require.main === module) {
|
|
7
|
+
const server = new Server({
|
|
8
|
+
Ctrl: Demo_Page,
|
|
9
|
+
src_path_client_js: require.resolve('./client.js')
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
server.on('ready', () => {
|
|
13
|
+
// 1. Tick Observable
|
|
14
|
+
const obs_tick = observable((next) => {
|
|
15
|
+
let i = 0;
|
|
16
|
+
const timer = setInterval(() => next(++i), 1000);
|
|
17
|
+
return () => clearInterval(timer);
|
|
18
|
+
});
|
|
19
|
+
// Attach schema manually (or could be done via helper)
|
|
20
|
+
obs_tick.schema = {
|
|
21
|
+
name: 'Uptime (Seconds)',
|
|
22
|
+
type: 'int'
|
|
23
|
+
};
|
|
24
|
+
server.publish_observable('/api/tick', obs_tick);
|
|
25
|
+
|
|
26
|
+
// 2. CPU Observable (Simulated)
|
|
27
|
+
const obs_cpu = observable((next) => {
|
|
28
|
+
const timer = setInterval(() => {
|
|
29
|
+
const load = 40 + Math.random() * 30;
|
|
30
|
+
next(Math.floor(load));
|
|
31
|
+
}, 500);
|
|
32
|
+
return () => clearInterval(timer);
|
|
33
|
+
});
|
|
34
|
+
obs_cpu.schema = {
|
|
35
|
+
name: 'CPU Load',
|
|
36
|
+
type: 'number',
|
|
37
|
+
min: 0,
|
|
38
|
+
max: 100
|
|
39
|
+
};
|
|
40
|
+
server.publish_observable('/api/cpu', obs_cpu);
|
|
41
|
+
|
|
42
|
+
// 3. Logs Observable
|
|
43
|
+
const obs_logs = observable((next) => {
|
|
44
|
+
const msgs = ['System check OK', 'Request received', 'Cache invalidated', 'User login', 'Background job started'];
|
|
45
|
+
const timer = setInterval(() => {
|
|
46
|
+
const msg = msgs[Math.floor(Math.random() * msgs.length)];
|
|
47
|
+
next({ message: msg, level: 'info' });
|
|
48
|
+
}, 2000);
|
|
49
|
+
return () => clearInterval(timer);
|
|
50
|
+
});
|
|
51
|
+
obs_logs.schema = {
|
|
52
|
+
name: 'Server Logs',
|
|
53
|
+
type: 'log'
|
|
54
|
+
};
|
|
55
|
+
server.publish_observable('/api/logs', obs_logs);
|
|
56
|
+
|
|
57
|
+
// Start
|
|
58
|
+
const port = 52100;
|
|
59
|
+
server.start(port, (err) => {
|
|
60
|
+
if (err) throw err;
|
|
61
|
+
console.log(`Demo running at http://localhost:${port}`);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"esbuild": "^0.27.1",
|
|
11
11
|
"fnl": "^0.0.37",
|
|
12
12
|
"fnlfs": "^0.0.34",
|
|
13
|
-
"jsgui3-client": "^0.0.
|
|
14
|
-
"jsgui3-html": "^0.0.
|
|
13
|
+
"jsgui3-client": "^0.0.129",
|
|
14
|
+
"jsgui3-html": "^0.0.180",
|
|
15
15
|
"jsgui3-webpage": "^0.0.8",
|
|
16
16
|
"jsgui3-website": "^0.0.8",
|
|
17
17
|
"lang-tools": "^0.0.44",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"type": "git",
|
|
44
44
|
"url": "https://github.com/metabench/jsgui3-server.git"
|
|
45
45
|
},
|
|
46
|
-
"version": "0.0.
|
|
46
|
+
"version": "0.0.148",
|
|
47
47
|
"scripts": {
|
|
48
48
|
"cli": "node cli.js",
|
|
49
49
|
"serve": "node cli.js serve",
|
|
@@ -27,6 +27,9 @@ class Observable_Publisher extends HTTP_Publisher {
|
|
|
27
27
|
this.type = 'observable';
|
|
28
28
|
this.obs = obs;
|
|
29
29
|
|
|
30
|
+
// Expose schema if provided (either in spec or on the observable itself)
|
|
31
|
+
this.schema = spec.schema || obs.schema || null;
|
|
32
|
+
|
|
30
33
|
this.keep_alive_interval_ms = (spec && spec.keep_alive_interval_ms !== undefined)
|
|
31
34
|
? spec.keep_alive_interval_ms
|
|
32
35
|
: default_keep_alive_interval_ms;
|
|
@@ -301,6 +304,11 @@ class Observable_Publisher extends HTTP_Publisher {
|
|
|
301
304
|
this._write_sse(res, `event: paused\ndata: ${this._stringify_sse_data({ status: 'paused' })}\n\n`);
|
|
302
305
|
}
|
|
303
306
|
|
|
307
|
+
// Send schema if available
|
|
308
|
+
if (this.schema) {
|
|
309
|
+
this._write_sse(res, `event: schema\ndata: ${this._stringify_sse_data(this.schema)}\n\n`);
|
|
310
|
+
}
|
|
311
|
+
|
|
304
312
|
let removed = false;
|
|
305
313
|
const remove_connection = () => {
|
|
306
314
|
if (removed) return;
|
|
@@ -72,9 +72,19 @@ class HTTP_Webpage_Publisher extends HTTP_Webpageorsite_Publisher {
|
|
|
72
72
|
bundler_config: this.bundler_config
|
|
73
73
|
});
|
|
74
74
|
(async () => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
try {
|
|
76
|
+
const res_get_ready = await this.get_ready();
|
|
77
|
+
this.raise('ready', res_get_ready);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.error('HTTP_Webpage_Publisher error: Failed to get ready (bundling or preparation failed).');
|
|
80
|
+
console.error(e);
|
|
81
|
+
// Can't just ignore it if it means the server won't handle requests correctly,
|
|
82
|
+
// but at least it won't crash the whole process.
|
|
83
|
+
// We might want to emit an error event.
|
|
84
|
+
this.raise('error', e);
|
|
85
|
+
// Also raise 'ready' so the pool/server can continue starting up other things
|
|
86
|
+
this.raise('ready', {});
|
|
87
|
+
}
|
|
78
88
|
})();
|
|
79
89
|
|
|
80
90
|
}
|
|
@@ -162,6 +162,24 @@ class HTTP_Webpageorsite_Publisher extends HTTP_Publisher {
|
|
|
162
162
|
|
|
163
163
|
console.log('[HTTP_Webpageorsite_Publisher] get_ready called, src_path_client_js:', src_path_client_js);
|
|
164
164
|
|
|
165
|
+
// Defensive programming: Handle missing client JS path
|
|
166
|
+
if (!src_path_client_js) {
|
|
167
|
+
console.warn('[HTTP_Webpageorsite_Publisher] No src_path_client_js provided. Returning empty bundle.');
|
|
168
|
+
const bundle = new Bundle();
|
|
169
|
+
// Could add empty CSS/JS placeholders if needed to prevent errors downstream
|
|
170
|
+
bundle.push({
|
|
171
|
+
type: 'CSS',
|
|
172
|
+
extension: 'css',
|
|
173
|
+
text: '/* No client CSS - Server Start Mode */'
|
|
174
|
+
});
|
|
175
|
+
bundle.push({
|
|
176
|
+
type: 'JavaScript',
|
|
177
|
+
extension: 'js',
|
|
178
|
+
text: '/* No client JS - Server Start Mode */'
|
|
179
|
+
});
|
|
180
|
+
return bundle;
|
|
181
|
+
}
|
|
182
|
+
|
|
165
183
|
// Skip bundling if no client.js path is provided
|
|
166
184
|
// This allows Server.serve() to work with SSR-only controls
|
|
167
185
|
if (!src_path_client_js) {
|