bitwrench 2.0.16 → 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.
- package/README.md +127 -38
- package/dist/bitwrench-bccl.cjs.js +13 -9
- package/dist/bitwrench-bccl.cjs.min.js +2 -2
- package/dist/bitwrench-bccl.esm.js +13 -9
- package/dist/bitwrench-bccl.esm.min.js +2 -2
- package/dist/bitwrench-bccl.umd.js +13 -9
- package/dist/bitwrench-bccl.umd.min.js +2 -2
- package/dist/bitwrench-code-edit.cjs.js +1 -1
- package/dist/bitwrench-code-edit.cjs.min.js +1 -1
- package/dist/bitwrench-code-edit.es5.js +1 -1
- package/dist/bitwrench-code-edit.es5.min.js +1 -1
- package/dist/bitwrench-code-edit.esm.js +1 -1
- package/dist/bitwrench-code-edit.esm.min.js +1 -1
- package/dist/bitwrench-code-edit.umd.js +1 -1
- package/dist/bitwrench-code-edit.umd.min.js +1 -1
- package/dist/bitwrench-lean.cjs.js +1438 -920
- package/dist/bitwrench-lean.cjs.min.js +20 -20
- package/dist/bitwrench-lean.es5.js +1518 -1105
- package/dist/bitwrench-lean.es5.min.js +18 -18
- package/dist/bitwrench-lean.esm.js +1437 -920
- package/dist/bitwrench-lean.esm.min.js +20 -20
- package/dist/bitwrench-lean.umd.js +1438 -920
- package/dist/bitwrench-lean.umd.min.js +20 -20
- package/dist/bitwrench-util-css.cjs.js +236 -0
- package/dist/bitwrench-util-css.cjs.min.js +22 -0
- package/dist/bitwrench-util-css.es5.js +414 -0
- package/dist/bitwrench-util-css.es5.min.js +21 -0
- package/dist/bitwrench-util-css.esm.js +230 -0
- package/dist/bitwrench-util-css.esm.min.js +21 -0
- package/dist/bitwrench-util-css.umd.js +242 -0
- package/dist/bitwrench-util-css.umd.min.js +21 -0
- package/dist/bitwrench.cjs.js +1450 -928
- package/dist/bitwrench.cjs.min.js +21 -21
- package/dist/bitwrench.css +456 -132
- package/dist/bitwrench.es5.js +1563 -1140
- package/dist/bitwrench.es5.min.js +19 -19
- package/dist/bitwrench.esm.js +1450 -929
- package/dist/bitwrench.esm.min.js +21 -21
- package/dist/bitwrench.min.css +1 -1
- package/dist/bitwrench.umd.js +1450 -928
- package/dist/bitwrench.umd.min.js +21 -21
- package/dist/builds.json +178 -90
- package/dist/bwserve.cjs.js +528 -68
- package/dist/bwserve.esm.js +527 -69
- package/dist/sri.json +44 -36
- package/package.json +5 -2
- package/readme.html +136 -49
- package/src/bitwrench-bccl.js +12 -8
- package/src/bitwrench-color-utils.js +31 -9
- package/src/bitwrench-esm-entry.js +11 -0
- package/src/bitwrench-styles.js +439 -232
- package/src/bitwrench-util-css.js +229 -0
- package/src/bitwrench.js +979 -630
- package/src/bwserve/attach.js +57 -0
- package/src/bwserve/bwclient.js +141 -0
- package/src/bwserve/bwshell.js +102 -0
- package/src/bwserve/client.js +151 -1
- package/src/bwserve/index.js +139 -29
- package/src/cli/attach.js +555 -0
- package/src/cli/convert.js +2 -5
- package/src/cli/index.js +7 -0
- package/src/cli/inject.js +1 -1
- package/src/cli/layout-default.js +47 -32
- package/src/cli/serve.js +6 -2
- package/src/generate-css.js +11 -4
- package/src/vendor/html2canvas.min.js +20 -0
- package/src/version.js +3 -3
- package/src/bwserve/shell.js +0 -103
package/src/bwserve/index.js
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { BwServeClient } from './client.js';
|
|
20
|
-
import { generateShell } from './
|
|
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';
|
|
@@ -26,7 +28,16 @@ import { createServer } from 'http';
|
|
|
26
28
|
import { readFileSync, existsSync, statSync } from 'fs';
|
|
27
29
|
|
|
28
30
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
|
|
32
|
+
// Resolve dist/ — try source layout (src/bwserve/), then npm install layout,
|
|
33
|
+
// then dist/ itself (when running from dist/bwserve.esm.js)
|
|
29
34
|
var DIST_DIR = resolve(__dirname, '..', '..', 'dist');
|
|
35
|
+
if (!existsSync(DIST_DIR)) {
|
|
36
|
+
DIST_DIR = resolve(__dirname, '..', 'dist');
|
|
37
|
+
}
|
|
38
|
+
if (!existsSync(DIST_DIR)) {
|
|
39
|
+
DIST_DIR = __dirname;
|
|
40
|
+
}
|
|
30
41
|
|
|
31
42
|
// MIME type lookup for static file serving
|
|
32
43
|
var MIME_TYPES = {
|
|
@@ -55,6 +66,7 @@ var MIME_TYPES = {
|
|
|
55
66
|
* @param {string} [opts.static] - Directory to serve static files from
|
|
56
67
|
* @param {boolean} [opts.injectBitwrench=true] - Auto-inject bitwrench client JS
|
|
57
68
|
* @param {string|Object} [opts.theme] - Theme preset name or config object
|
|
69
|
+
* @param {boolean} [opts.allowScreenshot=false] - Enable client.screenshot() capability
|
|
58
70
|
* @returns {BwServeApp} Application instance
|
|
59
71
|
*/
|
|
60
72
|
export function create(opts) {
|
|
@@ -73,11 +85,13 @@ class BwServeApp {
|
|
|
73
85
|
this.staticDir = opts.static || null;
|
|
74
86
|
this.injectBitwrench = opts.injectBitwrench !== false;
|
|
75
87
|
this.theme = opts.theme || null;
|
|
88
|
+
this.allowExec = opts.allowExec || false;
|
|
89
|
+
this.allowScreenshot = opts.allowScreenshot || false;
|
|
76
90
|
this.keepAliveInterval = opts.keepAliveInterval || 15000;
|
|
77
91
|
this._pages = new Map();
|
|
78
92
|
this._clients = new Map();
|
|
79
|
-
this._server = null;
|
|
80
93
|
this._clientCounter = 0;
|
|
94
|
+
this._server = null;
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
/**
|
|
@@ -185,31 +199,61 @@ class BwServeApp {
|
|
|
185
199
|
// Parse URL path (strip query string)
|
|
186
200
|
var path = url.split('?')[0];
|
|
187
201
|
|
|
188
|
-
// /
|
|
189
|
-
if (path === '/
|
|
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') {
|
|
190
209
|
return this._serveDistFile(res, 'bitwrench.umd.js');
|
|
191
210
|
}
|
|
192
211
|
|
|
193
|
-
// /
|
|
194
|
-
if (path === '/
|
|
212
|
+
// /bw/lib/bitwrench.umd.min.js — serve minified
|
|
213
|
+
if (path === '/bw/lib/bitwrench.umd.min.js' && method === 'GET') {
|
|
195
214
|
return this._serveDistFile(res, 'bitwrench.umd.min.js');
|
|
196
215
|
}
|
|
197
216
|
|
|
198
|
-
// /
|
|
199
|
-
if (path === '/
|
|
217
|
+
// /bw/lib/bitwrench.css — serve bitwrench CSS
|
|
218
|
+
if (path === '/bw/lib/bitwrench.css' && method === 'GET') {
|
|
200
219
|
return this._serveDistFile(res, 'bitwrench.css');
|
|
201
220
|
}
|
|
202
221
|
|
|
203
|
-
// /
|
|
204
|
-
if (path.startsWith('/
|
|
205
|
-
var clientId = path.slice('/
|
|
222
|
+
// /bw/events/:clientId — SSE stream
|
|
223
|
+
if (path.startsWith('/bw/events/') && method === 'GET') {
|
|
224
|
+
var clientId = path.slice('/bw/events/'.length);
|
|
206
225
|
return this._handleSSE(req, res, clientId);
|
|
207
226
|
}
|
|
208
227
|
|
|
209
|
-
// /
|
|
210
|
-
if (path.startsWith('/
|
|
211
|
-
|
|
212
|
-
|
|
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);
|
|
213
257
|
}
|
|
214
258
|
|
|
215
259
|
// Registered page routes — serve shell HTML
|
|
@@ -219,7 +263,8 @@ class BwServeApp {
|
|
|
219
263
|
clientId: clientId2,
|
|
220
264
|
title: this.title,
|
|
221
265
|
theme: this.theme,
|
|
222
|
-
injectBitwrench: this.injectBitwrench
|
|
266
|
+
injectBitwrench: this.injectBitwrench,
|
|
267
|
+
allowExec: this.allowExec
|
|
223
268
|
});
|
|
224
269
|
// Store the page path for this client so SSE knows which handler to call
|
|
225
270
|
this._clients.set(clientId2, { pagePath: path, client: null });
|
|
@@ -284,6 +329,7 @@ class BwServeApp {
|
|
|
284
329
|
|
|
285
330
|
// Create client instance
|
|
286
331
|
var client = new BwServeClient(clientId, res);
|
|
332
|
+
client._allowScreenshot = this.allowScreenshot;
|
|
287
333
|
|
|
288
334
|
// Look up the pending client record (set during page serve)
|
|
289
335
|
var pending = self._clients.get(clientId);
|
|
@@ -316,37 +362,101 @@ class BwServeApp {
|
|
|
316
362
|
}
|
|
317
363
|
|
|
318
364
|
/**
|
|
319
|
-
*
|
|
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
|
+
*
|
|
320
374
|
* @private
|
|
321
375
|
*/
|
|
322
|
-
|
|
376
|
+
_handleReturn(req, res, route, clientId) {
|
|
323
377
|
var record = this._clients.get(clientId);
|
|
324
378
|
if (!record || !record.client) {
|
|
325
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
379
|
+
res.writeHead(404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
326
380
|
res.end(JSON.stringify({ error: 'Unknown client' }));
|
|
327
381
|
return;
|
|
328
382
|
}
|
|
329
383
|
|
|
330
384
|
var body = '';
|
|
331
|
-
req.on('data', function(chunk) {
|
|
332
|
-
body += chunk;
|
|
333
|
-
});
|
|
385
|
+
req.on('data', function(chunk) { body += chunk; });
|
|
334
386
|
req.on('end', function() {
|
|
335
387
|
try {
|
|
336
388
|
var data = JSON.parse(body);
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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': '*' });
|
|
341
403
|
res.end(JSON.stringify({ ok: true }));
|
|
342
404
|
} catch (e) {
|
|
343
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
405
|
+
res.writeHead(400, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
344
406
|
res.end(JSON.stringify({ error: e.message }));
|
|
345
407
|
}
|
|
346
408
|
});
|
|
347
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
|
+
}
|
|
348
456
|
}
|
|
349
457
|
|
|
350
|
-
export
|
|
458
|
+
export var version = VERSION;
|
|
459
|
+
|
|
460
|
+
export { BwServeApp, BwServeClient, generateShell };
|
|
351
461
|
|
|
352
|
-
export default { create, BwServeApp, BwServeClient };
|
|
462
|
+
export default { create, version: VERSION, BwServeApp, BwServeClient, generateShell };
|