jsgui3-server 0.0.145 → 0.0.147

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.
Files changed (49) hide show
  1. package/README.md +16 -0
  2. package/docs/agent-development-guide.md +92 -9
  3. package/docs/books/jsgui3-mvvm-fullstack/00-overview.md +17 -0
  4. package/docs/books/jsgui3-mvvm-fullstack/01-stack-map.md +25 -0
  5. package/docs/books/jsgui3-mvvm-fullstack/02-control-lifecycle.md +32 -0
  6. package/docs/books/jsgui3-mvvm-fullstack/03-mvvm-basics.md +57 -0
  7. package/docs/books/jsgui3-mvvm-fullstack/04-bindings-and-validation.md +51 -0
  8. package/docs/books/jsgui3-mvvm-fullstack/05-full-stack-example.md +50 -0
  9. package/docs/books/jsgui3-mvvm-fullstack/06-testing.md +23 -0
  10. package/docs/books/jsgui3-mvvm-fullstack/07-troubleshooting.md +20 -0
  11. package/docs/books/jsgui3-mvvm-fullstack/08-agent-playbooks.md +30 -0
  12. package/docs/books/jsgui3-mvvm-fullstack/README.md +30 -0
  13. package/docs/comprehensive-documentation.md +145 -34
  14. package/docs/diagrams/jsgui3-progress-update.svg +181 -0
  15. package/docs/jsgui3-sass-patterns-book/01-vision-and-goals.md +31 -0
  16. package/docs/jsgui3-sass-patterns-book/02-stack-map.md +40 -0
  17. package/docs/jsgui3-sass-patterns-book/03-control-local-sass.md +60 -0
  18. package/docs/jsgui3-sass-patterns-book/04-extension-and-variants.md +76 -0
  19. package/docs/jsgui3-sass-patterns-book/05-theming-and-tokens.md +54 -0
  20. package/docs/jsgui3-sass-patterns-book/06-workspace-overrides.md +45 -0
  21. package/docs/jsgui3-sass-patterns-book/07-resource-and-bundling.md +46 -0
  22. package/docs/jsgui3-sass-patterns-book/08-examples.md +62 -0
  23. package/docs/jsgui3-sass-patterns-book/09-testing-and-adoption.md +27 -0
  24. package/docs/jsgui3-sass-patterns-book/README.md +23 -0
  25. package/docs/troubleshooting.md +44 -4
  26. package/examples/controls/14) window, canvas/client.js +1 -1
  27. package/examples/controls/14b) window, canvas (improved renderer)/client.js +1 -1
  28. package/examples/controls/14d) window, canvas globe/client.js +1 -1
  29. package/examples/controls/14e) window, canvas multithreaded/client.js +1 -1
  30. package/examples/controls/14f) window, canvas polyglobe/client.js +1 -1
  31. package/examples/controls/16) window, form container/client.js +254 -0
  32. package/examples/controls/16) window, form container/server.js +20 -0
  33. package/examples/controls/17) window, mvvm binding/client.js +530 -0
  34. package/examples/controls/17) window, mvvm binding/server.js +20 -0
  35. package/examples/controls/18) window, observable bindRemote/README.md +28 -0
  36. package/examples/controls/18) window, observable bindRemote/check.js +144 -0
  37. package/examples/controls/18) window, observable bindRemote/client.js +387 -0
  38. package/examples/controls/18) window, observable bindRemote/server.js +107 -0
  39. package/package.json +4 -4
  40. package/publishers/http-webpage-publisher.js +39 -16
  41. package/publishers/http-webpageorsite-publisher.js +48 -35
  42. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +87 -100
  43. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +89 -60
  44. package/server.js +199 -185
  45. package/tests/README.md +45 -9
  46. package/tests/bundlers.test.js +53 -47
  47. package/tests/examples-controls.e2e.test.js +3 -1
  48. package/tests/sass-controls.e2e.test.js +123 -9
  49. package/tests/server-publish-observable.test.js +99 -0
@@ -743,8 +743,48 @@ controls.MinimalControl = MinimalControl;
743
743
  module.exports = jsgui;
744
744
  ```
745
745
 
746
- This minimal setup helps isolate whether the issue is with your specific code or the framework itself.
747
-
748
- ---
749
-
746
+ This minimal setup helps isolate whether the issue is with your specific code or the framework itself.
747
+
748
+ ---
749
+
750
+ ## Bundling and Test Failures
751
+
752
+ ### `waiting for wp_publisher ready` or Publisher Ready Timeout
753
+
754
+ **Symptoms:**
755
+ - Tests hang while starting servers
756
+ - Logs show `waiting for wp_publisher ready`
757
+ - Tests time out without a clear stack trace
758
+
759
+ **Likely cause:** the JS/CSS bundler failed before emitting `ready`.
760
+
761
+ **What to check:**
762
+ 1. Look earlier in the log for bundler errors (esbuild, Sass, file resolution).
763
+ 2. Confirm `sass` is installed if you are running Sass tests.
764
+ 3. Validate the client entry path passed to `src_path_client_js`.
765
+
766
+ ### esbuild platform mismatch (Windows vs WSL)
767
+
768
+ **Symptoms:**
769
+ - Error: `You installed esbuild for another platform than the one you're currently using`
770
+
771
+ **Cause:** `node_modules` was installed on a different OS and reused in this environment.
772
+
773
+ **Fix:**
774
+ 1. Remove the existing `node_modules` from the current workspace.
775
+ 2. Reinstall dependencies in the current environment:
776
+ ```bash
777
+ npm install
778
+ ```
779
+ 3. If you prefer to keep the lockfile untouched, use:
780
+ ```bash
781
+ npm ci
782
+ ```
783
+ 4. As a fast workaround, you can try:
784
+ ```bash
785
+ npm rebuild esbuild
786
+ ```
787
+
788
+ ---
789
+
750
790
  Remember: Most issues can be resolved by carefully checking the console output, verifying file paths, and ensuring proper control lifecycle management. Start with the basics and work systematically through the possible causes.
@@ -181,7 +181,7 @@ class Demo_UI extends Active_HTML_Document {
181
181
  pos: [5, 5]
182
182
  });
183
183
  window.size = [480, 400];
184
- const canvas = new controls.canvas({
184
+ const canvas = new controls.Canvas({
185
185
  context
186
186
  });
187
187
  canvas.dom.attributes.id = 'globeCanvas'
@@ -329,7 +329,7 @@ class Demo_UI extends Active_HTML_Document {
329
329
  pos: [5, 5]
330
330
  });
331
331
  window.size = [480, 400];
332
- const canvas = new controls.canvas({
332
+ const canvas = new controls.Canvas({
333
333
  context
334
334
  });
335
335
  canvas.dom.attributes.id = 'globeCanvas'
@@ -23,7 +23,7 @@ class Demo_UI extends Active_HTML_Document {
23
23
  pos: [5, 5]
24
24
  });
25
25
  window.size = [1300, 1300];
26
- const canvas = new controls.canvas({
26
+ const canvas = new controls.Canvas({
27
27
  context
28
28
  });
29
29
  canvas.dom.attributes.id = 'globeCanvas'
@@ -877,7 +877,7 @@ class Demo_UI extends Active_HTML_Document {
877
877
  pos: [5, 5]
878
878
  });
879
879
  window.size = [1000, 1000];
880
- const canvas = new controls.canvas({
880
+ const canvas = new controls.Canvas({
881
881
  context
882
882
  });
883
883
  canvas.dom.attributes.id = 'globeCanvas'
@@ -515,7 +515,7 @@ class Demo_UI extends Active_HTML_Document {
515
515
  });
516
516
  windowCtrl.size = [1000, 1000];
517
517
 
518
- const canvas = new controls.canvas({ context });
518
+ const canvas = new controls.Canvas({ context });
519
519
  canvas.dom.attributes.id = 'globeCanvas';
520
520
  canvas.size = [900, 900];
521
521
 
@@ -0,0 +1,254 @@
1
+ const jsgui = require('jsgui3-client');
2
+ const { controls, Control } = jsgui;
3
+
4
+ const Active_HTML_Document = require('../../../controls/Active_HTML_Document');
5
+
6
+ const { Alert_Banner, Button, Form_Container, Window } = controls;
7
+
8
+ const validate_email = value => {
9
+ const trimmed = String(value || '').trim();
10
+ if (!trimmed) return 'Email is required.';
11
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) return 'Enter a valid email.';
12
+ return true;
13
+ };
14
+
15
+ const validate_age = value => {
16
+ if (value === '' || value === undefined || value === null) return true;
17
+ const numeric = Number(value);
18
+ if (!Number.isFinite(numeric)) return 'Enter a number.';
19
+ if (numeric < 16 || numeric > 120) return 'Age must be between 16 and 120.';
20
+ return true;
21
+ };
22
+
23
+ const validate_bio = value => {
24
+ const trimmed = String(value || '').trim();
25
+ if (trimmed.length < 20) return 'Share at least 20 characters.';
26
+ return true;
27
+ };
28
+
29
+ class Demo_UI extends Active_HTML_Document {
30
+ constructor(spec = {}) {
31
+ spec.__type_name = spec.__type_name || 'demo_ui';
32
+ super(spec);
33
+ const { context } = this;
34
+
35
+ if (typeof this.body.add_class === 'function') {
36
+ this.body.add_class('demo-ui');
37
+ }
38
+
39
+ const compose_ui = () => {
40
+ const window_ctrl = new Window({
41
+ context,
42
+ title: 'jsgui3-html Form_Container',
43
+ pos: [10, 10]
44
+ });
45
+
46
+ window_ctrl.size = [640, 520];
47
+
48
+ const alert_banner = new Alert_Banner({
49
+ context,
50
+ status: 'info',
51
+ message: 'Fill out the form and submit to see validation.'
52
+ });
53
+ alert_banner.add_class('form-banner');
54
+
55
+ const fields = [
56
+ {
57
+ name: 'full_name',
58
+ label: 'Full name',
59
+ required: true,
60
+ placeholder: 'Ada Lovelace'
61
+ },
62
+ {
63
+ name: 'email',
64
+ label: 'Email',
65
+ type: 'email',
66
+ required: true,
67
+ placeholder: 'ada@example.com',
68
+ validator: validate_email
69
+ },
70
+ {
71
+ name: 'age',
72
+ label: 'Age',
73
+ type: 'number',
74
+ placeholder: '36',
75
+ validator: validate_age
76
+ },
77
+ {
78
+ name: 'newsletter',
79
+ label: 'Newsletter',
80
+ type: 'checkbox',
81
+ value: true
82
+ },
83
+ {
84
+ name: 'bio',
85
+ label: 'Short bio',
86
+ type: 'textarea',
87
+ required: true,
88
+ placeholder: 'What are you working on?',
89
+ validator: validate_bio
90
+ }
91
+ ];
92
+
93
+ const form_container = new Form_Container({
94
+ context,
95
+ fields,
96
+ show_status_badge: true
97
+ });
98
+
99
+ const actions_row = new Control({
100
+ context,
101
+ tag_name: 'div'
102
+ });
103
+ actions_row.add_class('form-actions');
104
+
105
+ const submit_button = new Button({
106
+ context,
107
+ text: 'Submit'
108
+ });
109
+ submit_button.dom.attributes.type = 'submit';
110
+ submit_button.add_class('button-primary');
111
+
112
+ const reset_button = new Button({
113
+ context,
114
+ text: 'Reset'
115
+ });
116
+ reset_button.dom.attributes.type = 'button';
117
+ reset_button.add_class('button-secondary');
118
+
119
+ actions_row.add(submit_button);
120
+ actions_row.add(reset_button);
121
+
122
+ form_container.add(actions_row);
123
+
124
+ window_ctrl.inner.add(alert_banner);
125
+ window_ctrl.inner.add(form_container);
126
+
127
+ this.body.add(window_ctrl);
128
+
129
+ this.alert_banner = alert_banner;
130
+ this.form_container = form_container;
131
+ this.reset_button = reset_button;
132
+ };
133
+
134
+ if (!spec.el) {
135
+ compose_ui();
136
+ }
137
+ }
138
+
139
+ activate() {
140
+ if (!this.__active) {
141
+ super.activate();
142
+
143
+ const { form_container, alert_banner, reset_button } = this;
144
+
145
+ if (form_container && alert_banner) {
146
+ form_container.on('submit', e_submit => {
147
+ const values = e_submit && e_submit.values ? e_submit.values : {};
148
+ const summary_name = values.full_name ? `Thanks, ${values.full_name}.` : 'Thanks!';
149
+ alert_banner.set_status('success');
150
+ alert_banner.set_message(`${summary_name} Form submission looks good.`);
151
+ });
152
+
153
+ form_container.on('invalid', () => {
154
+ alert_banner.set_status('error');
155
+ alert_banner.set_message('Please fix the highlighted fields and try again.');
156
+ });
157
+ }
158
+
159
+ if (reset_button && form_container && alert_banner) {
160
+ reset_button.on('click', () => {
161
+ form_container.set_values({
162
+ full_name: '',
163
+ email: '',
164
+ age: '',
165
+ newsletter: false,
166
+ bio: ''
167
+ });
168
+
169
+ if (form_container.field_controls) {
170
+ Object.keys(form_container.field_controls).forEach(field_name => {
171
+ form_container.update_field_status(
172
+ form_container.field_controls[field_name],
173
+ '',
174
+ ''
175
+ );
176
+ });
177
+ }
178
+
179
+ alert_banner.set_status('info');
180
+ alert_banner.set_message('Form reset.');
181
+ });
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ Demo_UI.css = `
188
+ * {
189
+ margin: 0;
190
+ padding: 0;
191
+ }
192
+
193
+ body {
194
+ overflow-x: hidden;
195
+ overflow-y: hidden;
196
+ background-color: #e0e0e0;
197
+ }
198
+
199
+ .demo-ui .window .inner {
200
+ padding: 16px;
201
+ }
202
+
203
+ .demo-ui .form-banner {
204
+ margin-bottom: 12px;
205
+ }
206
+
207
+ .demo-ui .form-actions {
208
+ display: flex;
209
+ justify-content: flex-end;
210
+ gap: 12px;
211
+ padding-top: 8px;
212
+ }
213
+
214
+ .demo-ui .button-primary {
215
+ border: none;
216
+ border-radius: 4px;
217
+ padding: 6px 14px;
218
+ background: #0d47a1;
219
+ color: #fff;
220
+ cursor: pointer;
221
+ }
222
+
223
+ .demo-ui .button-secondary {
224
+ border: 1px solid #c5c5c5;
225
+ border-radius: 4px;
226
+ padding: 6px 14px;
227
+ background: #fff;
228
+ color: #333;
229
+ cursor: pointer;
230
+ }
231
+
232
+ @media (max-width: 720px) {
233
+ .demo-ui .window .inner {
234
+ padding: 12px;
235
+ }
236
+
237
+ .demo-ui .form-container-field {
238
+ grid-template-columns: 1fr;
239
+ gap: 6px;
240
+ }
241
+
242
+ .demo-ui .form-container-message {
243
+ grid-column: 1;
244
+ }
245
+
246
+ .demo-ui .form-actions {
247
+ flex-direction: column;
248
+ align-items: stretch;
249
+ }
250
+ }
251
+ `;
252
+
253
+ controls.Demo_UI = Demo_UI;
254
+ module.exports = jsgui;
@@ -0,0 +1,20 @@
1
+ const jsgui = require('./client');
2
+
3
+ const { Demo_UI } = jsgui.controls;
4
+ const Server = require('../../../server');
5
+
6
+ if (require.main === module) {
7
+ const server = new Server({
8
+ Ctrl: Demo_UI,
9
+ src_path_client_js: require.resolve('./client.js')
10
+ });
11
+
12
+ server.one('ready', () => {
13
+ server.start(52000, err => {
14
+ if (err) {
15
+ throw err;
16
+ }
17
+ console.log('server started');
18
+ });
19
+ });
20
+ }