bitwrench 2.0.15 → 2.0.16

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 (51) hide show
  1. package/README.md +57 -21
  2. package/dist/bitwrench-bccl.cjs.js +3746 -0
  3. package/dist/bitwrench-bccl.cjs.min.js +40 -0
  4. package/dist/bitwrench-bccl.esm.js +3741 -0
  5. package/dist/bitwrench-bccl.esm.min.js +40 -0
  6. package/dist/bitwrench-bccl.umd.js +3752 -0
  7. package/dist/bitwrench-bccl.umd.min.js +40 -0
  8. package/dist/bitwrench-code-edit.cjs.js +57 -7
  9. package/dist/bitwrench-code-edit.cjs.min.js +9 -2
  10. package/dist/bitwrench-code-edit.es5.js +74 -11
  11. package/dist/bitwrench-code-edit.es5.min.js +9 -2
  12. package/dist/bitwrench-code-edit.esm.js +57 -7
  13. package/dist/bitwrench-code-edit.esm.min.js +9 -2
  14. package/dist/bitwrench-code-edit.umd.js +57 -7
  15. package/dist/bitwrench-code-edit.umd.min.js +9 -2
  16. package/dist/bitwrench-lean.cjs.js +413 -17
  17. package/dist/bitwrench-lean.cjs.min.js +7 -7
  18. package/dist/bitwrench-lean.es5.js +428 -16
  19. package/dist/bitwrench-lean.es5.min.js +5 -5
  20. package/dist/bitwrench-lean.esm.js +413 -17
  21. package/dist/bitwrench-lean.esm.min.js +7 -7
  22. package/dist/bitwrench-lean.umd.js +413 -17
  23. package/dist/bitwrench-lean.umd.min.js +7 -7
  24. package/dist/bitwrench.cjs.js +413 -17
  25. package/dist/bitwrench.cjs.min.js +7 -7
  26. package/dist/bitwrench.css +60 -17
  27. package/dist/bitwrench.es5.js +428 -16
  28. package/dist/bitwrench.es5.min.js +6 -6
  29. package/dist/bitwrench.esm.js +413 -17
  30. package/dist/bitwrench.esm.min.js +7 -7
  31. package/dist/bitwrench.min.css +1 -1
  32. package/dist/bitwrench.umd.js +413 -17
  33. package/dist/bitwrench.umd.min.js +7 -7
  34. package/dist/builds.json +168 -80
  35. package/dist/bwserve.cjs.js +646 -0
  36. package/dist/bwserve.esm.js +638 -0
  37. package/dist/sri.json +36 -28
  38. package/package.json +18 -3
  39. package/readme.html +62 -23
  40. package/src/bitwrench-bccl-entry.js +72 -0
  41. package/src/bitwrench-code-edit.js +56 -6
  42. package/src/bitwrench-color-utils.js +5 -6
  43. package/src/bitwrench-styles.js +20 -8
  44. package/src/bitwrench.js +385 -0
  45. package/src/bwserve/client.js +182 -0
  46. package/src/bwserve/index.js +352 -0
  47. package/src/bwserve/shell.js +103 -0
  48. package/src/cli/index.js +36 -15
  49. package/src/cli/serve.js +325 -0
  50. package/src/version.js +3 -3
  51. /package/bin/{bitwrench.js → bwcli.js} +0 -0
@@ -0,0 +1,325 @@
1
+ /**
2
+ * bwcli serve — CLI subcommand for bwserve pipe server.
3
+ *
4
+ * Serves a directory of bitwrench pages and accepts protocol messages
5
+ * via an input HTTP port or stdin. Broadcasts messages to all connected
6
+ * browser tabs.
7
+ *
8
+ * Usage:
9
+ * bwcli serve [dir] [--port N] [--listen N] [--stdin] [--theme name]
10
+ */
11
+
12
+ import { parseArgs } from 'node:util';
13
+ import { createServer } from 'node:http';
14
+ import { createReadStream } from 'node:fs';
15
+ import { VERSION } from '../version.js';
16
+
17
+ var SERVE_USAGE = `
18
+ bwcli serve v${VERSION} — Pipe server for browser UI
19
+
20
+ Usage:
21
+ bwcli serve [dir] [options]
22
+
23
+ Arguments:
24
+ dir Directory to serve static files from (default: .)
25
+
26
+ Options:
27
+ -p, --port <number> Browser-facing web port (default: 8080)
28
+ -l, --listen <number> Input port for protocol messages (default: 9000)
29
+ --stdin Read protocol messages from stdin (newline-delimited JSON)
30
+ -t, --theme <name> Theme preset or hex colors ("#pri,#sec")
31
+ --title <string> Page title (default: "bwcli serve")
32
+ --open Open browser on start
33
+ -v, --verbose Verbose output
34
+ -h, --help Print this help
35
+
36
+ Examples:
37
+ bwcli serve Serve . on :8080, listen on :9000
38
+ bwcli serve ./public --port 3000 Serve ./public on :3000
39
+ bwcli serve --stdin Read from pipe instead of input port
40
+ sensor-reader | bwcli serve --stdin Pipe sensor data to browser
41
+ curl -X POST :9000 -d '{"type":"replace","target":"#app","node":{"t":"h1","c":"Hi"}}'
42
+ `.trim();
43
+
44
+ /**
45
+ * Parse a message string — supports both strict JSON and r-prefixed relaxed JSON.
46
+ * @param {string} str
47
+ * @returns {Object|null} parsed message or null on error
48
+ */
49
+ function parseMessage(str) {
50
+ str = str.trim();
51
+ if (!str) return null;
52
+ try {
53
+ if (str.charAt(0) === 'r') {
54
+ return parseRelaxedJSON(str.slice(1));
55
+ }
56
+ return JSON.parse(str);
57
+ } catch (e) {
58
+ return null;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Parse relaxed JSON (single-quoted strings, trailing commas).
64
+ * State machine — walks char by char.
65
+ */
66
+ function parseRelaxedJSON(str) {
67
+ var out = [];
68
+ var i = 0;
69
+ var len = str.length;
70
+
71
+ while (i < len) {
72
+ var ch = str[i];
73
+
74
+ if (ch === "'") {
75
+ out.push('"');
76
+ i++;
77
+ while (i < len) {
78
+ var c = str[i];
79
+ if (c === '\\' && i + 1 < len) {
80
+ var next = str[i + 1];
81
+ if (next === "'") {
82
+ out.push("'");
83
+ } else {
84
+ out.push('\\');
85
+ out.push(next);
86
+ }
87
+ i += 2;
88
+ } else if (c === '"') {
89
+ out.push('\\"');
90
+ i++;
91
+ } else if (c === "'") {
92
+ break;
93
+ } else {
94
+ out.push(c);
95
+ i++;
96
+ }
97
+ }
98
+ out.push('"');
99
+ i++;
100
+ } else if (ch === '"') {
101
+ out.push(ch);
102
+ i++;
103
+ while (i < len) {
104
+ var c2 = str[i];
105
+ if (c2 === '\\' && i + 1 < len) {
106
+ out.push(c2);
107
+ out.push(str[i + 1]);
108
+ i += 2;
109
+ } else {
110
+ out.push(c2);
111
+ i++;
112
+ if (c2 === '"') break;
113
+ }
114
+ }
115
+ } else if (ch === ',') {
116
+ var j = i + 1;
117
+ while (j < len && (str[j] === ' ' || str[j] === '\t' || str[j] === '\n' || str[j] === '\r')) j++;
118
+ if (j < len && (str[j] === '}' || str[j] === ']')) {
119
+ i++;
120
+ } else {
121
+ out.push(ch);
122
+ i++;
123
+ }
124
+ } else {
125
+ out.push(ch);
126
+ i++;
127
+ }
128
+ }
129
+
130
+ return JSON.parse(out.join(''));
131
+ }
132
+
133
+ /**
134
+ * Run the serve subcommand.
135
+ * @param {string[]} argv - arguments after "serve"
136
+ */
137
+ export function runServe(argv) {
138
+ var values, positionals;
139
+
140
+ try {
141
+ var result = parseArgs({
142
+ args: argv,
143
+ strict: true,
144
+ allowPositionals: true,
145
+ options: {
146
+ port: { type: 'string', short: 'p' },
147
+ listen: { type: 'string', short: 'l' },
148
+ stdin: { type: 'boolean' },
149
+ theme: { type: 'string', short: 't' },
150
+ title: { type: 'string' },
151
+ open: { type: 'boolean' },
152
+ verbose: { type: 'boolean', short: 'v' },
153
+ help: { type: 'boolean', short: 'h' }
154
+ }
155
+ });
156
+ values = result.values;
157
+ positionals = result.positionals;
158
+ } catch (err) {
159
+ console.error('Error: ' + err.message);
160
+ console.error('Run "bwcli serve --help" for usage.');
161
+ process.exit(1);
162
+ }
163
+
164
+ if (values.help) {
165
+ console.log(SERVE_USAGE);
166
+ return;
167
+ }
168
+
169
+ var dir = positionals[0] || '.';
170
+ var webPort = values.port ? parseInt(values.port, 10) : 8080;
171
+ var listenPort = values.listen ? parseInt(values.listen, 10) : 9000;
172
+ var useStdin = !!values.stdin;
173
+ var theme = values.theme || null;
174
+ var title = values.title || 'bwcli serve';
175
+ var verbose = !!values.verbose;
176
+
177
+ if (isNaN(webPort) || webPort < 1 || webPort > 65535) {
178
+ console.error('Error: --port must be a number between 1 and 65535.');
179
+ process.exit(1);
180
+ }
181
+ if (!useStdin && (isNaN(listenPort) || listenPort < 1 || listenPort > 65535)) {
182
+ console.error('Error: --listen must be a number between 1 and 65535.');
183
+ process.exit(1);
184
+ }
185
+
186
+ // Dynamic import of bwserve to avoid loading it at parse time
187
+ import('../../src/bwserve/index.js').then(function(bwserve) {
188
+ startServer(bwserve, {
189
+ dir: dir,
190
+ webPort: webPort,
191
+ listenPort: listenPort,
192
+ useStdin: useStdin,
193
+ theme: theme,
194
+ title: title,
195
+ verbose: verbose,
196
+ open: !!values.open
197
+ });
198
+ }).catch(function(err) {
199
+ console.error('Failed to load bwserve: ' + err.message);
200
+ process.exit(1);
201
+ });
202
+ }
203
+
204
+ /**
205
+ * Start the bwserve pipe server.
206
+ */
207
+ function startServer(bwserve, opts) {
208
+ var app = bwserve.create({
209
+ port: opts.webPort,
210
+ title: opts.title,
211
+ static: opts.dir,
212
+ theme: opts.theme
213
+ });
214
+
215
+ // Register a passthrough page handler — just keeps clients alive
216
+ app.page('/', function(client) {
217
+ if (opts.verbose) {
218
+ console.error('[bwcli serve] Client connected: ' + client.id);
219
+ }
220
+ client.on('_disconnect', function() {
221
+ if (opts.verbose) {
222
+ console.error('[bwcli serve] Client disconnected: ' + client.id);
223
+ }
224
+ });
225
+ });
226
+
227
+ // Start web server
228
+ app.listen(function() {
229
+ console.error('bwcli serve v' + VERSION);
230
+ console.error(' Web server: http://localhost:' + opts.webPort);
231
+ console.error(' Static dir: ' + opts.dir);
232
+ if (opts.theme) console.error(' Theme: ' + opts.theme);
233
+
234
+ if (opts.useStdin) {
235
+ console.error(' Input: stdin (newline-delimited JSON)');
236
+ startStdinReader(app, opts.verbose);
237
+ } else {
238
+ console.error(' Input port: http://localhost:' + opts.listenPort);
239
+ startInputServer(app, opts.listenPort, opts.verbose);
240
+ }
241
+
242
+ console.error('');
243
+ console.error('Ready. Send protocol messages to push UI to browsers.');
244
+
245
+ if (opts.open) {
246
+ import('node:child_process').then(function(cp) {
247
+ var url = 'http://localhost:' + opts.webPort;
248
+ var cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
249
+ cp.exec(cmd + ' ' + url);
250
+ });
251
+ }
252
+ });
253
+ }
254
+
255
+ /**
256
+ * Start the input HTTP server for receiving protocol messages.
257
+ */
258
+ function startInputServer(app, listenPort, verbose) {
259
+ var inputServer = createServer(function(req, res) {
260
+ if (req.method !== 'POST') {
261
+ res.writeHead(405, { 'Content-Type': 'application/json' });
262
+ res.end(JSON.stringify({ error: 'Use POST' }));
263
+ return;
264
+ }
265
+
266
+ var body = '';
267
+ req.on('data', function(chunk) { body += chunk; });
268
+ req.on('end', function() {
269
+ var msg = parseMessage(body);
270
+ if (!msg) {
271
+ res.writeHead(400, { 'Content-Type': 'application/json' });
272
+ res.end(JSON.stringify({ error: 'Invalid message' }));
273
+ return;
274
+ }
275
+
276
+ var count = app.broadcast(msg);
277
+ if (verbose) {
278
+ console.error('[input] ' + msg.type + ' -> ' + count + ' client(s)');
279
+ }
280
+ res.writeHead(200, { 'Content-Type': 'application/json' });
281
+ res.end(JSON.stringify({ ok: true, clients: count }));
282
+ });
283
+ });
284
+
285
+ inputServer.listen(listenPort);
286
+ }
287
+
288
+ /**
289
+ * Read protocol messages from stdin (newline-delimited).
290
+ */
291
+ function startStdinReader(app, verbose) {
292
+ var buffer = '';
293
+
294
+ process.stdin.setEncoding('utf8');
295
+ process.stdin.on('data', function(chunk) {
296
+ buffer += chunk;
297
+ var lines = buffer.split('\n');
298
+ buffer = lines.pop() || '';
299
+
300
+ for (var i = 0; i < lines.length; i++) {
301
+ var line = lines[i].trim();
302
+ if (!line) continue;
303
+
304
+ var msg = parseMessage(line);
305
+ if (!msg) {
306
+ if (verbose) console.error('[stdin] Parse error: ' + line.slice(0, 80));
307
+ continue;
308
+ }
309
+
310
+ var count = app.broadcast(msg);
311
+ if (verbose) {
312
+ console.error('[stdin] ' + msg.type + ' -> ' + count + ' client(s)');
313
+ }
314
+ }
315
+ });
316
+
317
+ process.stdin.on('end', function() {
318
+ // Flush remaining buffer
319
+ if (buffer.trim()) {
320
+ var msg = parseMessage(buffer.trim());
321
+ if (msg) app.broadcast(msg);
322
+ }
323
+ if (verbose) console.error('[stdin] Input stream closed. Server stays running.');
324
+ });
325
+ }
package/src/version.js CHANGED
@@ -3,14 +3,14 @@
3
3
  * DO NOT EDIT DIRECTLY - Use npm run generate-version
4
4
  */
5
5
 
6
- export const VERSION = '2.0.15';
6
+ export const VERSION = '2.0.16';
7
7
  export const VERSION_INFO = {
8
- version: '2.0.15',
8
+ version: '2.0.16',
9
9
  name: 'bitwrench',
10
10
  description: 'A library for javascript UI functions.',
11
11
  license: 'BSD-2-Clause',
12
12
  homepage: 'https://deftio.github.com/bitwrench/pages',
13
13
  repository: 'git+https://github.com/deftio/bitwrench.git',
14
14
  author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
15
- buildDate: '2026-03-10T09:08:17.015Z'
15
+ buildDate: '2026-03-12T08:05:52.043Z'
16
16
  };
File without changes