bitwrench 2.0.17 → 2.0.18

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 (67) hide show
  1. package/README.md +127 -38
  2. package/dist/bitwrench-bccl.cjs.js +8 -8
  3. package/dist/bitwrench-bccl.cjs.min.js +3 -3
  4. package/dist/bitwrench-bccl.esm.js +8 -8
  5. package/dist/bitwrench-bccl.esm.min.js +3 -3
  6. package/dist/bitwrench-bccl.umd.js +8 -8
  7. package/dist/bitwrench-bccl.umd.min.js +2 -2
  8. package/dist/bitwrench-code-edit.cjs.js +1 -1
  9. package/dist/bitwrench-code-edit.cjs.min.js +1 -1
  10. package/dist/bitwrench-code-edit.es5.js +1 -1
  11. package/dist/bitwrench-code-edit.es5.min.js +1 -1
  12. package/dist/bitwrench-code-edit.esm.js +1 -1
  13. package/dist/bitwrench-code-edit.esm.min.js +1 -1
  14. package/dist/bitwrench-code-edit.umd.js +1 -1
  15. package/dist/bitwrench-code-edit.umd.min.js +1 -1
  16. package/dist/bitwrench-lean.cjs.js +941 -775
  17. package/dist/bitwrench-lean.cjs.min.js +20 -20
  18. package/dist/bitwrench-lean.es5.js +1012 -961
  19. package/dist/bitwrench-lean.es5.min.js +18 -18
  20. package/dist/bitwrench-lean.esm.js +941 -775
  21. package/dist/bitwrench-lean.esm.min.js +20 -20
  22. package/dist/bitwrench-lean.umd.js +941 -775
  23. package/dist/bitwrench-lean.umd.min.js +20 -20
  24. package/dist/bitwrench-util-css.cjs.js +236 -0
  25. package/dist/bitwrench-util-css.cjs.min.js +22 -0
  26. package/dist/bitwrench-util-css.es5.js +414 -0
  27. package/dist/bitwrench-util-css.es5.min.js +21 -0
  28. package/dist/bitwrench-util-css.esm.js +230 -0
  29. package/dist/bitwrench-util-css.esm.min.js +21 -0
  30. package/dist/bitwrench-util-css.umd.js +242 -0
  31. package/dist/bitwrench-util-css.umd.min.js +21 -0
  32. package/dist/bitwrench.cjs.js +948 -782
  33. package/dist/bitwrench.cjs.min.js +21 -21
  34. package/dist/bitwrench.css +456 -132
  35. package/dist/bitwrench.es5.js +1024 -970
  36. package/dist/bitwrench.es5.min.js +19 -19
  37. package/dist/bitwrench.esm.js +949 -783
  38. package/dist/bitwrench.esm.min.js +21 -21
  39. package/dist/bitwrench.min.css +1 -1
  40. package/dist/bitwrench.umd.js +948 -782
  41. package/dist/bitwrench.umd.min.js +21 -21
  42. package/dist/builds.json +178 -90
  43. package/dist/bwserve.cjs.js +514 -68
  44. package/dist/bwserve.esm.js +513 -69
  45. package/dist/sri.json +44 -36
  46. package/package.json +3 -2
  47. package/readme.html +136 -49
  48. package/src/bitwrench-bccl.js +7 -7
  49. package/src/bitwrench-color-utils.js +31 -9
  50. package/src/bitwrench-esm-entry.js +11 -0
  51. package/src/bitwrench-styles.js +439 -232
  52. package/src/bitwrench-util-css.js +229 -0
  53. package/src/bitwrench.js +483 -485
  54. package/src/bwserve/attach.js +57 -0
  55. package/src/bwserve/bwclient.js +141 -0
  56. package/src/bwserve/bwshell.js +102 -0
  57. package/src/bwserve/client.js +151 -1
  58. package/src/bwserve/index.js +127 -28
  59. package/src/cli/attach.js +555 -0
  60. package/src/cli/convert.js +2 -5
  61. package/src/cli/index.js +7 -0
  62. package/src/cli/inject.js +1 -1
  63. package/src/cli/serve.js +6 -2
  64. package/src/generate-css.js +11 -4
  65. package/src/vendor/html2canvas.min.js +20 -0
  66. package/src/version.js +3 -3
  67. package/src/bwserve/shell.js +0 -106
@@ -17,7 +17,9 @@
17
17
  */
18
18
 
19
19
  import { BwServeClient } from './client.js';
20
- import { generateShell } from './shell.js';
20
+ import { generateShell } from './bwshell.js';
21
+ import { generateAttachScript } from './attach.js';
22
+ import { VERSION } from '../version.js';
21
23
 
22
24
  // Resolve dist/ paths relative to the package root
23
25
  import { fileURLToPath } from 'url';
@@ -64,6 +66,7 @@ var MIME_TYPES = {
64
66
  * @param {string} [opts.static] - Directory to serve static files from
65
67
  * @param {boolean} [opts.injectBitwrench=true] - Auto-inject bitwrench client JS
66
68
  * @param {string|Object} [opts.theme] - Theme preset name or config object
69
+ * @param {boolean} [opts.allowScreenshot=false] - Enable client.screenshot() capability
67
70
  * @returns {BwServeApp} Application instance
68
71
  */
69
72
  export function create(opts) {
@@ -83,11 +86,12 @@ class BwServeApp {
83
86
  this.injectBitwrench = opts.injectBitwrench !== false;
84
87
  this.theme = opts.theme || null;
85
88
  this.allowExec = opts.allowExec || false;
89
+ this.allowScreenshot = opts.allowScreenshot || false;
86
90
  this.keepAliveInterval = opts.keepAliveInterval || 15000;
87
91
  this._pages = new Map();
88
92
  this._clients = new Map();
89
- this._server = null;
90
93
  this._clientCounter = 0;
94
+ this._server = null;
91
95
  }
92
96
 
93
97
  /**
@@ -195,31 +199,61 @@ class BwServeApp {
195
199
  // Parse URL path (strip query string)
196
200
  var path = url.split('?')[0];
197
201
 
198
- // /__bw/bitwrench.umd.js — serve bitwrench client library
199
- if (path === '/__bw/bitwrench.umd.js' && method === 'GET') {
202
+ // /bw/attach.js — self-contained attach script for remote debugging
203
+ if (path === '/bw/attach.js' && method === 'GET') {
204
+ return this._serveAttachScript(req, res);
205
+ }
206
+
207
+ // /bw/lib/bitwrench.umd.js — serve bitwrench client library
208
+ if (path === '/bw/lib/bitwrench.umd.js' && method === 'GET') {
200
209
  return this._serveDistFile(res, 'bitwrench.umd.js');
201
210
  }
202
211
 
203
- // /__bw/bitwrench.umd.min.js — serve minified
204
- if (path === '/__bw/bitwrench.umd.min.js' && method === 'GET') {
212
+ // /bw/lib/bitwrench.umd.min.js — serve minified
213
+ if (path === '/bw/lib/bitwrench.umd.min.js' && method === 'GET') {
205
214
  return this._serveDistFile(res, 'bitwrench.umd.min.js');
206
215
  }
207
216
 
208
- // /__bw/bitwrench.css — serve bitwrench CSS
209
- if (path === '/__bw/bitwrench.css' && method === 'GET') {
217
+ // /bw/lib/bitwrench.css — serve bitwrench CSS
218
+ if (path === '/bw/lib/bitwrench.css' && method === 'GET') {
210
219
  return this._serveDistFile(res, 'bitwrench.css');
211
220
  }
212
221
 
213
- // /__bw/events/:clientId — SSE stream
214
- if (path.startsWith('/__bw/events/') && method === 'GET') {
215
- var clientId = path.slice('/__bw/events/'.length);
222
+ // /bw/events/:clientId — SSE stream
223
+ if (path.startsWith('/bw/events/') && method === 'GET') {
224
+ var clientId = path.slice('/bw/events/'.length);
216
225
  return this._handleSSE(req, res, clientId);
217
226
  }
218
227
 
219
- // /__bw/action/:clientId action POST
220
- if (path.startsWith('/__bw/action/') && method === 'POST') {
221
- var actionClientId = path.slice('/__bw/action/'.length);
222
- return this._handleAction(req, res, actionClientId);
228
+ // CORS preflight for /bw/return/ (needed for cross-origin attach)
229
+ if (method === 'OPTIONS' && path.startsWith('/bw/return/')) {
230
+ res.writeHead(204, {
231
+ 'Access-Control-Allow-Origin': '*',
232
+ 'Access-Control-Allow-Methods': 'POST',
233
+ 'Access-Control-Allow-Headers': 'Content-Type'
234
+ });
235
+ res.end();
236
+ return;
237
+ }
238
+
239
+ // /bw/return/<route>/<clientId> — unified return channel
240
+ if (method === 'POST' && path.startsWith('/bw/return/')) {
241
+ var rest = path.slice('/bw/return/'.length);
242
+ var slash = rest.indexOf('/');
243
+ if (slash === -1) {
244
+ res.writeHead(400, { 'Content-Type': 'application/json' });
245
+ res.end(JSON.stringify({ error: 'Invalid return path' }));
246
+ return;
247
+ }
248
+ var route = rest.slice(0, slash);
249
+ var returnClientId = rest.slice(slash + 1);
250
+ return this._handleReturn(req, res, route, returnClientId);
251
+ }
252
+
253
+ // /bw/lib/vendor/:filename — serve vendored libraries (allowlisted)
254
+ if (path.startsWith('/bw/lib/vendor/') && method === 'GET') {
255
+ var vendorFile = path.slice('/bw/lib/vendor/'.length);
256
+ return this._serveVendorFile(res, vendorFile);
223
257
  }
224
258
 
225
259
  // Registered page routes — serve shell HTML
@@ -295,6 +329,7 @@ class BwServeApp {
295
329
 
296
330
  // Create client instance
297
331
  var client = new BwServeClient(clientId, res);
332
+ client._allowScreenshot = this.allowScreenshot;
298
333
 
299
334
  // Look up the pending client record (set during page serve)
300
335
  var pending = self._clients.get(clientId);
@@ -327,37 +362,101 @@ class BwServeApp {
327
362
  }
328
363
 
329
364
  /**
330
- * Handle an action POST from a client.
365
+ * Unified return channel handler.
366
+ * Handles all client-to-server POST-backs via /bw/return/<route>/<clientId>.
367
+ *
368
+ * Routes:
369
+ * action — fire-and-forget action dispatch (no requestId)
370
+ * query — resolve pending query promise
371
+ * mount — resolve pending mount promise
372
+ * screenshot — resolve pending screenshot promise
373
+ *
331
374
  * @private
332
375
  */
333
- _handleAction(req, res, clientId) {
376
+ _handleReturn(req, res, route, clientId) {
334
377
  var record = this._clients.get(clientId);
335
378
  if (!record || !record.client) {
336
- res.writeHead(404, { 'Content-Type': 'application/json' });
379
+ res.writeHead(404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
337
380
  res.end(JSON.stringify({ error: 'Unknown client' }));
338
381
  return;
339
382
  }
340
383
 
341
384
  var body = '';
342
- req.on('data', function(chunk) {
343
- body += chunk;
344
- });
385
+ req.on('data', function(chunk) { body += chunk; });
345
386
  req.on('end', function() {
346
387
  try {
347
388
  var data = JSON.parse(body);
348
- var action = data.action;
349
- var payload = data.data || data;
350
- record.client._dispatch(action, payload);
351
- res.writeHead(200, { 'Content-Type': 'application/json' });
389
+ if (route === 'action' || route === 'event') {
390
+ // Action/event dispatch (no requestId/pending pattern)
391
+ var action = route === 'event'
392
+ ? '_bw_event'
393
+ : (data.result ? data.result.action : data.action);
394
+ var payload = route === 'event'
395
+ ? (data.result || data)
396
+ : (data.result ? data.result.data : data.data || data);
397
+ record.client._dispatch(action, payload);
398
+ } else {
399
+ // All other routes: resolve pending promise
400
+ record.client._resolvePending(data.requestId, data);
401
+ }
402
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
352
403
  res.end(JSON.stringify({ ok: true }));
353
404
  } catch (e) {
354
- res.writeHead(400, { 'Content-Type': 'application/json' });
405
+ res.writeHead(400, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
355
406
  res.end(JSON.stringify({ error: e.message }));
356
407
  }
357
408
  });
358
409
  }
410
+
411
+ /**
412
+ * Serve the self-contained attach script at /bw/attach.js.
413
+ * Loads bitwrench + bwclient and auto-connects via SSE.
414
+ * @private
415
+ */
416
+ _serveAttachScript(req, res) {
417
+ try {
418
+ var js = generateAttachScript({ origin: '' });
419
+ res.writeHead(200, {
420
+ 'Content-Type': 'application/javascript; charset=utf-8',
421
+ 'Access-Control-Allow-Origin': '*',
422
+ 'Cache-Control': 'no-cache'
423
+ });
424
+ res.end(js);
425
+ } catch (err) {
426
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
427
+ res.end('Error generating attach script: ' + err.message);
428
+ }
429
+ }
430
+
431
+ /**
432
+ * Serve a vendored library file (allowlisted filenames only).
433
+ * @private
434
+ */
435
+ _serveVendorFile(res, filename) {
436
+ var allowed = ['html2canvas.min.js'];
437
+ if (allowed.indexOf(filename) === -1) {
438
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
439
+ res.end('Not found');
440
+ return;
441
+ }
442
+ var vendorDir = resolve(__dirname, '..', 'vendor');
443
+ var filePath = join(vendorDir, filename);
444
+ if (!existsSync(filePath)) {
445
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
446
+ res.end('Vendor file not found: ' + filename);
447
+ return;
448
+ }
449
+ var content = readFileSync(filePath);
450
+ res.writeHead(200, {
451
+ 'Content-Type': 'application/javascript; charset=utf-8',
452
+ 'Cache-Control': 'public, max-age=86400'
453
+ });
454
+ res.end(content);
455
+ }
359
456
  }
360
457
 
361
- export { BwServeApp, BwServeClient };
458
+ export var version = VERSION;
459
+
460
+ export { BwServeApp, BwServeClient, generateShell };
362
461
 
363
- export default { create, BwServeApp, BwServeClient };
462
+ export default { create, version: VERSION, BwServeApp, BwServeClient, generateShell };