jsgui3-server 0.0.148 → 0.0.150
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/.github/agents/Mobile Developer.agent.md +89 -0
- package/.github/workflows/control-scan-manifest-check.yml +31 -0
- package/AGENTS.md +4 -0
- package/README.md +215 -3
- package/admin-ui/client.js +81 -51
- package/admin-ui/v1/admin_auth_service.js +197 -0
- package/admin-ui/v1/admin_user_store.js +71 -0
- package/admin-ui/v1/client.js +17 -0
- package/admin-ui/v1/controls/admin_shell.js +1399 -0
- package/admin-ui/v1/controls/group_box.js +84 -0
- package/admin-ui/v1/controls/stat_card.js +125 -0
- package/admin-ui/v1/server.js +658 -0
- package/admin-ui/v1/utils/formatters.js +68 -0
- package/dev-status.svg +139 -0
- package/docs/admin-extension-guide.md +345 -0
- package/docs/api-reference.md +301 -43
- package/docs/books/adaptive-control-improvements/01-control-candidate-matrix.md +122 -0
- package/docs/books/adaptive-control-improvements/02-tier-1-layout-playbooks.md +207 -0
- package/docs/books/adaptive-control-improvements/03-tier-2-navigation-form-overlay.md +140 -0
- package/docs/books/adaptive-control-improvements/04-cross-cutting-platform-functionality.md +141 -0
- package/docs/books/adaptive-control-improvements/05-styling-theming-density-upgrades.md +114 -0
- package/docs/books/adaptive-control-improvements/06-testing-quality-gates.md +97 -0
- package/docs/books/adaptive-control-improvements/07-delivery-roadmap-and-ownership.md +137 -0
- package/docs/books/adaptive-control-improvements/08-appendix-tier1-acceptance-and-pr-templates.md +261 -0
- package/docs/books/adaptive-control-improvements/README.md +66 -0
- package/docs/books/admin-ui-authentication/01-threat-model-and-goals.md +124 -0
- package/docs/books/admin-ui-authentication/02-session-model-and-token-model.md +75 -0
- package/docs/books/admin-ui-authentication/03-auth-middleware-patterns.md +77 -0
- package/docs/books/admin-ui-authentication/README.md +25 -0
- package/docs/books/creating-a-new-admin-ui/01-introduction-and-vision.md +130 -0
- package/docs/books/creating-a-new-admin-ui/02-architecture-and-data-flow.md +298 -0
- package/docs/books/creating-a-new-admin-ui/03-server-introspection.md +381 -0
- package/docs/books/creating-a-new-admin-ui/04-admin-module-adapter-layer.md +592 -0
- package/docs/books/creating-a-new-admin-ui/05-domain-controls-stat-cards-and-gauges.md +513 -0
- package/docs/books/creating-a-new-admin-ui/06-domain-controls-process-manager.md +544 -0
- package/docs/books/creating-a-new-admin-ui/07-domain-controls-resource-pool-inspector.md +493 -0
- package/docs/books/creating-a-new-admin-ui/08-domain-controls-route-table-and-api-explorer.md +586 -0
- package/docs/books/creating-a-new-admin-ui/09-domain-controls-log-viewer-and-activity-feed.md +490 -0
- package/docs/books/creating-a-new-admin-ui/10-domain-controls-build-status-and-bundle-inspector.md +526 -0
- package/docs/books/creating-a-new-admin-ui/11-domain-controls-configuration-panel.md +808 -0
- package/docs/books/creating-a-new-admin-ui/12-admin-shell-layout-sidebar-navigation.md +210 -0
- package/docs/books/creating-a-new-admin-ui/13-telemetry-integration.md +556 -0
- package/docs/books/creating-a-new-admin-ui/14-realtime-sse-observable-integration.md +485 -0
- package/docs/books/creating-a-new-admin-ui/15-styling-theming-aero-design-system.md +521 -0
- package/docs/books/creating-a-new-admin-ui/16-testing-and-quality-assurance.md +147 -0
- package/docs/books/creating-a-new-admin-ui/17-next-steps-process-resource-roadmap.md +356 -0
- package/docs/books/creating-a-new-admin-ui/README.md +68 -0
- package/docs/books/device-adaptive-composition/01-platform-feature-audit.md +177 -0
- package/docs/books/device-adaptive-composition/02-responsive-composition-model.md +187 -0
- package/docs/books/device-adaptive-composition/03-data-model-vs-view-model.md +231 -0
- package/docs/books/device-adaptive-composition/04-styling-theme-breakpoints.md +234 -0
- package/docs/books/device-adaptive-composition/05-showcase-app-multi-device-assessment.md +193 -0
- package/docs/books/device-adaptive-composition/06-implementation-patterns-and-apis.md +346 -0
- package/docs/books/device-adaptive-composition/07-testing-harness-and-quality-gates.md +265 -0
- package/docs/books/device-adaptive-composition/08-roadmap-and-adoption-plan.md +250 -0
- package/docs/books/device-adaptive-composition/README.md +47 -0
- package/docs/books/jsgui3-bundling-research-book/00-table-of-contents.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/01-pipeline-and-runtime-semantics.md +34 -0
- package/docs/books/jsgui3-bundling-research-book/02-javascript-bundling-core.md +36 -0
- package/docs/books/jsgui3-bundling-research-book/03-style-extraction-and-css-compilation.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/04-static-publishing-and-delivery.md +39 -0
- package/docs/books/jsgui3-bundling-research-book/05-current-limits-and-size-bloat-vectors.md +25 -0
- package/docs/books/jsgui3-bundling-research-book/06-unused-module-elimination-strategy.md +77 -0
- package/docs/books/jsgui3-bundling-research-book/07-jsgui3-html-control-and-mixin-pruning.md +63 -0
- package/docs/books/jsgui3-bundling-research-book/08-test-and-verification-methodology.md +43 -0
- package/docs/books/jsgui3-bundling-research-book/09-roadmap-and-rollout.md +42 -0
- package/docs/books/jsgui3-bundling-research-book/10-further-research-strategies-and-upgrades.md +211 -0
- package/docs/books/jsgui3-bundling-research-book/README.md +35 -0
- package/docs/bundling-system-deep-dive.md +9 -4
- package/docs/comparison-report-express-plex-cpanel.md +549 -0
- package/docs/comprehensive-documentation.md +49 -18
- package/docs/configuration-reference.md +152 -27
- package/docs/core/README.md +19 -0
- package/docs/core/jsgui3-server-core-book/00-table-of-contents.md +21 -0
- package/docs/core/jsgui3-server-core-book/01-startup-readiness-state-machine.md +41 -0
- package/docs/core/jsgui3-server-core-book/02-resource-abstraction-and-lifecycle.md +92 -0
- package/docs/core/jsgui3-server-core-book/03-resource-pool-and-event-topology.md +47 -0
- package/docs/core/jsgui3-server-core-book/04-sse-publisher-semantics.md +41 -0
- package/docs/core/jsgui3-server-core-book/05-serve-factory-resource-wiring.md +46 -0
- package/docs/core/jsgui3-server-core-book/06-e2e-testing-methodology.md +48 -0
- package/docs/core/jsgui3-server-core-book/07-defect-detection-and-hardening-loop.md +47 -0
- package/docs/designs/server-admin-interface-aero.svg +611 -0
- package/docs/publishers-guide.md +59 -4
- package/docs/resources-guide.md +184 -35
- package/docs/simple-server-api-design.md +72 -17
- package/docs/system-architecture.md +18 -14
- package/docs/troubleshooting.md +84 -53
- package/examples/controls/15) window, observable SSE/server.js +6 -1
- package/examples/controls/19) window, auto observable ui/server.js +9 -0
- package/examples/controls/20) window, task manager app/README.md +133 -0
- package/examples/controls/20) window, task manager app/client.js +797 -0
- package/examples/controls/20) window, task manager app/server.js +178 -0
- package/examples/controls/6) window, color_palette/client.js +165 -68
- package/examples/controls/9) window, date picker/client.js +362 -76
- package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +104 -83
- package/examples/jsgui3-html/06) theming/client.js +22 -1
- package/examples/jsgui3-html/10) binding-debugger/client.js +137 -1
- package/http/responders/static/Static_Route_HTTP_Responder.js +52 -34
- package/lab/experiments/capture-color-controls.js +196 -0
- package/lab/results/screenshots/color-controls/full_page.png +0 -0
- package/lab/results/screenshots/color-controls/section_1_color_grid_12x12.png +0 -0
- package/lab/results/screenshots/color-controls/section_2_color_grid_4x2.png +0 -0
- package/lab/results/screenshots/color-controls/section_3_color_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_4_palette_comparison.png +0 -0
- package/lab/results/screenshots/color-controls/section_5_raw_swatches.png +0 -0
- package/lab/results/screenshots/color-controls/section_6_optimized_crayola.png +0 -0
- package/lab/results/screenshots/color-controls/section_7_pastel_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_8_extended_144.png +0 -0
- package/lab/screenshot-utils.js +248 -0
- package/module.js +12 -0
- package/package.json +12 -2
- package/publishers/Publishers.js +4 -3
- package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +5 -5
- package/publishers/http-sse-publisher.js +341 -0
- package/resources/process-resource.js +950 -0
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +129 -33
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +18 -7
- package/resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer.js +829 -0
- package/resources/remote-process-resource.js +355 -0
- package/resources/server-resource-pool.js +354 -41
- package/serve-factory.js +442 -259
- package/server.js +288 -13
- package/tests/README.md +71 -4
- package/tests/admin-ui-jsgui-controls.test.js +581 -0
- package/tests/admin-ui-render.test.js +24 -0
- package/tests/assigners.test.js +56 -40
- package/tests/bundling-default-control-elimination.puppeteer.test.js +260 -0
- package/tests/configuration-validation.test.js +21 -18
- package/tests/content-analysis.test.js +7 -6
- package/tests/control-optimizer-cache-behavior.test.js +52 -0
- package/tests/control-scan-manifest-regression.test.js +144 -0
- package/tests/end-to-end.test.js +15 -14
- package/tests/error-handling.test.js +222 -179
- package/tests/fixtures/bundling-default-button-client.js +37 -0
- package/tests/fixtures/bundling-default-window-client.js +34 -0
- package/tests/fixtures/control_scan_manifest_expectations.json +48 -0
- package/tests/fixtures/resource-monitor-client.js +319 -0
- package/tests/helpers/puppeteer-e2e-harness.js +317 -0
- package/tests/http-sse-publisher.test.js +136 -0
- package/tests/performance.test.js +69 -65
- package/tests/process-resource.test.js +138 -0
- package/tests/publishers.test.js +7 -7
- package/tests/remote-process-resource.test.js +160 -0
- package/tests/sass-controls.e2e.test.js +7 -1
- package/tests/serve-resources.test.js +270 -0
- package/tests/serve.test.js +120 -50
- package/tests/server-resource-pool.test.js +106 -0
- package/tests/small-controls-bundle-size.test.js +252 -0
- package/tests/test-runner.js +14 -1
- package/tests/window-examples.puppeteer.test.js +204 -1
- package/tests/window-resource-integration.puppeteer.test.js +585 -0
- package/tests/temp_invalid.js +0 -7
- package/tests/temp_invalid_utf8.js +0 -1
- package/tests/temp_malformed.js +0 -10
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Mobile Developer
|
|
3
|
+
|
|
4
|
+
description: Device-adaptive UI specialist for jsgui3-html. Uses the Device-Adaptive Composition book to guide responsive layout, composition, theming, and testing across phone, tablet, and desktop.
|
|
5
|
+
|
|
6
|
+
tools: [vscode, execute, read, agent, edit, search, web, 'playwright/*', todo]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
argument-hint: A responsive/adaptive UI task, layout question, or multi-device composition problem.
|
|
10
|
+
---
|
|
11
|
+
# Mission
|
|
12
|
+
For any work involving responsive layout, multi-device composition, adaptive styling, or mobile/tablet support in jsgui3-html, anchor all decisions in the **Device-Adaptive Composition & Styling** book at `docs/books/device-adaptive-composition/`.
|
|
13
|
+
|
|
14
|
+
# Reference Book — Required Reading
|
|
15
|
+
|
|
16
|
+
Before starting any task, read the relevant chapters:
|
|
17
|
+
|
|
18
|
+
| Chapter | File | When to consult |
|
|
19
|
+
|---------|------|----------------|
|
|
20
|
+
| 1 — Platform Feature Audit | `docs/books/device-adaptive-composition/01-platform-feature-audit.md` | Understanding what layout primitives, tokens, and MVVM infrastructure already exist |
|
|
21
|
+
| 2 — Responsive Composition Model | `docs/books/device-adaptive-composition/02-responsive-composition-model.md` | Designing adaptive shells, choosing between CSS and JS composition, the four-layer model |
|
|
22
|
+
| 3 — Data Model vs View Model | `docs/books/device-adaptive-composition/03-data-model-vs-view-model.md` | Deciding where adaptive state lives (view.data.model, never data.model) |
|
|
23
|
+
| 4 — Styling, Themes, and Breakpoints | `docs/books/device-adaptive-composition/04-styling-theme-breakpoints.md` | Token overrides, density modes, mode attributes, touch target sizing |
|
|
24
|
+
| 5 — Showcase App Assessment | `docs/books/device-adaptive-composition/05-showcase-app-multi-device-assessment.md` | Understanding how the showcase app should adapt per device category |
|
|
25
|
+
| 6 — Implementation Patterns and APIs | `docs/books/device-adaptive-composition/06-implementation-patterns-and-apis.md` | Using View_Environment, compose_adaptive(), responsive params, container-aware utilities |
|
|
26
|
+
| 7 — Testing Harness and Quality Gates | `docs/books/device-adaptive-composition/07-testing-harness-and-quality-gates.md` | Writing viewport-matrix Playwright tests, assertion categories (P0/P1/P2) |
|
|
27
|
+
| 8 — Roadmap and Adoption Plan | `docs/books/device-adaptive-composition/08-roadmap-and-adoption-plan.md` | Phased rollout priorities, what to build vs what to skip |
|
|
28
|
+
|
|
29
|
+
# Non-negotiables
|
|
30
|
+
|
|
31
|
+
- **Consult the book first**: before proposing any adaptive/responsive solution, read the relevant chapter(s) and identify which patterns apply.
|
|
32
|
+
- **Use the four-layer model** (Chapter 2): separate Domain Composition, View Composition, Adaptive Resolution, and Concrete Render concerns.
|
|
33
|
+
- **Keep adaptive state in view models** (Chapter 3): never put layout_mode, density, viewport dimensions, or panel visibility in `data.model`.
|
|
34
|
+
- **Use mode attributes over scattered breakpoints** (Chapter 4): prefer `[data-layout-mode="phone"]` CSS selectors over raw `@media` queries.
|
|
35
|
+
- **Follow the snake_case convention**: all variables, methods, and file names use snake_case per AGENTS.md.
|
|
36
|
+
- **Name the pattern(s)** from the book that you're applying and cite the chapter.
|
|
37
|
+
|
|
38
|
+
# When this applies
|
|
39
|
+
|
|
40
|
+
- Any change involving responsive layout, adaptive composition, or multi-device support
|
|
41
|
+
- Adding or modifying layout primitives (Stack, Drawer, Grid_Gap, Split_Pane)
|
|
42
|
+
- Implementing density modes, touch target sizing, or interaction-mode awareness
|
|
43
|
+
- Writing viewport-matrix Playwright tests
|
|
44
|
+
- Theme profile work involving density or layout-mode token overrides
|
|
45
|
+
- Assessing how a control or app behaves on phone, tablet, or desktop
|
|
46
|
+
|
|
47
|
+
# Key Concepts from the Book
|
|
48
|
+
|
|
49
|
+
## Four-Layer Composition (Chapter 2)
|
|
50
|
+
- **Layer A** (Domain): business data — device-agnostic, lives in `data.model`
|
|
51
|
+
- **Layer B** (View): regions and component hierarchy — expresses adaptive intent
|
|
52
|
+
- **Layer C** (Adaptive Resolution): environment service resolves mode from viewport/input/preferences
|
|
53
|
+
- **Layer D** (Concrete Render): resolved CSS classes, token values, DOM attributes
|
|
54
|
+
|
|
55
|
+
## Environment Contract (Chapters 2, 6)
|
|
56
|
+
```js
|
|
57
|
+
context.view_environment = {
|
|
58
|
+
viewport: { width, height, orientation },
|
|
59
|
+
layout_mode: 'phone' | 'tablet' | 'desktop',
|
|
60
|
+
density_mode: 'compact' | 'cozy' | 'comfortable',
|
|
61
|
+
interaction_mode: 'touch' | 'pointer' | 'hybrid',
|
|
62
|
+
motion_mode: 'normal' | 'reduced'
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
Composition Helper (Chapter 6)
|
|
66
|
+
|
|
67
|
+
compose_adaptive(this, {
|
|
68
|
+
phone: () => this.compose_phone_shell(),
|
|
69
|
+
tablet: () => this.compose_tablet_shell(),
|
|
70
|
+
desktop: () => this.compose_desktop_shell()
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
Viewport Test Matrix (Chapter 7)
|
|
74
|
+
Phone portrait (390×844), Phone landscape (844×390), Tablet portrait (768×1024), Tablet landscape (1024×768), Desktop narrow (1280×720), Desktop wide (1920×1080).
|
|
75
|
+
|
|
76
|
+
If the book doesn't cover it, consult:
|
|
77
|
+
AGENTS.md — project-wide naming conventions, testing patterns, coding style
|
|
78
|
+
docs/accessibility_and_semantics.md — WCAG/ARIA guidance
|
|
79
|
+
control_mixins/keyboard_navigation.js — orientation-aware keyboard handling
|
|
80
|
+
css/jsgui-tokens.css — current token definitions
|
|
81
|
+
controls/organised/AGENT.md — control creation and theming guide
|
|
82
|
+
Output format for adaptive UI tasks
|
|
83
|
+
Include:
|
|
84
|
+
|
|
85
|
+
Book reference: which chapter(s) and pattern(s) apply
|
|
86
|
+
Layer analysis: which of the four layers (A/B/C/D) are affected
|
|
87
|
+
Model placement: what state goes in data.model vs view.data.model vs view.model
|
|
88
|
+
Composition approach: CSS-only (continuous) vs JS composition (discrete) vs both
|
|
89
|
+
Test coverage: which viewport profiles to test, which assertion categories (P0/P1/P2)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Control Scan Manifest Check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- master
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
control-scan-manifest:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Setup Node
|
|
19
|
+
uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: '20'
|
|
22
|
+
cache: 'npm'
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: npm ci
|
|
26
|
+
|
|
27
|
+
- name: Strict manifest regression test
|
|
28
|
+
run: node tests/test-runner.js --test=control-scan-manifest-regression.test.js
|
|
29
|
+
|
|
30
|
+
- name: Small controls bundle check
|
|
31
|
+
run: node tests/test-runner.js --test=small-controls-bundle-size.test.js
|
package/AGENTS.md
CHANGED
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
- **[docs/agent-development-guide.md](docs/agent-development-guide.md)** - Guide for AI agents working on this codebase
|
|
37
37
|
- **[docs/broken-functionality-tracker.md](docs/broken-functionality-tracker.md)** - Tracker for broken/incomplete functionality
|
|
38
38
|
|
|
39
|
+
### Admin UI
|
|
40
|
+
- **[docs/admin-extension-guide.md](docs/admin-extension-guide.md)** - Admin UI extension API: custom sections, endpoints, plugins, exported classes
|
|
41
|
+
|
|
39
42
|
### Review and Maintenance
|
|
40
43
|
- **[docs/documentation-review/CURRENT_REVIEW.md](docs/documentation-review/CURRENT_REVIEW.md)** - Current documentation review status and known issues
|
|
41
44
|
|
|
@@ -58,6 +61,7 @@
|
|
|
58
61
|
- **Custom control development** → `docs/controls-development.md`
|
|
59
62
|
- **Publisher system** → `docs/publishers-guide.md`
|
|
60
63
|
- **Resource management** → `docs/resources-guide.md`
|
|
64
|
+
- **Admin UI extensions** → `docs/admin-extension-guide.md`
|
|
61
65
|
|
|
62
66
|
### Agent Development
|
|
63
67
|
- **Agentic workflow patterns** → `docs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md`
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ This is the primary entry point for understanding the JSGUI3 Server project. Rea
|
|
|
8
8
|
- You're looking for quick start guides and basic usage examples
|
|
9
9
|
- You need to understand the project's capabilities and limitations
|
|
10
10
|
|
|
11
|
-
**Note:** For detailed API documentation, see [docs/comprehensive-documentation.md](docs/comprehensive-documentation.md). For advanced server API design, see [docs/simple-server-api-design.md](docs/simple-server-api-design.md).
|
|
11
|
+
**Note:** For detailed API documentation, see [docs/comprehensive-documentation.md](docs/comprehensive-documentation.md). For advanced server API design, see [docs/simple-server-api-design.md](docs/simple-server-api-design.md). For dense internals focused on startup, resources, SSE, and E2E verification, see [docs/core/jsgui3-server-core-book/00-table-of-contents.md](docs/core/jsgui3-server-core-book/00-table-of-contents.md). For deep bundling research and lightweight-bundle strategy, see [docs/books/jsgui3-bundling-research-book/README.md](docs/books/jsgui3-bundling-research-book/README.md).
|
|
12
12
|
|
|
13
13
|
# Jsgui3 Server
|
|
14
14
|
|
|
@@ -72,6 +72,66 @@ Server.serve({
|
|
|
72
72
|
});
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
### Managed Resources (In-Process, Direct Process, Remote Process)
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const Server = require('jsgui3-server');
|
|
79
|
+
const { Resource } = require('jsgui3-server');
|
|
80
|
+
|
|
81
|
+
class In_Process_Cache_Resource extends Resource {
|
|
82
|
+
constructor(spec = {}) {
|
|
83
|
+
super(spec);
|
|
84
|
+
this.cache = new Map();
|
|
85
|
+
}
|
|
86
|
+
start(callback) { callback(null, true); }
|
|
87
|
+
stop(callback) { this.cache.clear(); callback(null, true); }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const server = await Server.serve({
|
|
91
|
+
port: 3000,
|
|
92
|
+
api: {
|
|
93
|
+
'resources/summary': () => server.resource_pool.summary
|
|
94
|
+
},
|
|
95
|
+
resources: {
|
|
96
|
+
// Existing in-process resource instance
|
|
97
|
+
cache: new In_Process_Cache_Resource({ name: 'cache' }),
|
|
98
|
+
|
|
99
|
+
// Local child process (default process_manager is direct)
|
|
100
|
+
worker_direct: {
|
|
101
|
+
type: 'process',
|
|
102
|
+
command: process.execPath,
|
|
103
|
+
args: ['worker.js'],
|
|
104
|
+
autoRestart: true
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
// Local process managed by PM2 (pm2Path is optional)
|
|
108
|
+
worker_pm2: {
|
|
109
|
+
type: 'process',
|
|
110
|
+
processManager: {
|
|
111
|
+
type: 'pm2'
|
|
112
|
+
},
|
|
113
|
+
command: process.execPath,
|
|
114
|
+
args: ['worker.js']
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// Remote process controlled over HTTP
|
|
118
|
+
remote_worker: {
|
|
119
|
+
type: 'remote',
|
|
120
|
+
host: '127.0.0.1',
|
|
121
|
+
port: 3400
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
events: true // creates /events SSE endpoint and forwards pool resource lifecycle events
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
All process-style resources expose a consistent API:
|
|
129
|
+
- `start()`
|
|
130
|
+
- `stop()`
|
|
131
|
+
- `restart()`
|
|
132
|
+
- `status` (includes `state`, `pid`, `uptime`, `restartCount`, `lastHealthCheck`, `memoryUsage`, `processManager`)
|
|
133
|
+
- `get_abstract()`
|
|
134
|
+
|
|
75
135
|
### Real-time SSE Streams
|
|
76
136
|
|
|
77
137
|
```javascript
|
|
@@ -83,13 +143,161 @@ const obs = observable(next => {
|
|
|
83
143
|
|
|
84
144
|
// Start server and publish stream
|
|
85
145
|
const server = await Server.serve(MyControl);
|
|
86
|
-
|
|
87
|
-
//
|
|
146
|
+
|
|
147
|
+
// Simple name - auto-prefixes /api/
|
|
148
|
+
server.publish_observable('stream', obs);
|
|
149
|
+
// Server publishes SSE stream at http://localhost:8080/api/stream
|
|
150
|
+
|
|
151
|
+
// Or use full route path for custom routes
|
|
152
|
+
server.publish_observable('/custom/events', obs);
|
|
153
|
+
// Server publishes SSE stream at http://localhost:8080/custom/events
|
|
154
|
+
|
|
88
155
|
// Client connects via EventSource or Remote_Observable
|
|
89
156
|
```
|
|
90
157
|
|
|
158
|
+
### General SSE Publisher
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
const HTTP_SSE_Publisher = require('jsgui3-server/publishers/http-sse-publisher');
|
|
162
|
+
|
|
163
|
+
const sse_publisher = new HTTP_SSE_Publisher({ name: 'events' });
|
|
164
|
+
server.server_router.set_route('/events', sse_publisher, sse_publisher.handle_http);
|
|
165
|
+
|
|
166
|
+
sse_publisher.broadcast('resource_update', { running: 3, total: 5 });
|
|
167
|
+
```
|
|
168
|
+
|
|
91
169
|
> **Note:** The new `Server.serve()` API is the recommended approach for most use cases. See [Simple Server API Design](docs/simple-server-api-design.md) for complete documentation and advanced features.
|
|
92
170
|
|
|
171
|
+
## Admin UI Dashboard
|
|
172
|
+
|
|
173
|
+
Every jsgui3-server instance includes a built-in admin dashboard at `/admin/v1` with live stats, resource inspection, route listing, and SSE-driven heartbeat updates. The dashboard is session-authenticated (default dev credentials: `admin` / `admin`).
|
|
174
|
+
|
|
175
|
+
The admin shell is implemented with jsgui controls for navigation and dynamic panel rendering (control-first composition), and is covered by the interaction regression suite in `tests/admin-ui-jsgui-controls.test.js`.
|
|
176
|
+
|
|
177
|
+
### Disabling the Admin UI
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
Server.serve({ Ctrl: MyControl, admin: false });
|
|
181
|
+
|
|
182
|
+
// or
|
|
183
|
+
Server.serve({ Ctrl: MyControl, admin: { enabled: false } });
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Adding Custom Sections
|
|
187
|
+
|
|
188
|
+
Custom sections appear in the admin sidebar. When clicked, the shell fetches data from the section's API endpoint and auto-renders it as a table (arrays) or key-value panel (objects).
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
const server = await Server.serve(MyControl);
|
|
192
|
+
|
|
193
|
+
server.admin_v1.add_section({
|
|
194
|
+
id: 'crawlers',
|
|
195
|
+
label: 'Crawlers',
|
|
196
|
+
icon: '\uD83D\uDD77\uFE0F',
|
|
197
|
+
api_path: '/api/admin/v1/crawlers',
|
|
198
|
+
handler: (req, res) => {
|
|
199
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
200
|
+
res.end(JSON.stringify([
|
|
201
|
+
{ name: 'Site A', status: 'running', pages: 1234 },
|
|
202
|
+
{ name: 'Site B', status: 'idle', pages: 0 }
|
|
203
|
+
]));
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Adding Custom Protected Endpoints
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
server.admin_v1.add_endpoint({
|
|
212
|
+
path: '/api/admin/v1/crawlers/start',
|
|
213
|
+
role: 'admin_write',
|
|
214
|
+
handler: (req, res) => {
|
|
215
|
+
// start crawler logic
|
|
216
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
217
|
+
res.end(JSON.stringify({ ok: true }));
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Plugin Pattern
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
server.admin_v1.use((admin) => {
|
|
226
|
+
admin.add_section({
|
|
227
|
+
id: 'logs',
|
|
228
|
+
label: 'Logs',
|
|
229
|
+
icon: '\uD83D\uDCDC',
|
|
230
|
+
api_path: '/api/admin/v1/logs',
|
|
231
|
+
handler: (req, res) => {
|
|
232
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
233
|
+
res.end(JSON.stringify({ recent: ['log1', 'log2'] }));
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Admin UI Regression Test
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
node tests/test-runner.js --test=admin-ui-jsgui-controls.test.js
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Declarative Configuration via `Server.serve()`
|
|
246
|
+
|
|
247
|
+
Custom sections and endpoints can also be declared in the `Server.serve()` call:
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
Server.serve({
|
|
251
|
+
Ctrl: MyControl,
|
|
252
|
+
port: 8080,
|
|
253
|
+
admin: {
|
|
254
|
+
sections: [
|
|
255
|
+
{
|
|
256
|
+
id: 'jobs',
|
|
257
|
+
label: 'Jobs',
|
|
258
|
+
icon: '\u2699\uFE0F',
|
|
259
|
+
api_path: '/api/admin/v1/jobs',
|
|
260
|
+
handler: (req, res) => {
|
|
261
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
262
|
+
res.end(JSON.stringify([{ name: 'nightly-sync', status: 'complete' }]));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
],
|
|
266
|
+
endpoints: [
|
|
267
|
+
{
|
|
268
|
+
path: '/api/admin/v1/jobs/run',
|
|
269
|
+
role: 'admin_write',
|
|
270
|
+
handler: (req, res) => {
|
|
271
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
272
|
+
res.end(JSON.stringify({ ok: true }));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Exported Admin Classes
|
|
281
|
+
|
|
282
|
+
For advanced customisation, the admin classes are exported from the package:
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
285
|
+
const Server = require('jsgui3-server');
|
|
286
|
+
|
|
287
|
+
// Available on the Server constructor:
|
|
288
|
+
Server.Admin_Module_V1 // Admin adapter (sections, endpoints, auth, SSE)
|
|
289
|
+
Server.Admin_Auth_Service // Session management, cookie handling, role checking
|
|
290
|
+
Server.Admin_User_Store // In-memory user credential store (scrypt)
|
|
291
|
+
|
|
292
|
+
// Also available from the npm module entry:
|
|
293
|
+
const jsgui = require('jsgui3-server');
|
|
294
|
+
jsgui.Admin_Module_V1
|
|
295
|
+
jsgui.Admin_Auth_Service
|
|
296
|
+
jsgui.Admin_User_Store
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
See [Admin Extension Guide](docs/admin-extension-guide.md) for detailed API reference.
|
|
300
|
+
|
|
93
301
|
## Architecture Overview
|
|
94
302
|
|
|
95
303
|
The server operates as a bridge between server-side JavaScript applications and browser clients, offering:
|
|
@@ -909,11 +1117,15 @@ Minimal example:
|
|
|
909
1117
|
```javascript
|
|
910
1118
|
// Inside your server bootstrap (after constructing Server)
|
|
911
1119
|
server.on('ready', () => {
|
|
1120
|
+
// Simple name - auto-prefixes /api/
|
|
912
1121
|
// Returns text/plain at GET/POST /api/hello
|
|
913
1122
|
server.publish('hello', name => `Hello ${name || 'world'}`);
|
|
914
1123
|
|
|
915
1124
|
// Returns application/json at GET/POST /api/sum
|
|
916
1125
|
server.publish('sum', ({ a, b }) => ({ sum: a + b }));
|
|
1126
|
+
|
|
1127
|
+
// Full route path for custom routes (no auto-prefix)
|
|
1128
|
+
server.publish('/custom/endpoint', () => ({ custom: true }));
|
|
917
1129
|
});
|
|
918
1130
|
```
|
|
919
1131
|
|
package/admin-ui/client.js
CHANGED
|
@@ -2,15 +2,19 @@ const jsgui = require('jsgui3-client');
|
|
|
2
2
|
const { controls, Control, mixins } = jsgui;
|
|
3
3
|
const Active_HTML_Document = require('../controls/Active_HTML_Document');
|
|
4
4
|
|
|
5
|
-
class Admin_Page extends Active_HTML_Document {
|
|
6
|
-
constructor(spec = {}) {
|
|
7
|
-
spec.__type_name = spec.__type_name || 'admin_page';
|
|
8
|
-
super(spec);
|
|
9
|
-
const { context } = this;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
class Admin_Page extends Active_HTML_Document {
|
|
6
|
+
constructor(spec = {}) {
|
|
7
|
+
spec.__type_name = spec.__type_name || 'admin_page';
|
|
8
|
+
super(spec);
|
|
9
|
+
const { context } = this;
|
|
10
|
+
|
|
11
|
+
this._menu_items = [];
|
|
12
|
+
this._section_labels = Object.create(null);
|
|
13
|
+
this._active_section = 'overview';
|
|
14
|
+
|
|
15
|
+
if (typeof this.body.add_class === 'function') {
|
|
16
|
+
this.body.add_class('admin-page');
|
|
17
|
+
}
|
|
14
18
|
|
|
15
19
|
const compose = () => {
|
|
16
20
|
// Sidebar
|
|
@@ -50,9 +54,9 @@ class Admin_Page extends Active_HTML_Document {
|
|
|
50
54
|
top_bar.add(this.page_title);
|
|
51
55
|
|
|
52
56
|
// Content Panel
|
|
53
|
-
const
|
|
54
|
-
main.add(
|
|
55
|
-
this.
|
|
57
|
+
const content_panel = new controls.div({ context, class: 'admin-content' });
|
|
58
|
+
main.add(content_panel);
|
|
59
|
+
this.content_panel = content_panel;
|
|
56
60
|
|
|
57
61
|
// Default content (Overview)
|
|
58
62
|
this._render_overview();
|
|
@@ -63,53 +67,79 @@ class Admin_Page extends Active_HTML_Document {
|
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
_add_menu_item(label, id, active = false) {
|
|
67
|
-
const item = new controls.div({
|
|
68
|
-
context: this.context,
|
|
69
|
-
class: `menu-item ${active ? 'active' : ''}`
|
|
70
|
-
});
|
|
71
|
-
item.dom.attributes['data-id'] = id;
|
|
72
|
-
item.add(label);
|
|
73
|
-
this.menu.add(item);
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
_add_menu_item(label, id, active = false) {
|
|
71
|
+
const item = new controls.div({
|
|
72
|
+
context: this.context,
|
|
73
|
+
class: `menu-item ${active ? 'active' : ''}`
|
|
74
|
+
});
|
|
75
|
+
item.dom.attributes['data-id'] = id;
|
|
76
|
+
item.add(label);
|
|
77
|
+
this.menu.add(item);
|
|
78
|
+
|
|
79
|
+
this._section_labels[id] = label;
|
|
80
|
+
this._menu_items.push({
|
|
81
|
+
id,
|
|
82
|
+
label,
|
|
83
|
+
control: item
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
item.on('click', () => {
|
|
87
|
+
this._activate_menu_item(id);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return item;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_set_control_text(control, text) {
|
|
94
|
+
if (!control) return;
|
|
95
|
+
if (typeof control.clear === 'function') {
|
|
96
|
+
control.clear();
|
|
97
|
+
}
|
|
98
|
+
if (typeof control.add === 'function') {
|
|
99
|
+
control.add(String(text == null ? '' : text));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_set_active_menu_item(id) {
|
|
104
|
+
this._menu_items.forEach((menu_item) => {
|
|
105
|
+
if (!menu_item.control) return;
|
|
106
|
+
if (menu_item.id === id) {
|
|
107
|
+
menu_item.control.add_class('active');
|
|
108
|
+
} else {
|
|
109
|
+
menu_item.control.remove_class('active');
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
_activate_menu_item(id) {
|
|
115
|
+
this._active_section = id;
|
|
116
|
+
this._set_active_menu_item(id);
|
|
117
|
+
|
|
118
|
+
const label = this._section_labels[id] || id;
|
|
119
|
+
this._set_control_text(this.page_title, label);
|
|
120
|
+
|
|
121
|
+
// Placeholder navigation logic
|
|
122
|
+
console.log('Navigate to:', id);
|
|
123
|
+
}
|
|
76
124
|
|
|
77
125
|
_render_overview() {
|
|
78
|
-
// Clear main content area (
|
|
79
|
-
if (this.
|
|
80
|
-
this.
|
|
81
|
-
}
|
|
126
|
+
// Clear main content area (content_panel is the admin-content div)
|
|
127
|
+
if (this.content_panel && this.content_panel.content && typeof this.content_panel.content.clear === 'function') {
|
|
128
|
+
this.content_panel.content.clear();
|
|
129
|
+
}
|
|
82
130
|
|
|
83
131
|
const welcome = new controls.div({ context: this.context, class: 'welcome-card' });
|
|
84
132
|
welcome.add(new controls.h3({ context: this.context }).add('Welcome directly to jsgui3-server Admin'));
|
|
85
133
|
welcome.add(new controls.p({ context: this.context }).add('Select a resource from the sidebar to inspect.'));
|
|
86
|
-
this.
|
|
134
|
+
this.content_panel.add(welcome);
|
|
87
135
|
}
|
|
88
136
|
|
|
89
|
-
activate() {
|
|
90
|
-
if (!this.__active) {
|
|
91
|
-
super.activate();
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
menu_items.forEach(el => {
|
|
96
|
-
el.addEventListener('click', () => {
|
|
97
|
-
// Update Active State
|
|
98
|
-
menu_items.forEach(i => i.classList.remove('active'));
|
|
99
|
-
el.classList.add('active');
|
|
100
|
-
|
|
101
|
-
// Update Title
|
|
102
|
-
const id = el.getAttribute('data-id');
|
|
103
|
-
const label = el.innerText;
|
|
104
|
-
document.querySelector('.page-title').innerText = label;
|
|
105
|
-
|
|
106
|
-
// Placeholder navigation logic
|
|
107
|
-
console.log('Navigate to:', id);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
137
|
+
activate() {
|
|
138
|
+
if (!this.__active) {
|
|
139
|
+
super.activate();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
113
143
|
|
|
114
144
|
Admin_Page.css = `
|
|
115
145
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|