From a16677c9b9e566f41136f4888e713963a24ee95f Mon Sep 17 00:00:00 2001 From: Harvmaster Date: Fri, 23 Oct 2026 08:55:50 +0000 Subject: [PATCH] Improve tui demo --- demo/tui.ts | 68 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/demo/tui.ts b/demo/tui.ts index 39f35aa..142ca35 100644 --- a/demo/tui.ts +++ b/demo/tui.ts @@ -1,3 +1,6 @@ +/// +import readline from 'node:readline'; + import { PrivateKey } from '@xo-cash/primitives'; import type { BaseSyncClient } from '../source/shared/base-client.js'; @@ -20,6 +23,10 @@ const resetFormatting = () => { return '\x1b[0m'; }; +// readline lets us get both whole lines and individual keypresses (for Escape) +// escapeCodeTimeout: how long to wait after Escape to see if it's part of a key sequence (default 500ms) +const rl = readline.createInterface({ input: process.stdin, output: process.stdout, escapeCodeTimeout: 0 }); + const startTUI = async (client: BaseSyncClient) => { // Listen and log out the resource change client.on('resource-instance-updated', (message) => { @@ -31,22 +38,55 @@ const startTUI = async (client: BaseSyncClient) => { // Connect to the sync server and subscribe to the resource await client.connect(); - await client.subscribe('encrypted-test'); + + const writeResourceLoop = async (resourceId: string) => { + while (true) { + // Print the prompt + process.stdout.write('> '); + + // Wait for the user to enter a command + // Resolves with the typed line, or null if Escape was pressed + const onKeypress = (_char: string, key: readline.Key) => key?.name === 'escape' && rl.emit('line', null); + process.stdin.on('keypress', onKeypress); + const line = await new Promise((resolve) => rl.once('line', resolve)); + process.stdin.off('keypress', onKeypress); + + // Escape exits the loop + if (line === null) return; + + if (line.trim()) { + await client.write(resourceId, line.trim()); + } + } + }; + + const selectResource = async () => { + while (true) { + console.log('Enter a resource:'); + + // Print the prompt + process.stdout.write('> '); + + // Wait for the user to enter a command + const line = await new Promise((resolve) => rl.once('line', resolve)); + const resourceId = line.trim(); + + if (resourceId) { + // Subscribe to the resource + await client.subscribe(resourceId); + + // Read the current instances + const instance = await client.read(resourceId); + console.dir(instance, { depth: null }); + + // Write to the resource + await writeResourceLoop(resourceId); + } + } + }; // Start the TUI loop - while (true) { - // Print the prompt - process.stdout.write('> '); - - // Wait for the user to enter a command - const data = await new Promise((resolve) => process.stdin.once('data', resolve)); - - // If the user entered a command, write it to the resource - if (data) { - const message = data.toString().trim(); - await client.write('encrypted-test', message); - } - } + await selectResource(); }; const clients = {