termcut 0.6.0 → 0.6.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termcut",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Script terminal sessions in TypeScript, render them to reproducible MP4/GIF/WebM/SVG/HTML with Bun.",
5
5
  "license": "MIT",
6
6
  "author": "Aman Varshney",
package/src/browser.ts CHANGED
@@ -10,6 +10,12 @@ export interface BrowserCapture extends BrowserSession {
10
10
  stop(): Promise<void>;
11
11
  }
12
12
 
13
+ /** "better-t-stack.dev" → "https://better-t-stack.dev"; localhost defaults to http. */
14
+ export function normalizeUrl(url: string): string {
15
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(url) || /^(about|data|file|blob):/i.test(url)) return url;
16
+ return /^(localhost|127\.|0\.0\.0\.0|\[::1\])/.test(url) ? `http://${url}` : `https://${url}`;
17
+ }
18
+
13
19
  const toRegExp = (pattern: RegExp | string): RegExp =>
14
20
  typeof pattern === "string" ? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")) : pattern;
15
21
 
@@ -59,21 +65,28 @@ export function startBrowserCapture(config: ResolvedConfig, stamp: () => number,
59
65
  * or take a long first load (Vite pre-bundling, then a reload), so success is judged by the document's
60
66
  * readyState at the target URL rather than by the navigate() promise alone.
61
67
  */
62
- const goto = async (url: string): Promise<void> => {
68
+ const goto = async (rawUrl: string): Promise<void> => {
69
+ const url = normalizeUrl(rawUrl);
63
70
  const deadline = performance.now() + config.waitTimeout;
64
71
  const target = url.replace(/\/$/, "");
65
72
  let navigation: Promise<"ok" | "pending" | "failed"> | null = null;
66
73
  for (;;) {
67
- navigation ??= view.navigate(url).then(
74
+ if (!running) return; // stop() closed the view mid-retry; abort quietly
75
+ try {
76
+ navigation ??= view.navigate(url).then(
68
77
  () => "ok" as const,
69
- (err: unknown) => (/pending/i.test(String(err)) ? ("pending" as const) : ("failed" as const)),
70
- );
78
+ (err: unknown) => (/pending/i.test(String(err)) ? ("pending" as const) : ("failed" as const)),
79
+ );
80
+ } catch {
81
+ return; // navigate threw synchronously: the view is closed
82
+ }
71
83
  const outcome = await Promise.race([navigation, Bun.sleep(750).then(() => "tick" as const)]);
72
84
  if (outcome === "ok") {
73
85
  currentUrl = url;
74
86
  return;
75
87
  }
76
88
  if (outcome === "failed") navigation = null;
89
+ if (!running) return;
77
90
  const state = await within(view.evaluate("document.readyState"), 3000, "goto").catch(() => "");
78
91
  if (state === "complete" && (view.url ?? "").replace(/\/$/, "").startsWith(target)) {
79
92
  currentUrl = url;
package/src/config.ts CHANGED
@@ -68,6 +68,7 @@ export function resolveConfig(input: VideoConfig): ResolvedConfig {
68
68
  position: (config.keys === true ? undefined : config.keys.position) ?? "bottom",
69
69
  ttl: toMs(config.keys === true ? undefined : config.keys.ttl, 1200),
70
70
  merge: toMs(config.keys === true ? undefined : config.keys.merge, 350),
71
+ limit: (config.keys === true ? undefined : config.keys.limit) ?? 1,
71
72
  },
72
73
  }),
73
74
  fps: config.fps ?? 60,
@@ -232,7 +232,7 @@ export async function render(
232
232
  let chipsChanged = false;
233
233
  if (config.keys) {
234
234
  const ttl = config.keys.ttl / 1000;
235
- const visible = chips.filter((c) => c.at <= time + 1e-9 && time - c.at < ttl).slice(-6).map((c) => c.label);
235
+ const visible = chips.filter((c) => c.at <= time + 1e-9 && time - c.at < ttl).slice(-config.keys.limit).map((c) => c.label);
236
236
  const key = visible.join("\u0000");
237
237
  if (key !== lastChips) {
238
238
  await view.evaluate(`window.__vt.keys(${JSON.stringify(visible)})`);
package/src/types.ts CHANGED
@@ -54,6 +54,8 @@ export interface KeysConfig {
54
54
  ttl?: Duration;
55
55
  /** Printable keys pressed within this window merge into one chip. Default "350ms". */
56
56
  merge?: Duration;
57
+ /** How many chips are visible at once. Default 1 (the latest press replaces the previous). */
58
+ limit?: number;
57
59
  }
58
60
 
59
61
  /** A region of the terminal grid to magnify. */