@await-widget/runtime 0.0.31 → 0.0.33

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 (2) hide show
  1. package/bin/await-widget.js +81 -12
  2. package/package.json +1 -1
@@ -6,16 +6,25 @@ import http from 'node:http';
6
6
  import os from 'node:os';
7
7
  import path from 'node:path';
8
8
  import process from 'node:process';
9
+ import readline from 'node:readline';
9
10
 
10
11
  const defaultPort = 4343;
11
12
  const maxBodyBytes = 100 * 1024 * 1024;
12
13
  const zipDosTime = 0;
13
14
  const zipDosDate = 33;
14
- const excludedNames = new Set(['.git', '.build', 'node_modules', 'dist', 'build']);
15
+ const excludedNames = new Set([
16
+ 'node_modules',
17
+ 'package.json',
18
+ 'package-lock.json',
19
+ 'tsconfig.json',
20
+ 'xo.config.js',
21
+ ]);
22
+ const excludedSuffixes = ['.lock', '.lockb', '.yaml', '.yml', '.toml'];
15
23
  const crcTable = makeCrcTable();
16
24
  const bridgeInfoDirectory = '.await';
17
25
  const bridgeInfoFileName = 'bridge.json';
18
26
  const singleWidgetPath = '.';
27
+ const widgetDirectoryError = 'Run await-widget from a package root or first-level widget folder whose package.json includes @await-widget/runtime.';
19
28
 
20
29
  function main() {
21
30
  const options = parseArgs(process.argv.slice(2));
@@ -128,10 +137,10 @@ function parseAppArgs(args) {
128
137
  };
129
138
  }
130
139
 
131
- function startWorkspaceServer(options) {
140
+ async function startWorkspaceServer(options) {
132
141
  let roots;
133
142
  try {
134
- roots = resolveWidgetServerRoots(process.cwd());
143
+ roots = await resolveWidgetServerRoots(process.cwd());
135
144
  } catch (error) {
136
145
  console.error(error.message);
137
146
  process.exit(1);
@@ -394,22 +403,81 @@ function findPackageRoot(start) {
394
403
  }
395
404
  }
396
405
 
397
- function resolveWidgetServerRoots(start) {
406
+ async function resolveWidgetServerRoots(start) {
398
407
  const widgetRoot = path.resolve(start);
399
408
  const packageRoot = findPackageRoot(widgetRoot);
400
409
  if (
401
410
  !packageRoot
402
- || packageRoot === widgetRoot
403
- || path.dirname(widgetRoot) !== packageRoot
404
- || !isValidTopLevelName(path.basename(widgetRoot))
405
411
  || !hasRuntimeDependency(packageRoot)
406
412
  ) {
407
- throw new Error('Run await-widget from a first-level widget folder inside a package whose package.json includes @await-widget/runtime.');
413
+ throw new Error(widgetDirectoryError);
414
+ }
415
+
416
+ if (packageRoot === widgetRoot) {
417
+ return {packageRoot, widgetRoot: await selectWidgetRoot(packageRoot)};
418
+ }
419
+
420
+ if (path.dirname(widgetRoot) !== packageRoot || !isValidTopLevelName(path.basename(widgetRoot))) {
421
+ throw new Error(widgetDirectoryError);
408
422
  }
409
423
 
410
424
  return {packageRoot, widgetRoot};
411
425
  }
412
426
 
427
+ function selectWidgetRoot(packageRoot) {
428
+ const options = [
429
+ {name: `${path.basename(packageRoot)} (root)`, path: packageRoot},
430
+ ...fs.readdirSync(packageRoot, {withFileTypes: true})
431
+ .filter(entry => entry.isDirectory() && isValidTopLevelName(entry.name))
432
+ .sort((left, right) => left.name.localeCompare(right.name))
433
+ .map(entry => ({name: entry.name, path: path.join(packageRoot, entry.name)})),
434
+ ];
435
+ let selected = 0;
436
+ let rendered = false;
437
+ readline.emitKeypressEvents(process.stdin);
438
+ process.stdin.setRawMode(true);
439
+ process.stdin.resume();
440
+ console.log('Select a directory to connect:');
441
+
442
+ const render = () => {
443
+ if (rendered) {
444
+ readline.moveCursor(process.stdout, 0, -options.length);
445
+ readline.clearScreenDown(process.stdout);
446
+ }
447
+
448
+ process.stdout.write(`${options.map((option, index) => `${index === selected ? '❯' : ' '} ${option.name}`).join('\n')}\n`);
449
+ rendered = true;
450
+ };
451
+ render();
452
+
453
+ return new Promise(resolve => {
454
+ const cleanup = () => {
455
+ process.stdin.off('keypress', onKeypress);
456
+ process.stdin.setRawMode(false);
457
+ process.stdin.pause();
458
+ };
459
+ const onKeypress = (_character, key) => {
460
+ if (key.name === 'up' || key.name === 'down') {
461
+ selected = (selected + (key.name === 'up' ? options.length - 1 : 1)) % options.length;
462
+ render();
463
+ return;
464
+ }
465
+
466
+ if (key.name === 'return' || key.name === 'enter') {
467
+ cleanup();
468
+ resolve(options[selected].path);
469
+ return;
470
+ }
471
+
472
+ if (key.ctrl && key.name === 'c') {
473
+ cleanup();
474
+ process.exit(130);
475
+ }
476
+ };
477
+ process.stdin.on('keypress', onKeypress);
478
+ });
479
+ }
480
+
413
481
  function hasRuntimeDependency(packageRoot) {
414
482
  const manifest = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
415
483
  return Boolean(manifest.dependencies?.['@await-widget/runtime'] ?? manifest.devDependencies?.['@await-widget/runtime']);
@@ -420,7 +488,7 @@ function listDesktopWidgets(root) {
420
488
  }
421
489
 
422
490
  function isExcludedName(name) {
423
- return name.startsWith('.') || excludedNames.has(name);
491
+ return name.startsWith('.') || excludedNames.has(name) || excludedSuffixes.some(suffix => name.endsWith(suffix));
424
492
  }
425
493
 
426
494
  function widgetRootFromQuery(root, url) {
@@ -948,11 +1016,12 @@ function printHelp() {
948
1016
  await-widget [--port ${defaultPort}]
949
1017
  await-widget app <command> [options]
950
1018
 
951
- Start the Await computer connection from a first-level widget folder under a
952
- package whose package.json includes @await-widget/runtime.
1019
+ Start the Await computer connection from a package root or first-level widget
1020
+ folder whose package.json includes @await-widget/runtime. Starting from the
1021
+ package root opens a directory selector.
953
1022
 
954
1023
  What it does:
955
- - Serves the current widget folder to Await for live sync.
1024
+ - Serves the selected widget folder to Await for live sync.
956
1025
  - Prints a URL to paste into Await's Connect Computer sheet.
957
1026
  - Writes .await/bridge.json in the package root for app commands.
958
1027
  - Sends one-shot JSON app commands with await-widget app <command>.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@await-widget/runtime",
3
- "version": "0.0.31",
3
+ "version": "0.0.33",
4
4
  "description": "TypeScript declarations for Await widgets.",
5
5
  "license": "MIT",
6
6
  "author": "Maundy",