@bobfrankston/brother-label 1.1.22 → 1.1.24

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/api.d.ts CHANGED
@@ -36,10 +36,15 @@ export declare function getConfig(): PrinterConfig;
36
36
  export declare function setConfig(config: Partial<PrinterConfig>): void;
37
37
  export declare function getConfigPath(): string;
38
38
  /**
39
- * The queue used when a caller names no printer: the configured default, else
40
- * the built-in fallback. Exported so callers can NAME the queue they are about
41
- * to use instead of saying "the default".
39
+ * The configured default queue, or null when none is set. Exported so callers
40
+ * can NAME the queue they are about to use instead of saying "the default".
42
41
  * Claude Code 2026-08-24.
42
+ *
43
+ * Claude Code 2026-09-01: this used to fall back to a wired-in
44
+ * "Brother PT-P710BT". That is exactly the bug Bob hit -- a machine with no
45
+ * configuration silently printed to a model name baked into the source, and
46
+ * nothing in the output said the choice had been invented rather than chosen.
47
+ * There is no fallback now; callers that need a printer use requirePrinter().
43
48
  */
44
49
  export declare function getDefaultPrinter(): string;
45
50
  export declare function listPrinters(): Promise<PrinterInfo[]>;
package/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"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"}
package/api.js CHANGED
@@ -11,10 +11,21 @@
11
11
  import * as fs from "fs";
12
12
  import * as os from "os";
13
13
  import * as path from "path";
14
- import { validateContent, resolveContent, renderSegments as coreRenderSegments, listPrinters as coreListPrinters, getPrinterStatus, waitOnline as coreWaitOnline, runScriptOrThrow, readJsonConfig, mergeJsonConfig, } from "@bobfrankston/label-core";
14
+ import { validateContent, resolveContent, renderSegments as coreRenderSegments, listPrinters as coreListPrinters, getPrinterStatus, waitOnline as coreWaitOnline, runScriptOrThrow, } from "@bobfrankston/label-core";
15
+ import { configDir, readJson5, writeJson5 } from "@bobfrankston/userconfig";
15
16
  /* ----- Constants ----- */
16
- const CONFIG_PATH = path.join(os.homedir(), ".brother-label.json");
17
- const DEFAULT_PRINTER = "Brother PT-P710BT";
17
+ /**
18
+ * The label config lives in the SHARED user-config directory, not beside this
19
+ * package, so every label utility (brother-print, iplabels, ...) reads one
20
+ * default instead of each keeping its own idea of "the printer".
21
+ *
22
+ * Claude Code 2026-09-01, at Bob's direction. The path comes from
23
+ * @bobfrankston/userconfig's `configDir` — never build it from homedir here;
24
+ * where that directory lives is UserConfig's business, not ours.
25
+ */
26
+ const CONFIG_PATH = path.join(configDir, "labels.json5");
27
+ /** Pre-2026-09-01 location. Read once to migrate, never written again. */
28
+ const LEGACY_CONFIG_PATH = path.join(os.homedir(), ".brother-label.json");
18
29
  const DEFAULT_PRINTER_PATTERN = /brother|^pt-|^ql-/i;
19
30
  const PRINT_DPI = 300;
20
31
  const VALID_TAPES = [6, 9, 12, 18, 24];
@@ -36,26 +47,63 @@ const MEDIA_OPTIONS = {
36
47
  };
37
48
  /* ----- Config (backward-compat — note "defaultTape" stays in JSON) ----- */
38
49
  export function getConfig() {
39
- const raw = readJsonConfig(CONFIG_PATH);
50
+ const raw = fs.existsSync(CONFIG_PATH) ? readJson5(CONFIG_PATH) : migrateLegacyConfig();
40
51
  if (typeof raw.defaultTape === "string") {
41
52
  raw.defaultTape = parseInt(raw.defaultTape.replace("mm", ""), 10);
42
53
  }
43
54
  return raw;
44
55
  }
56
+ /**
57
+ * Copy a pre-move ~/.brother-label.json into the new location the first time we
58
+ * look and find nothing there, so a default set before 2026-09-01 survives.
59
+ * Returns the settings either way; after the copy this never runs again.
60
+ */
61
+ function migrateLegacyConfig() {
62
+ if (!fs.existsSync(LEGACY_CONFIG_PATH))
63
+ return {};
64
+ let old;
65
+ try {
66
+ old = JSON.parse(fs.readFileSync(LEGACY_CONFIG_PATH, "utf-8"));
67
+ }
68
+ catch {
69
+ return {}; // Unreadable legacy file is not worth failing an install over
70
+ }
71
+ writeJson5(CONFIG_PATH, old);
72
+ return old;
73
+ }
45
74
  export function setConfig(config) {
46
- mergeJsonConfig(CONFIG_PATH, config);
75
+ writeJson5(CONFIG_PATH, { ...getConfig(), ...config });
47
76
  }
48
77
  export function getConfigPath() {
49
78
  return CONFIG_PATH;
50
79
  }
51
80
  /**
52
- * The queue used when a caller names no printer: the configured default, else
53
- * the built-in fallback. Exported so callers can NAME the queue they are about
54
- * to use instead of saying "the default".
81
+ * The configured default queue, or null when none is set. Exported so callers
82
+ * can NAME the queue they are about to use instead of saying "the default".
55
83
  * Claude Code 2026-08-24.
84
+ *
85
+ * Claude Code 2026-09-01: this used to fall back to a wired-in
86
+ * "Brother PT-P710BT". That is exactly the bug Bob hit -- a machine with no
87
+ * configuration silently printed to a model name baked into the source, and
88
+ * nothing in the output said the choice had been invented rather than chosen.
89
+ * There is no fallback now; callers that need a printer use requirePrinter().
56
90
  */
57
91
  export function getDefaultPrinter() {
58
- return getConfig().defaultPrinter ?? DEFAULT_PRINTER;
92
+ return getConfig().defaultPrinter ?? null;
93
+ }
94
+ /**
95
+ * The queue to use when the caller named none -- or a user error saying how to
96
+ * set one. Every path that is about to move bytes goes through here, so "no
97
+ * printer" is reported once, in one voice, instead of each call site guessing.
98
+ */
99
+ function requirePrinter(printerName) {
100
+ const printer = printerName ?? getDefaultPrinter();
101
+ if (!printer) {
102
+ throw userError(`No printer named and no default set. Set one with ` +
103
+ `'brother-print -default <name>', or name a printer with -p. ` +
104
+ `'brother-print -list' shows what is installed.`);
105
+ }
106
+ return printer;
59
107
  }
60
108
  /* ----- Printer listing (backward-compat shape: { name }[]) ----- */
61
109
  export async function listPrinters() {
@@ -131,6 +179,8 @@ export async function detectTapeSize(printerName) {
131
179
  */
132
180
  async function detectTapeSizeFromDriver(printerName) {
133
181
  const printer = printerName ?? getDefaultPrinter();
182
+ if (!printer)
183
+ return null; // Nothing to ask; tape stays unknown rather than throwing
134
184
  const script = `
135
185
  $ErrorActionPreference = 'SilentlyContinue'
136
186
  Add-Type -AssemblyName System.Printing | Out-Null
@@ -184,6 +234,8 @@ function withTimeout(p, ms) {
184
234
  */
185
235
  export async function queryTapeStatus(printerName) {
186
236
  const printer = printerName ?? getDefaultPrinter();
237
+ if (!printer)
238
+ return null; // Documented never to throw
187
239
  const usbPid = Object.entries(PT_USB_PIDS)
188
240
  .find(([model]) => printer.toUpperCase().includes(model))?.[1] ?? "";
189
241
  const script = String.raw `
@@ -351,12 +403,10 @@ class BrotherPrinterImpl {
351
403
  return coreListPrinters(DEFAULT_PRINTER_PATTERN);
352
404
  }
353
405
  async getStatus(printerName) {
354
- const printer = printerName ?? getDefaultPrinter();
355
- return getPrinterStatus(printer);
406
+ return getPrinterStatus(requirePrinter(printerName));
356
407
  }
357
408
  async waitOnline(printerName, opts = {}) {
358
- const printer = printerName ?? getDefaultPrinter();
359
- return coreWaitOnline(printer, opts, DEFAULT_PRINTER_PATTERN);
409
+ return coreWaitOnline(requirePrinter(printerName), opts, DEFAULT_PRINTER_PATTERN);
360
410
  }
361
411
  async render(opts) {
362
412
  validateContent(opts);
@@ -365,7 +415,7 @@ class BrotherPrinterImpl {
365
415
  }
366
416
  async print(opts) {
367
417
  validateContent(opts);
368
- const printer = opts.printer ?? getDefaultPrinter();
418
+ const printer = requirePrinter(opts.printer);
369
419
  const tape = await this.resolveTape(opts.media);
370
420
  const image = await resolveContent(opts, TAPE_SIZES[tape].height, tape);
371
421
  await ensureOnline(printer, opts);
@@ -377,7 +427,7 @@ class BrotherPrinterImpl {
377
427
  return coreRenderSegments(segments, TAPE_SIZES[tape].height, opts.textHeight, opts.space);
378
428
  }
379
429
  async printSegments(segments, opts = {}) {
380
- const printer = opts.printer ?? getDefaultPrinter();
430
+ const printer = requirePrinter(opts.printer);
381
431
  const tape = await this.resolveTape(opts.media);
382
432
  const image = await coreRenderSegments(segments, TAPE_SIZES[tape].height, opts.textHeight, opts.space);
383
433
  await ensureOnline(printer, opts);
package/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Brother Label Printer API\n * Programmatic interface for printing labels on Brother P-touch printers.\n *\n * Implements the unified LabelPrinter interface from @bobfrankston/label-core.\n * All printer-agnostic logic (rendering, segments, clipboard, CLI primitives,\n * online-wait) lives in label-core. This file holds the Brother-specific bits:\n * TAPE_SIZES catalog, MEDIA_OPTIONS (CustomMediaSize* names), XPS PrintTicket\n * builder with the Brother namespace, and detectTapeSize.\n */\n\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport {\n validateContent,\n resolveContent,\n renderSegments as coreRenderSegments,\n listPrinters as coreListPrinters,\n getPrinterStatus,\n waitOnline as coreWaitOnline,\n runScriptOrThrow,\n readJsonConfig,\n mergeJsonConfig,\n} from \"@bobfrankston/label-core\";\nimport type {\n LabelPrinter,\n PrintOptions as CorePrintOptions,\n SegmentOptions as CoreSegmentOptions,\n PrintResult as CorePrintResult,\n PrinterStatus,\n PrinterInfo as CorePrinterInfo,\n PrinterConfig as CorePrinterConfig,\n MediaInfo,\n Segment,\n WaitOptions,\n} from \"@bobfrankston/label-core\";\n\n/* ----- Brother-specific types ----- */\n\nexport type TapeSize = 6 | 9 | 12 | 18 | 24;\nexport type Orientation = \"landscape\" | \"portrait\";\n\n/** Backward-compat: brother-label's config kept the `defaultTape` name. */\nexport interface PrinterConfig {\n defaultTape?: TapeSize;\n defaultPrinter?: string;\n}\n\nexport interface PrinterInfo {\n name: string;\n}\n\n/** Brother-specific PrintOptions: same as core but with tape alias for media. */\nexport interface PrintOptions extends Omit<CorePrintOptions, \"media\"> {\n tape?: TapeSize; /** Tape size in mm — alias for core.media */\n orientation?: Orientation; /** Reserved (Brother PT prints landscape only) */\n length?: number; /** Reserved — explicit length in mm */\n}\n\nexport interface SegmentOptions extends Omit<CoreSegmentOptions, \"media\"> {\n tape?: TapeSize;\n}\n\nexport interface PrintResult {\n image: Buffer;\n}\n\nexport type { Segment };\n\n/* ----- Constants ----- */\n\nconst CONFIG_PATH = path.join(os.homedir(), \".brother-label.json\");\nconst DEFAULT_PRINTER = \"Brother PT-P710BT\";\nconst DEFAULT_PRINTER_PATTERN = /brother|^pt-|^ql-/i;\nconst PRINT_DPI = 300;\nconst VALID_TAPES: TapeSize[] = [6, 9, 12, 18, 24];\n\n/** Tape sizes: width in pixels @ 300 DPI = continuous direction; height = perpendicular. */\nconst TAPE_SIZES: Record<TapeSize, { width: number; height: number }> = {\n 6: { width: 1137, height: 56 },\n 9: { width: 1137, height: 84 },\n 12: { width: 1137, height: 113 },\n 18: { width: 1137, height: 169 },\n 24: { width: 1137, height: 213 },\n};\n\n/** Brother CustomMediaSize names + tape widths in microns (XPS PrintTicket). */\nconst MEDIA_OPTIONS: Record<TapeSize, { name: string; width: number }> = {\n 6: { name: \"CustomMediaSize257\", width: 5900 },\n 9: { name: \"CustomMediaSize258\", width: 9000 },\n 12: { name: \"CustomMediaSize259\", width: 11900 },\n 18: { name: \"CustomMediaSize260\", width: 18100 },\n 24: { name: \"CustomMediaSize261\", width: 24000 },\n};\n\n/* ----- Config (backward-compat — note \"defaultTape\" stays in JSON) ----- */\n\nexport function getConfig(): PrinterConfig {\n const raw: any = readJsonConfig(CONFIG_PATH);\n if (typeof raw.defaultTape === \"string\") {\n raw.defaultTape = parseInt(raw.defaultTape.replace(\"mm\", \"\"), 10) as TapeSize;\n }\n return raw;\n}\n\nexport function setConfig(config: Partial<PrinterConfig>): void {\n mergeJsonConfig(CONFIG_PATH, config);\n}\n\nexport function getConfigPath(): string {\n return CONFIG_PATH;\n}\n\n/**\n * The queue used when a caller names no printer: the configured default, else\n * the built-in fallback. Exported so callers can NAME the queue they are about\n * to use instead of saying \"the default\".\n * Claude Code 2026-08-24.\n */\nexport function getDefaultPrinter(): string {\n return getConfig().defaultPrinter ?? DEFAULT_PRINTER;\n}\n\n/* ----- Printer listing (backward-compat shape: { name }[]) ----- */\n\nexport async function listPrinters(): Promise<PrinterInfo[]> {\n const ps = await coreListPrinters(DEFAULT_PRINTER_PATTERN);\n return ps.map(p => ({ name: p.name }));\n}\n\n/** Mark an error as user-actionable so cli.ts prints it inline instead of\n * dumping to a log file. The cli's catch block duck-types on `isUserError`. */\nfunction userError(msg: string): Error {\n const e = new Error(msg);\n (e as any).isUserError = true; // No typed shape for this; cli.ts duck-types the flag\n return e;\n}\n\n/**\n * Resolve a user-supplied printer value to an installed Windows queue name. Accepts:\n * #N 1-based index into the list shown by `brother-label list`\n * <exact> Full queue name (case-sensitive match shortcut)\n * <substr> Case-insensitive substring against name or port (e.g. \"ql820\",\n * \"172.20.1.165\", \"BRW4CD577B59B6A\"). Errors if ambiguous.\n *\n * Claude Code 2026-08-24: moved here from cli.ts so other apps that let the user\n * name a printer (iplabels) resolve names the same way rather than each rolling\n * its own matching.\n */\nexport async function resolvePrinter(value: string): Promise<string> {\n const all = await coreListPrinters(DEFAULT_PRINTER_PATTERN);\n const sorted = [...all].sort((a, b) => a.name.localeCompare(b.name));\n\n if (sorted.length === 0) {\n throw userError(`No Brother printers installed. Run 'brother-label list' to verify.`);\n }\n\n const idx = value.match(/^#(\\d+)$/);\n if (idx) {\n const n = parseInt(idx[1], 10);\n if (n < 1 || n > sorted.length) {\n throw userError(`${value}: only ${sorted.length} printer(s) installed (use 'brother-label list').`);\n }\n return sorted[n - 1].name;\n }\n\n const exact = sorted.find(p => p.name === value);\n if (exact) return exact.name;\n\n const lower = value.toLowerCase();\n const norm = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n const target = norm(value);\n const matches = sorted.filter(p => {\n const name = p.name.toLowerCase();\n const port = (p.portName || \"\").toLowerCase();\n if (name.includes(lower) || port.includes(lower)) return true;\n // Normalized fallback: \"ql820\" matches \"Brother QL-820NWB\"\n return norm(p.name).includes(target) || norm(p.portName || \"\").includes(target);\n });\n if (matches.length === 1) return matches[0].name;\n if (matches.length === 0) {\n throw userError(`No printer matches '${value}'. Run 'brother-label list' to see available printers.`);\n }\n const names = matches.map(p => p.name).join(\", \");\n throw userError(`'${value}' is ambiguous — matches: ${names}`);\n}\n\n/**\n * Auto-detect tape size. Tries the live printer status first, then the\n * Windows driver's default print ticket (see detectTape for details).\n */\nexport async function detectTapeSize(printerName?: string): Promise<TapeSize> {\n const d = await detectTape(printerName);\n return d?.tape ?? null;\n}\n\n/**\n * Read the tape size the Windows driver's default PrintTicket claims.\n * Brother's driver embeds a CustomMediaSize name in the ticket XML — but\n * this is just the driver's saved preference, not what's physically loaded.\n */\nasync function detectTapeSizeFromDriver(printerName?: string): Promise<TapeSize> {\n const printer = printerName ?? getDefaultPrinter();\n const script = `\n$ErrorActionPreference = 'SilentlyContinue'\nAdd-Type -AssemblyName System.Printing | Out-Null\ntry {\n $server = New-Object System.Printing.LocalPrintServer\n $queue = $server.GetPrintQueue('${printer.replace(/'/g, \"''\")}')\n $ticket = $queue.DefaultPrintTicket\n $stream = $ticket.GetXmlStream()\n $reader = New-Object System.IO.StreamReader($stream)\n Write-Output $reader.ReadToEnd()\n $reader.Close()\n} catch {\n Write-Output \"ERROR\"\n}\n`;\n try {\n const out = await runScriptOrThrow(script);\n for (const [size, media] of Object.entries(MEDIA_OPTIONS)) {\n if (out.includes(media.name)) return parseInt(size, 10) as TapeSize;\n }\n } catch { /* fall through */ }\n return null;\n}\n\n/* ----- Live tape status (raw P-touch protocol) ----- */\n\n/**\n * USB product IDs for PT models whose queue sits on a spooler USB port.\n * The spooler is write-only, so the live status request needs the usbprint\n * device interface opened directly (CreateFile on the \\\\?\\USB#... path).\n * Bluetooth models (PT-D610BT) need no entry — their queue's PortName is a\n * COM port, which is bidirectional as-is.\n */\nconst PT_USB_PIDS: Record<string, string> = {\n \"PT-P710BT\": \"20AF\",\n};\n\n/** Parsed ESC i S status reply (32 bytes; byte 10 = cassette width in mm). */\nexport interface TapeStatus {\n widthMm: number; /** 0 = no cassette loaded */\n tape: TapeSize | null; /** widthMm when it maps to a supported size */\n mediaType: number; /** 0x01 laminated, 0x03 non-laminated, 0x11 heat-shrink */\n raw: string; /** all 32 status bytes as hex */\n}\n\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n p,\n new Promise<never>((_, reject) => {\n const t = setTimeout(() => reject(new Error(\"timeout\")), ms);\n t.unref();\n }),\n ]);\n}\n\n/**\n * Query the printer itself for the loaded cassette via the raw P-touch\n * status request (100×0x00 invalidate, ESC @, ESC i S → 32-byte reply).\n * Returns null when the printer is off, busy printing, or on an\n * unsupported port. Never throws.\n */\nexport async function queryTapeStatus(printerName?: string): Promise<TapeStatus | null> {\n const printer = printerName ?? getDefaultPrinter();\n const usbPid = Object.entries(PT_USB_PIDS)\n .find(([model]) => printer.toUpperCase().includes(model))?.[1] ?? \"\";\n const script = String.raw`\n$ErrorActionPreference = 'Stop'\ntry { $port = (Get-Printer -Name '${printer.replace(/'/g, \"''\")}').PortName }\ncatch { Write-Output 'FAIL no such queue'; exit 0 }\n\n$req = New-Object byte[] 105\n$req[100] = 0x1B; $req[101] = 0x40 # ESC @ initialize\n$req[102] = 0x1B; $req[103] = 0x69; $req[104] = 0x53 # ESC i S status request\n\nif ($port -match '^COM\\d+') {\n try {\n $sp = New-Object System.IO.Ports.SerialPort ($port.TrimEnd(':'))\n $sp.ReadTimeout = 3000; $sp.WriteTimeout = 2000\n $sp.Open()\n try {\n $sp.Write($req, 0, $req.Length)\n $buf = New-Object byte[] 32\n $total = 0\n while ($total -lt 32) {\n $n = $sp.Read($buf, $total, 32 - $total)\n if ($n -le 0) { break }\n $total += $n\n }\n if ($total -lt 32) { Write-Output 'FAIL short serial read'; exit 0 }\n Write-Output ('OK ' + (($buf | ForEach-Object { $_.ToString('X2') }) -join ' '))\n } finally { $sp.Close() }\n } catch { Write-Output \"FAIL $($_.Exception.Message)\" }\n exit 0\n}\nif ($port -notmatch '^USB') { Write-Output \"FAIL unsupported port $port\"; exit 0 }\n\n# usbprint device interfaces live under this class GUID; stale (unplugged)\n# entries persist in the registry, so try each match until one opens.\n$classKey = 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\DeviceClasses\\{28d78fad-5a12-11d1-ae5b-0000f803a8c2}'\n$pidFilter = '${usbPid}'\n$paths = @(Get-ChildItem $classKey | ForEach-Object {\n $leaf = Split-Path $_.Name -Leaf\n if ($leaf -match 'VID_04F9' -and ($pidFilter -eq '' -or $leaf -match \"PID_$pidFilter\")) {\n $leaf -replace '^##\\?#', '\\\\?\\'\n }\n})\nif ($paths.Count -eq 0) { Write-Output 'FAIL no usbprint interface'; exit 0 }\n\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Threading.Tasks;\nusing Microsoft.Win32.SafeHandles;\n\npublic static class BrotherRawUsb {\n [DllImport(\"kernel32.dll\", CharSet = CharSet.Unicode, SetLastError = true)]\n static extern SafeFileHandle CreateFile(string fileName, uint access, uint share,\n IntPtr security, uint creation, uint flags, IntPtr template);\n\n public static byte[] QueryStatus(string devPath, byte[] request) {\n SafeFileHandle h = CreateFile(devPath, 0xC0000000u /*GENERIC_RW*/, 0, IntPtr.Zero,\n 3 /*OPEN_EXISTING*/, 0, IntPtr.Zero);\n if (h.IsInvalid) throw new IOException(\"open failed: \" + Marshal.GetLastWin32Error());\n using (FileStream fs = new FileStream(h, FileAccess.ReadWrite)) {\n fs.Write(request, 0, request.Length);\n fs.Flush();\n byte[] buf = new byte[32];\n int total = 0;\n while (total < 32) {\n Task<int> t = fs.ReadAsync(buf, total, 32 - total);\n if (!t.Wait(3000)) throw new IOException(\"status read timeout\");\n if (t.Result <= 0) throw new IOException(\"read returned \" + t.Result);\n total += t.Result;\n }\n return buf;\n }\n }\n}\n'@\n\nforeach ($p in $paths) {\n try {\n $buf = [BrotherRawUsb]::QueryStatus($p, $req)\n Write-Output ('OK ' + (($buf | ForEach-Object { $_.ToString('X2') }) -join ' '))\n exit 0\n } catch { }\n}\nWrite-Output 'FAIL no device answered'\n`;\n try {\n const out = await withTimeout(runScriptOrThrow(script), 10000);\n const m = out.match(/^OK ((?:[0-9A-F]{2} ?){32})/m);\n if (!m) return null;\n const bytes = m[1].trim().split(/\\s+/).map(h => parseInt(h, 16));\n if (bytes[0] !== 0x80) return null; /* print-head mark: sanity check */\n const widthMm = bytes[10];\n const tape = VALID_TAPES.includes(widthMm as TapeSize) ? widthMm as TapeSize : null;\n return { widthMm, tape, mediaType: bytes[11], raw: m[1].trim() };\n } catch {\n return null;\n }\n}\n\nexport interface DetectedTape {\n tape: TapeSize;\n source: \"printer\" | \"driver\";\n}\n\n/**\n * Detect the loaded tape: live printer status first (authoritative — reads\n * the cassette sensor), falling back to the Windows driver's default print\n * ticket, which is only the driver's saved preference and may be stale.\n * A live reply of \"no cassette\" returns null rather than falling back.\n */\nexport async function detectTape(printerName?: string): Promise<DetectedTape | null> {\n const live = await queryTapeStatus(printerName);\n if (live) {\n return live.tape ? { tape: live.tape, source: \"printer\" } : null;\n }\n const t = await detectTapeSizeFromDriver(printerName);\n return t ? { tape: t, source: \"driver\" } : null;\n}\n\n/* ----- Brother LabelPrinter implementation ----- */\n\nclass BrotherPrinterImpl implements LabelPrinter {\n readonly driverName = \"brother\";\n\n getConfig(): CorePrinterConfig {\n const c = getConfig();\n return {\n defaultPrinter: c.defaultPrinter,\n defaultMedia: c.defaultTape !== undefined ? String(c.defaultTape) : undefined,\n };\n }\n setConfig(config: Partial<CorePrinterConfig>): void {\n const update: Partial<PrinterConfig> = {};\n if (config.defaultPrinter !== undefined) update.defaultPrinter = config.defaultPrinter;\n if (config.defaultMedia !== undefined) {\n const t = parseInt(config.defaultMedia, 10) as TapeSize;\n if (VALID_TAPES.includes(t)) update.defaultTape = t;\n }\n setConfig(update);\n }\n getConfigPath(): string {\n return CONFIG_PATH;\n }\n\n listMedia(): MediaInfo[] {\n return VALID_TAPES.map(t => ({\n id: String(t),\n name: `${t}mm tape`,\n widthPx: TAPE_SIZES[t].height, /** \"media width\" (perpendicular to feed) */\n lengthPx: 0, /** continuous tape — length determined by content */\n continuous: true,\n }));\n }\n getMedia(id: string): MediaInfo {\n const t = parseInt(id.replace(\"mm\", \"\"), 10) as TapeSize;\n if (!VALID_TAPES.includes(t)) return null;\n return {\n id: String(t), name: `${t}mm tape`,\n widthPx: TAPE_SIZES[t].height, lengthPx: 0, continuous: true,\n };\n }\n async detectMedia(printerName?: string): Promise<MediaInfo> {\n const t = await detectTapeSize(printerName);\n return t ? this.getMedia(String(t)) : null;\n }\n\n async listPrinters(): Promise<CorePrinterInfo[]> {\n return coreListPrinters(DEFAULT_PRINTER_PATTERN);\n }\n async getStatus(printerName?: string): Promise<PrinterStatus> {\n const printer = printerName ?? getDefaultPrinter();\n return getPrinterStatus(printer);\n }\n async waitOnline(printerName?: string, opts: WaitOptions = {}): Promise<PrinterStatus> {\n const printer = printerName ?? getDefaultPrinter();\n return coreWaitOnline(printer, opts, DEFAULT_PRINTER_PATTERN);\n }\n\n async render(opts: CorePrintOptions): Promise<Buffer> {\n validateContent(opts);\n const tape = await this.resolveTape(opts.media);\n return resolveContent(opts, TAPE_SIZES[tape].height, tape);\n }\n\n async print(opts: CorePrintOptions): Promise<CorePrintResult> {\n validateContent(opts);\n const printer = opts.printer ?? getDefaultPrinter();\n const tape = await this.resolveTape(opts.media);\n const image = await resolveContent(opts, TAPE_SIZES[tape].height, tape);\n await ensureOnline(printer, opts);\n await printBuffer(image, printer, tape);\n return { image, media: this.getMedia(String(tape)), printer };\n }\n\n async renderSegments(segments: Segment[], opts: CoreSegmentOptions = {}): Promise<Buffer> {\n const tape = await this.resolveTape(opts.media);\n return coreRenderSegments(segments, TAPE_SIZES[tape].height, opts.textHeight, opts.space);\n }\n async printSegments(segments: Segment[], opts: CoreSegmentOptions = {}): Promise<CorePrintResult> {\n const printer = opts.printer ?? getDefaultPrinter();\n const tape = await this.resolveTape(opts.media);\n const image = await coreRenderSegments(segments, TAPE_SIZES[tape].height, opts.textHeight, opts.space);\n await ensureOnline(printer, opts);\n await printBuffer(image, printer, tape);\n return { image, media: this.getMedia(String(tape)), printer };\n }\n\n private async resolveTape(media?: string): Promise<TapeSize> {\n if (media !== undefined) {\n const t = parseInt(media.replace(\"mm\", \"\"), 10) as TapeSize;\n if (!VALID_TAPES.includes(t)) throw new Error(`Invalid tape size: ${media}. Valid: ${VALID_TAPES.join(\", \")}`);\n return t;\n }\n const cfg = getConfig();\n if (cfg.defaultTape) return cfg.defaultTape;\n const detected = await detectTapeSize();\n return detected ?? 24;\n }\n}\n\n/** Public Brother singleton (implements LabelPrinter). */\nexport const brotherPrinter: LabelPrinter = new BrotherPrinterImpl();\n\n/* ----- Backward-compatible function exports ----- */\n\n/**\n * Translate brother-label PrintOptions (with tape) to core (with media).\n */\nfunction toCore(opts: PrintOptions): CorePrintOptions {\n const out: CorePrintOptions = { ...opts };\n if (opts.tape !== undefined && out.media === undefined) {\n out.media = String(opts.tape);\n }\n delete (out as any).tape;\n return out;\n}\nfunction toCoreSeg(opts: SegmentOptions = {}): CoreSegmentOptions {\n const out: CoreSegmentOptions = { ...opts };\n if (opts.tape !== undefined && out.media === undefined) out.media = String(opts.tape);\n delete (out as any).tape;\n return out;\n}\n\nexport async function render(options: PrintOptions): Promise<Buffer> {\n return brotherPrinter.render(toCore(options));\n}\n\nexport async function print(options: PrintOptions): Promise<PrintResult> {\n const r = await brotherPrinter.print(toCore(options));\n return { image: r.image };\n}\n\nexport async function renderSegments(segments: Segment[], tape?: TapeSize, textHeight?: string, space?: string): Promise<Buffer> {\n return brotherPrinter.renderSegments(segments, {\n media: tape !== undefined ? String(tape) : undefined,\n textHeight, space,\n });\n}\n\nexport async function printSegments(segments: Segment[], options?: SegmentOptions): Promise<PrintResult> {\n const r = await brotherPrinter.printSegments(segments, toCoreSeg(options));\n return { image: r.image };\n}\n\n/* ----- Brother XPS print path (kept here, Brother-specific) ----- */\n\nasync function ensureOnline(printer: string, opts: { wait?: boolean; waitTimeoutMs?: number; waitIntervalMs?: number; onWaiting?: CorePrintOptions[\"onWaiting\"]; log?: CorePrintOptions[\"log\"] }): Promise<void> {\n const status = await getPrinterStatus(printer);\n const queueNote = status.queueWarning ? \" \" + status.queueWarning : \"\";\n if (status.online) {\n /* A backed-up queue matters even when the printer is reachable: the\n * label about to be submitted lands behind whatever is already wedged,\n * so nothing comes out of the printer. The offline paths below carry\n * the same note in their own message, so only log it here. */\n if (status.queueWarning && opts.log) opts.log(`[brother-label] ${status.queueWarning}`);\n return;\n }\n if (opts.wait === false) {\n throw new Error(`Printer \"${printer}\" is offline (${status.statusText}${status.error ? \", \" + status.error : \"\"}).${queueNote} Use wait:true to wait, or pick another printer.`);\n }\n if (opts.log) opts.log(`[brother-label] ${printer} offline (${status.statusText}); waiting...${queueNote}`);\n await coreWaitOnline(printer, {\n timeoutMs: opts.waitTimeoutMs,\n intervalMs: opts.waitIntervalMs,\n onWaiting: opts.onWaiting,\n log: opts.log,\n }, DEFAULT_PRINTER_PATTERN);\n}\n\n/**\n * Print a single image buffer using the Brother XPS PrintTicket path.\n * Builds an XPS document with a custom CustomMediaSize for the tape, then\n * sends it to the print queue.\n */\nasync function printBuffer(imageBuffer: Buffer, printer: string, tape: TapeSize): Promise<void> {\n const media = MEDIA_OPTIONS[tape];\n const tempPath = path.join(os.tmpdir(), `label-${Date.now()}.png`);\n fs.writeFileSync(tempPath, imageBuffer);\n const psPath = tempPath.replace(/\\\\/g, \"\\\\\\\\\");\n\n const script = `\n$ErrorActionPreference = 'Stop'\nAdd-Type -AssemblyName System.Drawing\nAdd-Type -AssemblyName System.Printing\nAdd-Type -AssemblyName ReachFramework\nAdd-Type -AssemblyName PresentationCore\n\n$img = [System.Drawing.Image]::FromFile('${psPath}')\n\n$DPI = ${PRINT_DPI}\n$MICRONS_PER_INCH = 25400\n\n$labelLengthMicrons = [int]($img.Width / $DPI * $MICRONS_PER_INCH) + 3000\n$tapeWidthMicrons = ${media.width}\n\n$imgWidthWpf = $img.Width / $DPI * 96\n$imgHeightWpf = $img.Height / $DPI * 96\n\n$ticketXml = @\"\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<psf:PrintTicket xmlns:psf=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"1\"\n xmlns:psk=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords\"\n xmlns:ns0001=\"http://schemas.brother.info/mfc/printing/2006/11/printschemakeywords\">\n <psf:Feature name=\"psk:PageMediaSize\">\n <psf:Option name=\"ns0001:${media.name}\">\n <psf:ScoredProperty name=\"psk:MediaSizeWidth\">\n <psf:Value xsi:type=\"xsd:integer\">${media.width}</psf:Value>\n </psf:ScoredProperty>\n <psf:ScoredProperty name=\"psk:MediaSizeHeight\">\n <psf:ParameterRef name=\"psk:PageMediaSizeMediaSizeHeight\" />\n </psf:ScoredProperty>\n </psf:Option>\n </psf:Feature>\n <psf:ParameterInit name=\"psk:PageMediaSizeMediaSizeHeight\">\n <psf:Value xsi:type=\"xsd:integer\">$labelLengthMicrons</psf:Value>\n </psf:ParameterInit>\n <psf:Feature name=\"psk:PageOrientation\">\n <psf:Option name=\"psk:Landscape\" />\n </psf:Feature>\n <psf:Feature name=\"ns0001:PageRollFeedToEndOfSheet\">\n <psf:Option name=\"ns0001:FeedToImageEdge\" />\n </psf:Feature>\n <psf:Feature name=\"psk:PageMediaType\">\n <psf:Option name=\"psk:Label\" />\n </psf:Feature>\n <psf:Feature name=\"ns0001:JobRollCutAtEndOfJob\">\n <psf:Option name=\"ns0001:Cut\" />\n </psf:Feature>\n</psf:PrintTicket>\n\"@\n\n$xmlBytes = [System.Text.Encoding]::UTF8.GetBytes($ticketXml)\n$memStream = New-Object System.IO.MemoryStream(,$xmlBytes)\n$ticket = New-Object System.Printing.PrintTicket($memStream)\n\n$server = New-Object System.Printing.LocalPrintServer\n$queue = $server.GetPrintQueue('${printer.replace(/'/g, \"''\")}')\n\n$xpsPath = [System.IO.Path]::GetTempFileName() + \".xps\"\n\n$pageWidth = $labelLengthMicrons / $MICRONS_PER_INCH * 96\n$pageHeight = $tapeWidthMicrons / $MICRONS_PER_INCH * 96\n\n$package = [System.IO.Packaging.Package]::Open($xpsPath, [System.IO.FileMode]::Create)\n$xpsDoc = New-Object System.Windows.Xps.Packaging.XpsDocument($package)\n$writer = [System.Windows.Xps.Packaging.XpsDocument]::CreateXpsDocumentWriter($xpsDoc)\n\n$visual = New-Object System.Windows.Media.DrawingVisual\n$dc = $visual.RenderOpen()\n\n$bitmapImg = New-Object System.Windows.Media.Imaging.BitmapImage\n$bitmapImg.BeginInit()\n$bitmapImg.UriSource = New-Object System.Uri('${psPath}')\n$bitmapImg.EndInit()\n\n$yOffset = ($pageHeight - $imgHeightWpf) / 2\n$xOffset = 2 / 25.4 * 96\n$rect = New-Object System.Windows.Rect($xOffset, $yOffset, $imgWidthWpf, $imgHeightWpf)\n$dc.DrawImage($bitmapImg, $rect)\n$dc.Close()\n\n$writer.Write($visual, $ticket)\n\n$xpsDoc.Close()\n$package.Close()\n$img.Dispose()\n\n$xpsDocForPrint = New-Object System.Windows.Xps.Packaging.XpsDocument($xpsPath, [System.IO.FileAccess]::Read)\n$seq = $xpsDocForPrint.GetFixedDocumentSequence()\n\n$xpsWriter = [System.Printing.PrintQueue]::CreateXpsDocumentWriter($queue)\n$xpsWriter.Write($seq, $ticket)\n\n$xpsDocForPrint.Close()\nRemove-Item $xpsPath -ErrorAction SilentlyContinue\n`;\n try {\n await runScriptOrThrow(script);\n } finally {\n if (fs.existsSync(tempPath)) fs.unlinkSync(tempPath);\n }\n}\n"]}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Brother Label Printer API\n * Programmatic interface for printing labels on Brother P-touch printers.\n *\n * Implements the unified LabelPrinter interface from @bobfrankston/label-core.\n * All printer-agnostic logic (rendering, segments, clipboard, CLI primitives,\n * online-wait) lives in label-core. This file holds the Brother-specific bits:\n * TAPE_SIZES catalog, MEDIA_OPTIONS (CustomMediaSize* names), XPS PrintTicket\n * builder with the Brother namespace, and detectTapeSize.\n */\n\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport {\n validateContent,\n resolveContent,\n renderSegments as coreRenderSegments,\n listPrinters as coreListPrinters,\n getPrinterStatus,\n waitOnline as coreWaitOnline,\n runScriptOrThrow,\n} from \"@bobfrankston/label-core\";\nimport { configDir, readJson5, writeJson5 } from \"@bobfrankston/userconfig\";\nimport type {\n LabelPrinter,\n PrintOptions as CorePrintOptions,\n SegmentOptions as CoreSegmentOptions,\n PrintResult as CorePrintResult,\n PrinterStatus,\n PrinterInfo as CorePrinterInfo,\n PrinterConfig as CorePrinterConfig,\n MediaInfo,\n Segment,\n WaitOptions,\n} from \"@bobfrankston/label-core\";\n\n/* ----- Brother-specific types ----- */\n\nexport type TapeSize = 6 | 9 | 12 | 18 | 24;\nexport type Orientation = \"landscape\" | \"portrait\";\n\n/** Backward-compat: brother-label's config kept the `defaultTape` name. */\nexport interface PrinterConfig {\n defaultTape?: TapeSize;\n defaultPrinter?: string;\n}\n\nexport interface PrinterInfo {\n name: string;\n}\n\n/** Brother-specific PrintOptions: same as core but with tape alias for media. */\nexport interface PrintOptions extends Omit<CorePrintOptions, \"media\"> {\n tape?: TapeSize; /** Tape size in mm — alias for core.media */\n orientation?: Orientation; /** Reserved (Brother PT prints landscape only) */\n length?: number; /** Reserved — explicit length in mm */\n}\n\nexport interface SegmentOptions extends Omit<CoreSegmentOptions, \"media\"> {\n tape?: TapeSize;\n}\n\nexport interface PrintResult {\n image: Buffer;\n}\n\nexport type { Segment };\n\n/* ----- Constants ----- */\n\n/**\n * The label config lives in the SHARED user-config directory, not beside this\n * package, so every label utility (brother-print, iplabels, ...) reads one\n * default instead of each keeping its own idea of \"the printer\".\n *\n * Claude Code 2026-09-01, at Bob's direction. The path comes from\n * @bobfrankston/userconfig's `configDir` — never build it from homedir here;\n * where that directory lives is UserConfig's business, not ours.\n */\nconst CONFIG_PATH = path.join(configDir, \"labels.json5\");\n\n/** Pre-2026-09-01 location. Read once to migrate, never written again. */\nconst LEGACY_CONFIG_PATH = path.join(os.homedir(), \".brother-label.json\");\nconst DEFAULT_PRINTER_PATTERN = /brother|^pt-|^ql-/i;\nconst PRINT_DPI = 300;\nconst VALID_TAPES: TapeSize[] = [6, 9, 12, 18, 24];\n\n/** Tape sizes: width in pixels @ 300 DPI = continuous direction; height = perpendicular. */\nconst TAPE_SIZES: Record<TapeSize, { width: number; height: number }> = {\n 6: { width: 1137, height: 56 },\n 9: { width: 1137, height: 84 },\n 12: { width: 1137, height: 113 },\n 18: { width: 1137, height: 169 },\n 24: { width: 1137, height: 213 },\n};\n\n/** Brother CustomMediaSize names + tape widths in microns (XPS PrintTicket). */\nconst MEDIA_OPTIONS: Record<TapeSize, { name: string; width: number }> = {\n 6: { name: \"CustomMediaSize257\", width: 5900 },\n 9: { name: \"CustomMediaSize258\", width: 9000 },\n 12: { name: \"CustomMediaSize259\", width: 11900 },\n 18: { name: \"CustomMediaSize260\", width: 18100 },\n 24: { name: \"CustomMediaSize261\", width: 24000 },\n};\n\n/* ----- Config (backward-compat — note \"defaultTape\" stays in JSON) ----- */\n\nexport function getConfig(): PrinterConfig {\n const raw: any = fs.existsSync(CONFIG_PATH) ? readJson5(CONFIG_PATH) : migrateLegacyConfig();\n if (typeof raw.defaultTape === \"string\") {\n raw.defaultTape = parseInt(raw.defaultTape.replace(\"mm\", \"\"), 10) as TapeSize;\n }\n return raw;\n}\n\n/**\n * Copy a pre-move ~/.brother-label.json into the new location the first time we\n * look and find nothing there, so a default set before 2026-09-01 survives.\n * Returns the settings either way; after the copy this never runs again.\n */\nfunction migrateLegacyConfig(): any {\n if (!fs.existsSync(LEGACY_CONFIG_PATH)) return {};\n let old: any;\n try {\n old = JSON.parse(fs.readFileSync(LEGACY_CONFIG_PATH, \"utf-8\"));\n } catch {\n return {}; // Unreadable legacy file is not worth failing an install over\n }\n writeJson5(CONFIG_PATH, old);\n return old;\n}\n\nexport function setConfig(config: Partial<PrinterConfig>): void {\n writeJson5(CONFIG_PATH, { ...getConfig(), ...config });\n}\n\nexport function getConfigPath(): string {\n return CONFIG_PATH;\n}\n\n/**\n * The configured default queue, or null when none is set. Exported so callers\n * can NAME the queue they are about to use instead of saying \"the default\".\n * Claude Code 2026-08-24.\n *\n * Claude Code 2026-09-01: this used to fall back to a wired-in\n * \"Brother PT-P710BT\". That is exactly the bug Bob hit -- a machine with no\n * configuration silently printed to a model name baked into the source, and\n * nothing in the output said the choice had been invented rather than chosen.\n * There is no fallback now; callers that need a printer use requirePrinter().\n */\nexport function getDefaultPrinter(): string {\n return getConfig().defaultPrinter ?? null;\n}\n\n/**\n * The queue to use when the caller named none -- or a user error saying how to\n * set one. Every path that is about to move bytes goes through here, so \"no\n * printer\" is reported once, in one voice, instead of each call site guessing.\n */\nfunction requirePrinter(printerName?: string): string {\n const printer = printerName ?? getDefaultPrinter();\n if (!printer) {\n throw userError(\n `No printer named and no default set. Set one with ` +\n `'brother-print -default <name>', or name a printer with -p. ` +\n `'brother-print -list' shows what is installed.`\n );\n }\n return printer;\n}\n\n/* ----- Printer listing (backward-compat shape: { name }[]) ----- */\n\nexport async function listPrinters(): Promise<PrinterInfo[]> {\n const ps = await coreListPrinters(DEFAULT_PRINTER_PATTERN);\n return ps.map(p => ({ name: p.name }));\n}\n\n/** Mark an error as user-actionable so cli.ts prints it inline instead of\n * dumping to a log file. The cli's catch block duck-types on `isUserError`. */\nfunction userError(msg: string): Error {\n const e = new Error(msg);\n (e as any).isUserError = true; // No typed shape for this; cli.ts duck-types the flag\n return e;\n}\n\n/**\n * Resolve a user-supplied printer value to an installed Windows queue name. Accepts:\n * #N 1-based index into the list shown by `brother-label list`\n * <exact> Full queue name (case-sensitive match shortcut)\n * <substr> Case-insensitive substring against name or port (e.g. \"ql820\",\n * \"172.20.1.165\", \"BRW4CD577B59B6A\"). Errors if ambiguous.\n *\n * Claude Code 2026-08-24: moved here from cli.ts so other apps that let the user\n * name a printer (iplabels) resolve names the same way rather than each rolling\n * its own matching.\n */\nexport async function resolvePrinter(value: string): Promise<string> {\n const all = await coreListPrinters(DEFAULT_PRINTER_PATTERN);\n const sorted = [...all].sort((a, b) => a.name.localeCompare(b.name));\n\n if (sorted.length === 0) {\n throw userError(`No Brother printers installed. Run 'brother-label list' to verify.`);\n }\n\n const idx = value.match(/^#(\\d+)$/);\n if (idx) {\n const n = parseInt(idx[1], 10);\n if (n < 1 || n > sorted.length) {\n throw userError(`${value}: only ${sorted.length} printer(s) installed (use 'brother-label list').`);\n }\n return sorted[n - 1].name;\n }\n\n const exact = sorted.find(p => p.name === value);\n if (exact) return exact.name;\n\n const lower = value.toLowerCase();\n const norm = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n const target = norm(value);\n const matches = sorted.filter(p => {\n const name = p.name.toLowerCase();\n const port = (p.portName || \"\").toLowerCase();\n if (name.includes(lower) || port.includes(lower)) return true;\n // Normalized fallback: \"ql820\" matches \"Brother QL-820NWB\"\n return norm(p.name).includes(target) || norm(p.portName || \"\").includes(target);\n });\n if (matches.length === 1) return matches[0].name;\n if (matches.length === 0) {\n throw userError(`No printer matches '${value}'. Run 'brother-label list' to see available printers.`);\n }\n const names = matches.map(p => p.name).join(\", \");\n throw userError(`'${value}' is ambiguous — matches: ${names}`);\n}\n\n/**\n * Auto-detect tape size. Tries the live printer status first, then the\n * Windows driver's default print ticket (see detectTape for details).\n */\nexport async function detectTapeSize(printerName?: string): Promise<TapeSize> {\n const d = await detectTape(printerName);\n return d?.tape ?? null;\n}\n\n/**\n * Read the tape size the Windows driver's default PrintTicket claims.\n * Brother's driver embeds a CustomMediaSize name in the ticket XML — but\n * this is just the driver's saved preference, not what's physically loaded.\n */\nasync function detectTapeSizeFromDriver(printerName?: string): Promise<TapeSize> {\n const printer = printerName ?? getDefaultPrinter();\n if (!printer) return null; // Nothing to ask; tape stays unknown rather than throwing\n const script = `\n$ErrorActionPreference = 'SilentlyContinue'\nAdd-Type -AssemblyName System.Printing | Out-Null\ntry {\n $server = New-Object System.Printing.LocalPrintServer\n $queue = $server.GetPrintQueue('${printer.replace(/'/g, \"''\")}')\n $ticket = $queue.DefaultPrintTicket\n $stream = $ticket.GetXmlStream()\n $reader = New-Object System.IO.StreamReader($stream)\n Write-Output $reader.ReadToEnd()\n $reader.Close()\n} catch {\n Write-Output \"ERROR\"\n}\n`;\n try {\n const out = await runScriptOrThrow(script);\n for (const [size, media] of Object.entries(MEDIA_OPTIONS)) {\n if (out.includes(media.name)) return parseInt(size, 10) as TapeSize;\n }\n } catch { /* fall through */ }\n return null;\n}\n\n/* ----- Live tape status (raw P-touch protocol) ----- */\n\n/**\n * USB product IDs for PT models whose queue sits on a spooler USB port.\n * The spooler is write-only, so the live status request needs the usbprint\n * device interface opened directly (CreateFile on the \\\\?\\USB#... path).\n * Bluetooth models (PT-D610BT) need no entry — their queue's PortName is a\n * COM port, which is bidirectional as-is.\n */\nconst PT_USB_PIDS: Record<string, string> = {\n \"PT-P710BT\": \"20AF\",\n};\n\n/** Parsed ESC i S status reply (32 bytes; byte 10 = cassette width in mm). */\nexport interface TapeStatus {\n widthMm: number; /** 0 = no cassette loaded */\n tape: TapeSize | null; /** widthMm when it maps to a supported size */\n mediaType: number; /** 0x01 laminated, 0x03 non-laminated, 0x11 heat-shrink */\n raw: string; /** all 32 status bytes as hex */\n}\n\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n p,\n new Promise<never>((_, reject) => {\n const t = setTimeout(() => reject(new Error(\"timeout\")), ms);\n t.unref();\n }),\n ]);\n}\n\n/**\n * Query the printer itself for the loaded cassette via the raw P-touch\n * status request (100×0x00 invalidate, ESC @, ESC i S → 32-byte reply).\n * Returns null when the printer is off, busy printing, or on an\n * unsupported port. Never throws.\n */\nexport async function queryTapeStatus(printerName?: string): Promise<TapeStatus | null> {\n const printer = printerName ?? getDefaultPrinter();\n if (!printer) return null; // Documented never to throw\n const usbPid = Object.entries(PT_USB_PIDS)\n .find(([model]) => printer.toUpperCase().includes(model))?.[1] ?? \"\";\n const script = String.raw`\n$ErrorActionPreference = 'Stop'\ntry { $port = (Get-Printer -Name '${printer.replace(/'/g, \"''\")}').PortName }\ncatch { Write-Output 'FAIL no such queue'; exit 0 }\n\n$req = New-Object byte[] 105\n$req[100] = 0x1B; $req[101] = 0x40 # ESC @ initialize\n$req[102] = 0x1B; $req[103] = 0x69; $req[104] = 0x53 # ESC i S status request\n\nif ($port -match '^COM\\d+') {\n try {\n $sp = New-Object System.IO.Ports.SerialPort ($port.TrimEnd(':'))\n $sp.ReadTimeout = 3000; $sp.WriteTimeout = 2000\n $sp.Open()\n try {\n $sp.Write($req, 0, $req.Length)\n $buf = New-Object byte[] 32\n $total = 0\n while ($total -lt 32) {\n $n = $sp.Read($buf, $total, 32 - $total)\n if ($n -le 0) { break }\n $total += $n\n }\n if ($total -lt 32) { Write-Output 'FAIL short serial read'; exit 0 }\n Write-Output ('OK ' + (($buf | ForEach-Object { $_.ToString('X2') }) -join ' '))\n } finally { $sp.Close() }\n } catch { Write-Output \"FAIL $($_.Exception.Message)\" }\n exit 0\n}\nif ($port -notmatch '^USB') { Write-Output \"FAIL unsupported port $port\"; exit 0 }\n\n# usbprint device interfaces live under this class GUID; stale (unplugged)\n# entries persist in the registry, so try each match until one opens.\n$classKey = 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\DeviceClasses\\{28d78fad-5a12-11d1-ae5b-0000f803a8c2}'\n$pidFilter = '${usbPid}'\n$paths = @(Get-ChildItem $classKey | ForEach-Object {\n $leaf = Split-Path $_.Name -Leaf\n if ($leaf -match 'VID_04F9' -and ($pidFilter -eq '' -or $leaf -match \"PID_$pidFilter\")) {\n $leaf -replace '^##\\?#', '\\\\?\\'\n }\n})\nif ($paths.Count -eq 0) { Write-Output 'FAIL no usbprint interface'; exit 0 }\n\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Threading.Tasks;\nusing Microsoft.Win32.SafeHandles;\n\npublic static class BrotherRawUsb {\n [DllImport(\"kernel32.dll\", CharSet = CharSet.Unicode, SetLastError = true)]\n static extern SafeFileHandle CreateFile(string fileName, uint access, uint share,\n IntPtr security, uint creation, uint flags, IntPtr template);\n\n public static byte[] QueryStatus(string devPath, byte[] request) {\n SafeFileHandle h = CreateFile(devPath, 0xC0000000u /*GENERIC_RW*/, 0, IntPtr.Zero,\n 3 /*OPEN_EXISTING*/, 0, IntPtr.Zero);\n if (h.IsInvalid) throw new IOException(\"open failed: \" + Marshal.GetLastWin32Error());\n using (FileStream fs = new FileStream(h, FileAccess.ReadWrite)) {\n fs.Write(request, 0, request.Length);\n fs.Flush();\n byte[] buf = new byte[32];\n int total = 0;\n while (total < 32) {\n Task<int> t = fs.ReadAsync(buf, total, 32 - total);\n if (!t.Wait(3000)) throw new IOException(\"status read timeout\");\n if (t.Result <= 0) throw new IOException(\"read returned \" + t.Result);\n total += t.Result;\n }\n return buf;\n }\n }\n}\n'@\n\nforeach ($p in $paths) {\n try {\n $buf = [BrotherRawUsb]::QueryStatus($p, $req)\n Write-Output ('OK ' + (($buf | ForEach-Object { $_.ToString('X2') }) -join ' '))\n exit 0\n } catch { }\n}\nWrite-Output 'FAIL no device answered'\n`;\n try {\n const out = await withTimeout(runScriptOrThrow(script), 10000);\n const m = out.match(/^OK ((?:[0-9A-F]{2} ?){32})/m);\n if (!m) return null;\n const bytes = m[1].trim().split(/\\s+/).map(h => parseInt(h, 16));\n if (bytes[0] !== 0x80) return null; /* print-head mark: sanity check */\n const widthMm = bytes[10];\n const tape = VALID_TAPES.includes(widthMm as TapeSize) ? widthMm as TapeSize : null;\n return { widthMm, tape, mediaType: bytes[11], raw: m[1].trim() };\n } catch {\n return null;\n }\n}\n\nexport interface DetectedTape {\n tape: TapeSize;\n source: \"printer\" | \"driver\";\n}\n\n/**\n * Detect the loaded tape: live printer status first (authoritative — reads\n * the cassette sensor), falling back to the Windows driver's default print\n * ticket, which is only the driver's saved preference and may be stale.\n * A live reply of \"no cassette\" returns null rather than falling back.\n */\nexport async function detectTape(printerName?: string): Promise<DetectedTape | null> {\n const live = await queryTapeStatus(printerName);\n if (live) {\n return live.tape ? { tape: live.tape, source: \"printer\" } : null;\n }\n const t = await detectTapeSizeFromDriver(printerName);\n return t ? { tape: t, source: \"driver\" } : null;\n}\n\n/* ----- Brother LabelPrinter implementation ----- */\n\nclass BrotherPrinterImpl implements LabelPrinter {\n readonly driverName = \"brother\";\n\n getConfig(): CorePrinterConfig {\n const c = getConfig();\n return {\n defaultPrinter: c.defaultPrinter,\n defaultMedia: c.defaultTape !== undefined ? String(c.defaultTape) : undefined,\n };\n }\n setConfig(config: Partial<CorePrinterConfig>): void {\n const update: Partial<PrinterConfig> = {};\n if (config.defaultPrinter !== undefined) update.defaultPrinter = config.defaultPrinter;\n if (config.defaultMedia !== undefined) {\n const t = parseInt(config.defaultMedia, 10) as TapeSize;\n if (VALID_TAPES.includes(t)) update.defaultTape = t;\n }\n setConfig(update);\n }\n getConfigPath(): string {\n return CONFIG_PATH;\n }\n\n listMedia(): MediaInfo[] {\n return VALID_TAPES.map(t => ({\n id: String(t),\n name: `${t}mm tape`,\n widthPx: TAPE_SIZES[t].height, /** \"media width\" (perpendicular to feed) */\n lengthPx: 0, /** continuous tape — length determined by content */\n continuous: true,\n }));\n }\n getMedia(id: string): MediaInfo {\n const t = parseInt(id.replace(\"mm\", \"\"), 10) as TapeSize;\n if (!VALID_TAPES.includes(t)) return null;\n return {\n id: String(t), name: `${t}mm tape`,\n widthPx: TAPE_SIZES[t].height, lengthPx: 0, continuous: true,\n };\n }\n async detectMedia(printerName?: string): Promise<MediaInfo> {\n const t = await detectTapeSize(printerName);\n return t ? this.getMedia(String(t)) : null;\n }\n\n async listPrinters(): Promise<CorePrinterInfo[]> {\n return coreListPrinters(DEFAULT_PRINTER_PATTERN);\n }\n async getStatus(printerName?: string): Promise<PrinterStatus> {\n return getPrinterStatus(requirePrinter(printerName));\n }\n async waitOnline(printerName?: string, opts: WaitOptions = {}): Promise<PrinterStatus> {\n return coreWaitOnline(requirePrinter(printerName), opts, DEFAULT_PRINTER_PATTERN);\n }\n\n async render(opts: CorePrintOptions): Promise<Buffer> {\n validateContent(opts);\n const tape = await this.resolveTape(opts.media);\n return resolveContent(opts, TAPE_SIZES[tape].height, tape);\n }\n\n async print(opts: CorePrintOptions): Promise<CorePrintResult> {\n validateContent(opts);\n const printer = requirePrinter(opts.printer);\n const tape = await this.resolveTape(opts.media);\n const image = await resolveContent(opts, TAPE_SIZES[tape].height, tape);\n await ensureOnline(printer, opts);\n await printBuffer(image, printer, tape);\n return { image, media: this.getMedia(String(tape)), printer };\n }\n\n async renderSegments(segments: Segment[], opts: CoreSegmentOptions = {}): Promise<Buffer> {\n const tape = await this.resolveTape(opts.media);\n return coreRenderSegments(segments, TAPE_SIZES[tape].height, opts.textHeight, opts.space);\n }\n async printSegments(segments: Segment[], opts: CoreSegmentOptions = {}): Promise<CorePrintResult> {\n const printer = requirePrinter(opts.printer);\n const tape = await this.resolveTape(opts.media);\n const image = await coreRenderSegments(segments, TAPE_SIZES[tape].height, opts.textHeight, opts.space);\n await ensureOnline(printer, opts);\n await printBuffer(image, printer, tape);\n return { image, media: this.getMedia(String(tape)), printer };\n }\n\n private async resolveTape(media?: string): Promise<TapeSize> {\n if (media !== undefined) {\n const t = parseInt(media.replace(\"mm\", \"\"), 10) as TapeSize;\n if (!VALID_TAPES.includes(t)) throw new Error(`Invalid tape size: ${media}. Valid: ${VALID_TAPES.join(\", \")}`);\n return t;\n }\n const cfg = getConfig();\n if (cfg.defaultTape) return cfg.defaultTape;\n const detected = await detectTapeSize();\n return detected ?? 24;\n }\n}\n\n/** Public Brother singleton (implements LabelPrinter). */\nexport const brotherPrinter: LabelPrinter = new BrotherPrinterImpl();\n\n/* ----- Backward-compatible function exports ----- */\n\n/**\n * Translate brother-label PrintOptions (with tape) to core (with media).\n */\nfunction toCore(opts: PrintOptions): CorePrintOptions {\n const out: CorePrintOptions = { ...opts };\n if (opts.tape !== undefined && out.media === undefined) {\n out.media = String(opts.tape);\n }\n delete (out as any).tape;\n return out;\n}\nfunction toCoreSeg(opts: SegmentOptions = {}): CoreSegmentOptions {\n const out: CoreSegmentOptions = { ...opts };\n if (opts.tape !== undefined && out.media === undefined) out.media = String(opts.tape);\n delete (out as any).tape;\n return out;\n}\n\nexport async function render(options: PrintOptions): Promise<Buffer> {\n return brotherPrinter.render(toCore(options));\n}\n\nexport async function print(options: PrintOptions): Promise<PrintResult> {\n const r = await brotherPrinter.print(toCore(options));\n return { image: r.image };\n}\n\nexport async function renderSegments(segments: Segment[], tape?: TapeSize, textHeight?: string, space?: string): Promise<Buffer> {\n return brotherPrinter.renderSegments(segments, {\n media: tape !== undefined ? String(tape) : undefined,\n textHeight, space,\n });\n}\n\nexport async function printSegments(segments: Segment[], options?: SegmentOptions): Promise<PrintResult> {\n const r = await brotherPrinter.printSegments(segments, toCoreSeg(options));\n return { image: r.image };\n}\n\n/* ----- Brother XPS print path (kept here, Brother-specific) ----- */\n\nasync function ensureOnline(printer: string, opts: { wait?: boolean; waitTimeoutMs?: number; waitIntervalMs?: number; onWaiting?: CorePrintOptions[\"onWaiting\"]; log?: CorePrintOptions[\"log\"] }): Promise<void> {\n const status = await getPrinterStatus(printer);\n const queueNote = status.queueWarning ? \" \" + status.queueWarning : \"\";\n if (status.online) {\n /* A backed-up queue matters even when the printer is reachable: the\n * label about to be submitted lands behind whatever is already wedged,\n * so nothing comes out of the printer. The offline paths below carry\n * the same note in their own message, so only log it here. */\n if (status.queueWarning && opts.log) opts.log(`[brother-label] ${status.queueWarning}`);\n return;\n }\n if (opts.wait === false) {\n throw new Error(`Printer \"${printer}\" is offline (${status.statusText}${status.error ? \", \" + status.error : \"\"}).${queueNote} Use wait:true to wait, or pick another printer.`);\n }\n if (opts.log) opts.log(`[brother-label] ${printer} offline (${status.statusText}); waiting...${queueNote}`);\n await coreWaitOnline(printer, {\n timeoutMs: opts.waitTimeoutMs,\n intervalMs: opts.waitIntervalMs,\n onWaiting: opts.onWaiting,\n log: opts.log,\n }, DEFAULT_PRINTER_PATTERN);\n}\n\n/**\n * Print a single image buffer using the Brother XPS PrintTicket path.\n * Builds an XPS document with a custom CustomMediaSize for the tape, then\n * sends it to the print queue.\n */\nasync function printBuffer(imageBuffer: Buffer, printer: string, tape: TapeSize): Promise<void> {\n const media = MEDIA_OPTIONS[tape];\n const tempPath = path.join(os.tmpdir(), `label-${Date.now()}.png`);\n fs.writeFileSync(tempPath, imageBuffer);\n const psPath = tempPath.replace(/\\\\/g, \"\\\\\\\\\");\n\n const script = `\n$ErrorActionPreference = 'Stop'\nAdd-Type -AssemblyName System.Drawing\nAdd-Type -AssemblyName System.Printing\nAdd-Type -AssemblyName ReachFramework\nAdd-Type -AssemblyName PresentationCore\n\n$img = [System.Drawing.Image]::FromFile('${psPath}')\n\n$DPI = ${PRINT_DPI}\n$MICRONS_PER_INCH = 25400\n\n$labelLengthMicrons = [int]($img.Width / $DPI * $MICRONS_PER_INCH) + 3000\n$tapeWidthMicrons = ${media.width}\n\n$imgWidthWpf = $img.Width / $DPI * 96\n$imgHeightWpf = $img.Height / $DPI * 96\n\n$ticketXml = @\"\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<psf:PrintTicket xmlns:psf=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"1\"\n xmlns:psk=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords\"\n xmlns:ns0001=\"http://schemas.brother.info/mfc/printing/2006/11/printschemakeywords\">\n <psf:Feature name=\"psk:PageMediaSize\">\n <psf:Option name=\"ns0001:${media.name}\">\n <psf:ScoredProperty name=\"psk:MediaSizeWidth\">\n <psf:Value xsi:type=\"xsd:integer\">${media.width}</psf:Value>\n </psf:ScoredProperty>\n <psf:ScoredProperty name=\"psk:MediaSizeHeight\">\n <psf:ParameterRef name=\"psk:PageMediaSizeMediaSizeHeight\" />\n </psf:ScoredProperty>\n </psf:Option>\n </psf:Feature>\n <psf:ParameterInit name=\"psk:PageMediaSizeMediaSizeHeight\">\n <psf:Value xsi:type=\"xsd:integer\">$labelLengthMicrons</psf:Value>\n </psf:ParameterInit>\n <psf:Feature name=\"psk:PageOrientation\">\n <psf:Option name=\"psk:Landscape\" />\n </psf:Feature>\n <psf:Feature name=\"ns0001:PageRollFeedToEndOfSheet\">\n <psf:Option name=\"ns0001:FeedToImageEdge\" />\n </psf:Feature>\n <psf:Feature name=\"psk:PageMediaType\">\n <psf:Option name=\"psk:Label\" />\n </psf:Feature>\n <psf:Feature name=\"ns0001:JobRollCutAtEndOfJob\">\n <psf:Option name=\"ns0001:Cut\" />\n </psf:Feature>\n</psf:PrintTicket>\n\"@\n\n$xmlBytes = [System.Text.Encoding]::UTF8.GetBytes($ticketXml)\n$memStream = New-Object System.IO.MemoryStream(,$xmlBytes)\n$ticket = New-Object System.Printing.PrintTicket($memStream)\n\n$server = New-Object System.Printing.LocalPrintServer\n$queue = $server.GetPrintQueue('${printer.replace(/'/g, \"''\")}')\n\n$xpsPath = [System.IO.Path]::GetTempFileName() + \".xps\"\n\n$pageWidth = $labelLengthMicrons / $MICRONS_PER_INCH * 96\n$pageHeight = $tapeWidthMicrons / $MICRONS_PER_INCH * 96\n\n$package = [System.IO.Packaging.Package]::Open($xpsPath, [System.IO.FileMode]::Create)\n$xpsDoc = New-Object System.Windows.Xps.Packaging.XpsDocument($package)\n$writer = [System.Windows.Xps.Packaging.XpsDocument]::CreateXpsDocumentWriter($xpsDoc)\n\n$visual = New-Object System.Windows.Media.DrawingVisual\n$dc = $visual.RenderOpen()\n\n$bitmapImg = New-Object System.Windows.Media.Imaging.BitmapImage\n$bitmapImg.BeginInit()\n$bitmapImg.UriSource = New-Object System.Uri('${psPath}')\n$bitmapImg.EndInit()\n\n$yOffset = ($pageHeight - $imgHeightWpf) / 2\n$xOffset = 2 / 25.4 * 96\n$rect = New-Object System.Windows.Rect($xOffset, $yOffset, $imgWidthWpf, $imgHeightWpf)\n$dc.DrawImage($bitmapImg, $rect)\n$dc.Close()\n\n$writer.Write($visual, $ticket)\n\n$xpsDoc.Close()\n$package.Close()\n$img.Dispose()\n\n$xpsDocForPrint = New-Object System.Windows.Xps.Packaging.XpsDocument($xpsPath, [System.IO.FileAccess]::Read)\n$seq = $xpsDocForPrint.GetFixedDocumentSequence()\n\n$xpsWriter = [System.Printing.PrintQueue]::CreateXpsDocumentWriter($queue)\n$xpsWriter.Write($seq, $ticket)\n\n$xpsDocForPrint.Close()\nRemove-Item $xpsPath -ErrorAction SilentlyContinue\n`;\n try {\n await runScriptOrThrow(script);\n } finally {\n if (fs.existsSync(tempPath)) fs.unlinkSync(tempPath);\n }\n}\n"]}
package/api.ts CHANGED
@@ -20,9 +20,8 @@ import {
20
20
  getPrinterStatus,
21
21
  waitOnline as coreWaitOnline,
22
22
  runScriptOrThrow,
23
- readJsonConfig,
24
- mergeJsonConfig,
25
23
  } from "@bobfrankston/label-core";
24
+ import { configDir, readJson5, writeJson5 } from "@bobfrankston/userconfig";
26
25
  import type {
27
26
  LabelPrinter,
28
27
  PrintOptions as CorePrintOptions,
@@ -70,8 +69,19 @@ export type { Segment };
70
69
 
71
70
  /* ----- Constants ----- */
72
71
 
73
- const CONFIG_PATH = path.join(os.homedir(), ".brother-label.json");
74
- const DEFAULT_PRINTER = "Brother PT-P710BT";
72
+ /**
73
+ * The label config lives in the SHARED user-config directory, not beside this
74
+ * package, so every label utility (brother-print, iplabels, ...) reads one
75
+ * default instead of each keeping its own idea of "the printer".
76
+ *
77
+ * Claude Code 2026-09-01, at Bob's direction. The path comes from
78
+ * @bobfrankston/userconfig's `configDir` — never build it from homedir here;
79
+ * where that directory lives is UserConfig's business, not ours.
80
+ */
81
+ const CONFIG_PATH = path.join(configDir, "labels.json5");
82
+
83
+ /** Pre-2026-09-01 location. Read once to migrate, never written again. */
84
+ const LEGACY_CONFIG_PATH = path.join(os.homedir(), ".brother-label.json");
75
85
  const DEFAULT_PRINTER_PATTERN = /brother|^pt-|^ql-/i;
76
86
  const PRINT_DPI = 300;
77
87
  const VALID_TAPES: TapeSize[] = [6, 9, 12, 18, 24];
@@ -97,15 +107,32 @@ const MEDIA_OPTIONS: Record<TapeSize, { name: string; width: number }> = {
97
107
  /* ----- Config (backward-compat — note "defaultTape" stays in JSON) ----- */
98
108
 
99
109
  export function getConfig(): PrinterConfig {
100
- const raw: any = readJsonConfig(CONFIG_PATH);
110
+ const raw: any = fs.existsSync(CONFIG_PATH) ? readJson5(CONFIG_PATH) : migrateLegacyConfig();
101
111
  if (typeof raw.defaultTape === "string") {
102
112
  raw.defaultTape = parseInt(raw.defaultTape.replace("mm", ""), 10) as TapeSize;
103
113
  }
104
114
  return raw;
105
115
  }
106
116
 
117
+ /**
118
+ * Copy a pre-move ~/.brother-label.json into the new location the first time we
119
+ * look and find nothing there, so a default set before 2026-09-01 survives.
120
+ * Returns the settings either way; after the copy this never runs again.
121
+ */
122
+ function migrateLegacyConfig(): any {
123
+ if (!fs.existsSync(LEGACY_CONFIG_PATH)) return {};
124
+ let old: any;
125
+ try {
126
+ old = JSON.parse(fs.readFileSync(LEGACY_CONFIG_PATH, "utf-8"));
127
+ } catch {
128
+ return {}; // Unreadable legacy file is not worth failing an install over
129
+ }
130
+ writeJson5(CONFIG_PATH, old);
131
+ return old;
132
+ }
133
+
107
134
  export function setConfig(config: Partial<PrinterConfig>): void {
108
- mergeJsonConfig(CONFIG_PATH, config);
135
+ writeJson5(CONFIG_PATH, { ...getConfig(), ...config });
109
136
  }
110
137
 
111
138
  export function getConfigPath(): string {
@@ -113,13 +140,35 @@ export function getConfigPath(): string {
113
140
  }
114
141
 
115
142
  /**
116
- * The queue used when a caller names no printer: the configured default, else
117
- * the built-in fallback. Exported so callers can NAME the queue they are about
118
- * to use instead of saying "the default".
143
+ * The configured default queue, or null when none is set. Exported so callers
144
+ * can NAME the queue they are about to use instead of saying "the default".
119
145
  * Claude Code 2026-08-24.
146
+ *
147
+ * Claude Code 2026-09-01: this used to fall back to a wired-in
148
+ * "Brother PT-P710BT". That is exactly the bug Bob hit -- a machine with no
149
+ * configuration silently printed to a model name baked into the source, and
150
+ * nothing in the output said the choice had been invented rather than chosen.
151
+ * There is no fallback now; callers that need a printer use requirePrinter().
120
152
  */
121
153
  export function getDefaultPrinter(): string {
122
- return getConfig().defaultPrinter ?? DEFAULT_PRINTER;
154
+ return getConfig().defaultPrinter ?? null;
155
+ }
156
+
157
+ /**
158
+ * The queue to use when the caller named none -- or a user error saying how to
159
+ * set one. Every path that is about to move bytes goes through here, so "no
160
+ * printer" is reported once, in one voice, instead of each call site guessing.
161
+ */
162
+ function requirePrinter(printerName?: string): string {
163
+ const printer = printerName ?? getDefaultPrinter();
164
+ if (!printer) {
165
+ throw userError(
166
+ `No printer named and no default set. Set one with ` +
167
+ `'brother-print -default <name>', or name a printer with -p. ` +
168
+ `'brother-print -list' shows what is installed.`
169
+ );
170
+ }
171
+ return printer;
123
172
  }
124
173
 
125
174
  /* ----- Printer listing (backward-compat shape: { name }[]) ----- */
@@ -202,6 +251,7 @@ export async function detectTapeSize(printerName?: string): Promise<TapeSize> {
202
251
  */
203
252
  async function detectTapeSizeFromDriver(printerName?: string): Promise<TapeSize> {
204
253
  const printer = printerName ?? getDefaultPrinter();
254
+ if (!printer) return null; // Nothing to ask; tape stays unknown rather than throwing
205
255
  const script = `
206
256
  $ErrorActionPreference = 'SilentlyContinue'
207
257
  Add-Type -AssemblyName System.Printing | Out-Null
@@ -265,6 +315,7 @@ function withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {
265
315
  */
266
316
  export async function queryTapeStatus(printerName?: string): Promise<TapeStatus | null> {
267
317
  const printer = printerName ?? getDefaultPrinter();
318
+ if (!printer) return null; // Documented never to throw
268
319
  const usbPid = Object.entries(PT_USB_PIDS)
269
320
  .find(([model]) => printer.toUpperCase().includes(model))?.[1] ?? "";
270
321
  const script = String.raw`
@@ -437,12 +488,10 @@ class BrotherPrinterImpl implements LabelPrinter {
437
488
  return coreListPrinters(DEFAULT_PRINTER_PATTERN);
438
489
  }
439
490
  async getStatus(printerName?: string): Promise<PrinterStatus> {
440
- const printer = printerName ?? getDefaultPrinter();
441
- return getPrinterStatus(printer);
491
+ return getPrinterStatus(requirePrinter(printerName));
442
492
  }
443
493
  async waitOnline(printerName?: string, opts: WaitOptions = {}): Promise<PrinterStatus> {
444
- const printer = printerName ?? getDefaultPrinter();
445
- return coreWaitOnline(printer, opts, DEFAULT_PRINTER_PATTERN);
494
+ return coreWaitOnline(requirePrinter(printerName), opts, DEFAULT_PRINTER_PATTERN);
446
495
  }
447
496
 
448
497
  async render(opts: CorePrintOptions): Promise<Buffer> {
@@ -453,7 +502,7 @@ class BrotherPrinterImpl implements LabelPrinter {
453
502
 
454
503
  async print(opts: CorePrintOptions): Promise<CorePrintResult> {
455
504
  validateContent(opts);
456
- const printer = opts.printer ?? getDefaultPrinter();
505
+ const printer = requirePrinter(opts.printer);
457
506
  const tape = await this.resolveTape(opts.media);
458
507
  const image = await resolveContent(opts, TAPE_SIZES[tape].height, tape);
459
508
  await ensureOnline(printer, opts);
@@ -466,7 +515,7 @@ class BrotherPrinterImpl implements LabelPrinter {
466
515
  return coreRenderSegments(segments, TAPE_SIZES[tape].height, opts.textHeight, opts.space);
467
516
  }
468
517
  async printSegments(segments: Segment[], opts: CoreSegmentOptions = {}): Promise<CorePrintResult> {
469
- const printer = opts.printer ?? getDefaultPrinter();
518
+ const printer = requirePrinter(opts.printer);
470
519
  const tape = await this.resolveTape(opts.media);
471
520
  const image = await coreRenderSegments(segments, TAPE_SIZES[tape].height, opts.textHeight, opts.space);
472
521
  await ensureOnline(printer, opts);
package/cli.js CHANGED
@@ -4,12 +4,17 @@
4
4
  * Thin wrapper around api.ts using shared CLI primitives from label-core.
5
5
  */
6
6
  import * as fs from "fs";
7
+ import packageJson from "./package.json" with { type: "json" };
7
8
  import * as os from "os";
8
9
  import * as path from "path";
9
10
  import * as dns from "dns/promises";
10
11
  import { preprocessSingleQuotes, parseArgs, } from "@bobfrankston/label-core";
11
12
  import { print, render, renderSegments, printSegments, getConfig, setConfig, getConfigPath, listPrinters, resolvePrinter, getDefaultPrinter, detectTape, brotherPrinter, } from "./api.js";
12
- const VERSION = "1.1.0";
13
+ /* Claude Code 2026-09-01: was a hardcoded "1.1.0", 23 patch releases stale by
14
+ * the time anyone noticed -- `-version` and `-help` both reported a number that
15
+ * was not the one installed. Read it from the package instead; there is exactly
16
+ * one place a version belongs. */
17
+ const VERSION = packageJson.version;
13
18
  const VALID_TAPES = [6, 9, 12, 18, 24];
14
19
  function parseTape(value) {
15
20
  const num = parseInt(value.replace("mm", ""), 10);
@@ -21,6 +26,7 @@ function parseTape(value) {
21
26
  const VALUED = [
22
27
  { names: ["-tape"], key: "tape" },
23
28
  { names: ["-p", "-printer"], key: "printer" },
29
+ { names: ["-default"], key: "setDefault" },
24
30
  { names: ["-o", "-output"], key: "output" },
25
31
  { names: ["-a", "-aspect"], key: "aspect" },
26
32
  { names: ["-ht", "-height"], key: "height" },
@@ -67,6 +73,7 @@ Single quotes can wrap arguments: '7"' 'line1\\nline2'
67
73
  Options:
68
74
  -tape <size> Tape size: 6, 9, 12, 18, 24 (mm) [auto-detected]
69
75
  -p, -printer <name> Printer queue name
76
+ -default <name> Set the default printer (used when -p is omitted)
70
77
  -o, -output <file> Save PNG to file instead of printing
71
78
  -a, -aspect <r> Aspect ratio width:height for HTML (e.g. 3.5:2)
72
79
  -ht, -height <size> Text height: 12mm, .5in, or 50% (of tape height)
@@ -170,6 +177,10 @@ async function main() {
170
177
  parsed.opts.ql = host;
171
178
  }
172
179
  }
180
+ if (typeof parsed.opts.setDefault === "string") {
181
+ await cmdSetDefault(parsed.opts.setDefault);
182
+ return;
183
+ }
173
184
  switch (parsed.command) {
174
185
  case "list":
175
186
  await cmdList(parsed.opts);
@@ -537,6 +548,22 @@ async function cmdStatus(opts) {
537
548
  if (s.workOffline)
538
549
  console.log(`Work offline flag: true`);
539
550
  }
551
+ /**
552
+ * Set the default printer. `-default <name>` and `-config -printer <name>` are
553
+ * the same operation and share this one setter -- two ways to say it, one
554
+ * mechanism deciding what gets stored.
555
+ *
556
+ * The name goes through resolvePrinter first so what lands in the config is a
557
+ * real queue name: "710" is stored as "Brother PT-P710BT", and a name matching
558
+ * nothing is rejected here rather than at the next print.
559
+ * Claude Code 2026-09-01.
560
+ */
561
+ async function cmdSetDefault(value) {
562
+ const name = await resolvePrinter(value);
563
+ setConfig({ defaultPrinter: name });
564
+ console.log(`Default printer set to: ${name}`);
565
+ console.log(` (stored in ${getConfigPath()})`);
566
+ }
540
567
  async function cmdConfig(opts) {
541
568
  const hasUpdate = !!(opts.tape || opts.printer);
542
569
  if (!hasUpdate) {
@@ -554,6 +581,7 @@ async function cmdConfig(opts) {
554
581
  console.log(`Default tape set to: ${t}mm`);
555
582
  }
556
583
  if (opts.printer) {
584
+ /* main() already resolved opts.printer to a real queue name. */
557
585
  setConfig({ defaultPrinter: opts.printer });
558
586
  console.log(`Default printer set to: ${opts.printer}`);
559
587
  }
package/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * Brother Label Printer CLI\n * Thin wrapper around api.ts using shared CLI primitives from label-core.\n */\n\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport * as dns from \"dns/promises\";\nimport {\n preprocessSingleQuotes,\n parseArgs,\n} from \"@bobfrankston/label-core\";\nimport type {\n PrintOptions as CorePrintOptions,\n PrinterStatus,\n Segment,\n ValuedOptionSpec,\n BooleanFlagSpec,\n} from \"@bobfrankston/label-core\";\nimport {\n print,\n render,\n renderSegments,\n printSegments,\n getConfig,\n setConfig,\n getConfigPath,\n listPrinters,\n resolvePrinter,\n getDefaultPrinter,\n detectTape,\n brotherPrinter,\n} from \"./api.js\";\nimport type { TapeSize, PrintOptions, SegmentOptions } from \"./api.js\";\n\nconst VERSION = \"1.1.0\";\nconst VALID_TAPES: TapeSize[] = [6, 9, 12, 18, 24];\n\nfunction parseTape(value: string): TapeSize {\n const num = parseInt(value.replace(\"mm\", \"\"), 10) as TapeSize;\n if (!VALID_TAPES.includes(num)) {\n throw new UserError(`Invalid tape size: ${value}. Valid: ${VALID_TAPES.join(\", \")}`);\n }\n return num;\n}\n\nconst VALUED: ValuedOptionSpec[] = [\n { names: [\"-tape\"], key: \"tape\" },\n { names: [\"-p\", \"-printer\"], key: \"printer\" },\n { names: [\"-o\", \"-output\"], key: \"output\" },\n { names: [\"-a\", \"-aspect\"], key: \"aspect\" },\n { names: [\"-ht\", \"-height\"], key: \"height\" },\n { names: [\"-s\", \"-space\"], key: \"space\" },\n { names: [\"-timeout\"], key: \"timeout\" },\n { names: [\"-interval\"], key: \"interval\" },\n { names: [\"-ql\"], key: \"ql\" },\n { names: [\"-ql-media\"], key: \"qlMedia\" },\n { names: [\"-port\"], key: \"port\" },\n];\n\nconst BOOLEAN: BooleanFlagSpec[] = [\n { names: [\"-w\", \"-html\"], key: \"html\" },\n { names: [\"-i\", \"-image\"], key: \"image\" },\n { names: [\"-t\"], key: \"text\" },\n { names: [\"-c\", \"-clip\"], key: \"clip\" },\n { names: [\"-no-wait\", \"-nowait\"], key: \"nowait\" },\n { names: [\"-mdns\"], key: \"mdns\" },\n { names: [\"-vb\", \"-verbose\"], key: \"verbose\" },\n { names: [\"-queue\"], key: \"queue\" },\n { names: [\"-no-cut\", \"-nocut\"], key: \"nocut\" },\n { names: [\"-help\", \"-h\", \"-?\"], key: \"help\" },\n { names: [\"-version\", \"-v\"], key: \"version\" },\n];\n\nconst SUBCOMMANDS = [\"list\", \"status\", \"config\"];\n\nfunction showHelp(): void {\n console.log(`Brother Label Printer CLI v${VERSION}\n\nUsage:\n brother-print [options] <text> Print text\n brother-print [options] <file> Print html/txt/image file (auto-detected)\n brother-print -clip [options] Print clipboard contents (image or text)\n brother-print -text <v> -qr <v> ... Print ordered text/qr segments\n brother-print -list [-mdns] List Brother printers and status\n (-mdns also discovers network printers)\n brother-print -status [-p <name>] Show printer status\n brother-print -config Show / set defaults\n\nCommands take a leading dash so they can never be confused with label content:\na bare word is always something to print, a dashed word is always a command.\n\nTape size is auto-detected from the printer. Use -tape to override.\nSingle quotes can wrap arguments: '7\"' 'line1\\\\nline2'\n\nOptions:\n -tape <size> Tape size: 6, 9, 12, 18, 24 (mm) [auto-detected]\n -p, -printer <name> Printer queue name\n -o, -output <file> Save PNG to file instead of printing\n -a, -aspect <r> Aspect ratio width:height for HTML (e.g. 3.5:2)\n -ht, -height <size> Text height: 12mm, .5in, or 50% (of tape height)\n -s, -space <size> Space between segments: 12px, 1mm, .2in\n -t, -text Force input as literal text (-text <v> for segments)\n -qr <data> QR code segment\n -w, -html Force input as HTML file path\n -i, -image Force input as image file path\n -c, -clip Read content from clipboard (image preferred, then text)\n -no-wait Fail immediately if printer is offline (default: wait)\n -timeout <secs> Max wait time when printer is offline\n -interval <secs> Polling interval while waiting (default 2)\n -mdns With -list: also discover network printers via mDNS\n -ql <host> Print to a Brother QL series printer over TCP/9100\n (bypasses Windows queue; e.g. -ql ql720 or -ql 1.2.3.4)\n -ql-media <id> QL media id (e.g. 271=DK-11201 29×90mm, 259=DK-22205 62mm)\n Required when the printer doesn't respond to status\n -queue Print through the Windows spooler (XPS) instead of\n writing raster bytes straight to the printer's port\n -port <COMn> Serial/Bluetooth port for direct printing (overrides\n the port looked up from the printer queue)\n -no-cut Do not cut the tape after the label (direct path only)\n -vb, -verbose Print extra QL diagnostic messages (status, media source)\n -help Show this help\n -version Show version`);\n}\n\n/** Expected user-facing error: prints one line, no log file, no stack. */\nclass UserError extends Error {\n readonly isUserError = true;\n}\n\n/**\n * Single-line status display: on a TTY the line is rewritten in place\n * (CR + erase-line) instead of scrolling; callers must clear() before any\n * normal output so it doesn't collide with the pending status line.\n */\nconst statusLine = {\n active: false,\n update(msg: string): void {\n if (process.stderr.isTTY) {\n process.stderr.write(`\\r\\x1b[2K${msg}`);\n this.active = true;\n } else {\n console.error(msg);\n }\n },\n clear(): void {\n if (this.active) {\n process.stderr.write(`\\r\\x1b[2K`);\n this.active = false;\n }\n },\n};\n\n/** console.log that first clears any in-place status line. */\nfunction outln(msg: string): void {\n statusLine.clear();\n console.log(msg);\n}\n\nasync function main(): Promise<void> {\n const argv = preprocessSingleQuotes(process.argv.slice(2));\n let parsed;\n try {\n parsed = parseArgs(argv, VALUED, BOOLEAN, SUBCOMMANDS);\n } catch (e: any) {\n console.error(`Error: ${e.message}`);\n process.exit(1);\n }\n\n if (parsed.unknown.length > 0) {\n console.error(`Unknown option(s): ${parsed.unknown.join(\", \")}`);\n console.error(`Run \"brother-print -help\" for usage.`);\n process.exit(1);\n }\n\n /* Bare `list` used to be the command syntax; it is now `-list`. Refusing\n * beats guessing: printing a label that says \"list\" and listing printers\n * are both plausible readings of the same word. */\n if (parsed.ambiguous.length > 0) {\n const w = parsed.ambiguous[0];\n console.error(`Ambiguous argument: \"${w}\" -- commands now take a dash.`);\n console.error(` brother-print -${w} run the ${w} command`);\n console.error(` brother-print -text ${w} print a label that says \"${w}\"`);\n process.exit(1);\n }\n\n if (parsed.opts.help) { showHelp(); return; }\n if (parsed.opts.version) { console.log(VERSION); return; }\n\n try {\n if (typeof parsed.opts.printer === \"string\") {\n parsed.opts.printer = await resolvePrinter(parsed.opts.printer);\n /* Auto-route QL series through the QL TCP path. The XPS / CustomMediaSize\n * pipeline is P-touch-only; sending it to a QL queue produces an XPS\n * error. If the user already passed -ql explicitly, leave it alone. */\n if (!parsed.opts.ql && isQLPrinter(parsed.opts.printer)) {\n const host = await resolveQLHost(parsed.opts.printer);\n if (host) parsed.opts.ql = host;\n }\n }\n switch (parsed.command) {\n case \"list\": await cmdList(parsed.opts); return;\n case \"status\": await cmdStatus(parsed.opts); return;\n case \"config\": await cmdConfig(parsed.opts); return;\n }\n await cmdPrint(parsed.opts, parsed.segments, parsed.inputs);\n } catch (e: any) {\n statusLine.clear();\n /* Timeout/offline are expected conditions, not crashes — one line,\n * no error-report file. */\n if (e?.isUserError || /^Timed out waiting for printer|is offline \\(/.test(e?.message ?? \"\")) {\n console.error(`Error: ${e.message}`);\n process.exit(1);\n }\n reportError(e);\n process.exit(1);\n }\n}\n\nfunction isQLPrinter(name: string): boolean {\n return /\\bQL-/i.test(name);\n}\n\n/**\n * Look up the TCP host for a QL printer's installed Windows queue. Pulls the\n * port name via label-core, then asks PowerShell for that port's\n * PrinterHostAddress. Returns undefined if the port isn't a TCP/IP port (e.g.\n * the QL-820NWB's BRWxxxx Bluetooth port has no host address).\n */\nasync function resolveQLHost(printerName: string): Promise<string | undefined> {\n const { listPrinters: coreListPrinters, runScriptOrThrow } =\n await import(\"@bobfrankston/label-core\");\n const all = await coreListPrinters(/brother|^pt-|^ql-/i);\n const info = all.find(p => p.name === printerName);\n if (!info?.portName) return undefined;\n const port = info.portName.replace(/'/g, \"''\");\n const script = `\n$ErrorActionPreference = 'SilentlyContinue'\n$p = Get-PrinterPort -Name '${port}'\nif ($p -and $p.PrinterHostAddress) { Write-Output $p.PrinterHostAddress }\n`;\n try {\n const out = (await runScriptOrThrow(script)).trim();\n if (!out) return undefined;\n return await resolvableHost(out);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Brother's installer often writes a bare NetBIOS-style hostname (BRWxxxx)\n * as the port's PrinterHostAddress, which won't resolve in environments where\n * the DNS suffix isn't auto-appended. Resolution tiers, in order:\n * 1. as-is via the OS resolver\n * 2. <host>.<suffix> for every DNS suffix the OS knows about (global search\n * list, per-connection suffix, computer domain) — covers the case where\n * the user pings as FQDN manually because Windows isn't auto-appending\n * 3. <host>.local via the OS resolver (Windows 10 1803+ native mDNS)\n * 4. multicast mDNS query directly (bypasses OS resolver — works even when\n * Windows .local resolution is disabled, common in AD/domain environments)\n */\nasync function resolvableHost(host: string): Promise<string> {\n if (/^\\d{1,3}(\\.\\d{1,3}){3}$/.test(host)) return host;\n try {\n await dns.lookup(host);\n return host;\n } catch {}\n if (!host.includes(\".\")) {\n const suffixes = await getDnsSuffixes();\n const { default_fqdn } = await import(\"@bobfrankston/miscinfo\");\n if (default_fqdn && !suffixes.includes(default_fqdn.toLowerCase())) {\n suffixes.push(default_fqdn.toLowerCase());\n }\n for (const suffix of suffixes) {\n const candidate = `${host}.${suffix}`;\n try {\n await dns.lookup(candidate);\n return candidate;\n } catch {}\n }\n }\n const mdnsName = host.includes(\".\") ? host : host + \".local\";\n try {\n await dns.lookup(mdnsName);\n return mdnsName;\n } catch {}\n try {\n const { discoverPdlPrinters } = await import(\"./mdns.js\");\n const printers = await discoverPdlPrinters(2500);\n const target = host.toLowerCase();\n const hit = printers.find(p => {\n const h = p.hostname.toLowerCase().replace(/\\.$/, \"\");\n return h === target || h === target + \".local\" || h.startsWith(target + \".\");\n });\n if (hit && hit.addresses.length > 0) return hit.addresses[0];\n } catch {}\n return host;\n}\n\nlet dnsSuffixCache: string[] | undefined;\n/**\n * Read every DNS suffix the system knows about: the global SuffixSearchList,\n * each adapter's ConnectionSpecificSuffix, and the computer's AD/workgroup\n * domain. Cached per-process. Returns lowercased, de-duplicated, in priority\n * order (search list first since that's what the user explicitly configured).\n */\nasync function getDnsSuffixes(): Promise<string[]> {\n if (dnsSuffixCache) return dnsSuffixCache;\n const { runScriptOrThrow } = await import(\"@bobfrankston/label-core\");\n const script = `\n$ErrorActionPreference = 'SilentlyContinue'\n$out = @()\n$out += (Get-DnsClientGlobalSetting).SuffixSearchList\n$out += Get-DnsClient | Select-Object -ExpandProperty ConnectionSpecificSuffix\n$out += (Get-CimInstance Win32_ComputerSystem).Domain\n$out | Where-Object { $_ -and $_ -ne 'WORKGROUP' } | ForEach-Object { $_.ToLower() } | Select-Object -Unique\n`;\n try {\n const out = await runScriptOrThrow(script);\n dnsSuffixCache = out.split(/\\r?\\n/).map(s => s.trim()).filter(Boolean);\n } catch {\n dnsSuffixCache = [];\n }\n return dnsSuffixCache;\n}\n\n\n/**\n * Print an error with full context: message, cause chain (Node's fetch and\n * other newer APIs put the actual cause in error.cause), and stack on -v.\n */\n/**\n * Report an error: print a one-line summary to stderr and write the full\n * cause-chain (with stacks, codes, paths) to a temp file. Avoids dumping\n * walls of error text into the user's terminal. Set BROTHER_PRINT_DEBUG=1\n * to also include the full chain inline.\n */\nfunction reportError(e: any): void {\n const lines: string[] = [];\n lines.push(`# brother-print error report`);\n lines.push(`# timestamp: ${new Date().toISOString()}`);\n lines.push(`# argv: ${process.argv.join(\" \")}`);\n lines.push(`# cwd: ${process.cwd()}`);\n lines.push(`# pid: ${process.pid}`);\n lines.push(\"\");\n\n let cur = e;\n let depth = 0;\n while (cur) {\n const prefix = depth === 0 ? \"Error\" : \"Caused by\";\n const name = cur.name && cur.name !== \"Error\" ? ` ${cur.name}` : \"\";\n const code = cur.code ? ` [${cur.code}]` : \"\";\n const msg = cur.message ?? String(cur);\n lines.push(`${prefix}${name}${code}: ${msg}`);\n if (cur.path) lines.push(` path: ${cur.path}`);\n if (cur.input) lines.push(` input: ${cur.input}`);\n if (cur.stack) lines.push(String(cur.stack));\n lines.push(\"\");\n cur = cur.cause;\n depth++;\n if (depth > 8) { lines.push(\"... (cause chain truncated at 8 levels)\"); break; }\n }\n\n const dump = lines.join(\"\\n\");\n const tempPath = path.join(os.tmpdir(), `brother-print-error-${Date.now()}-${process.pid}.log`);\n let wroteFile = false;\n try { fs.writeFileSync(tempPath, dump); wroteFile = true; } catch { /* fallback */ }\n\n if (wroteFile) {\n console.error(`Error: ${tempPath}`);\n } else {\n console.error(dump);\n }\n if (process.env.BROTHER_PRINT_DEBUG) {\n console.error(\"--- full report (BROTHER_PRINT_DEBUG enabled) ---\");\n console.error(dump);\n }\n}\n\nasync function cmdList(opts: Record<string, string | boolean>): Promise<void> {\n const printers = await listPrinters();\n /* Brother's listPrinters returns just { name } (legacy shape). To get\n * portName/driverName for the diagnostic line, query label-core's\n * coreListPrinters too. */\n const { listPrinters: coreListPrinters } = await import(\"@bobfrankston/label-core\");\n const all = await coreListPrinters(/brother|^pt-|^ql-/i);\n const byName = new Map(all.map(p => [p.name, p]));\n\n if (printers.length === 0) {\n console.log(\"No installed Brother printers.\");\n } else {\n const sorted = [...printers].sort((a, b) => a.name.localeCompare(b.name));\n console.log(`Brother printers (${sorted.length}):`);\n for (let i = 0; i < sorted.length; i++) {\n const p = sorted[i];\n const info = byName.get(p.name);\n let statusStr = \"?\";\n let queueWarning = \"\";\n try {\n const s = await brotherPrinter.getStatus(p.name);\n statusStr = s.online ? \"online\" : `offline (${s.statusText}${s.error ? \", \" + s.error : \"\"})`;\n queueWarning = s.queueWarning;\n } catch (e: any) {\n statusStr = `status error: ${e.message}`;\n }\n const port = info ? shortenPort(info.portName) : \"(unknown)\";\n const driver = info?.driverName ?? \"(unknown)\";\n console.log(` #${i + 1} ${p.name}`);\n if (info?.comment) console.log(` description: ${info.comment}`);\n if (info?.location) console.log(` location: ${info.location}`);\n console.log(` port: ${port}`);\n if (info?.portName && info.portName !== port) {\n console.log(` full port: ${info.portName}`);\n }\n console.log(` driver: ${driver}`);\n if (info?.shareName && info.shareName !== p.name) {\n console.log(` share name: ${info.shareName}`);\n }\n console.log(` status: ${statusStr}`);\n if (queueWarning) console.log(` warning: ${queueWarning}`);\n }\n }\n\n if (opts.mdns) {\n const { discoverPdlPrinters, isBrother, modelFromTxt, matchesInstalledPort } =\n await import(\"./mdns.js\");\n console.log(\"\");\n console.log(\"Browsing mDNS for _pdl-datastream._tcp (3s)...\");\n const found = (await discoverPdlPrinters()).filter(isBrother);\n if (found.length === 0) {\n console.log(\"No Brother printers responded via mDNS.\");\n return;\n }\n const installedPorts = all.map(p => p.portName);\n const networkOnly = found.filter(m => !installedPorts.some(pn => matchesInstalledPort(m, pn)));\n const matched = found.filter(m => installedPorts.some(pn => matchesInstalledPort(m, pn)));\n\n console.log(`mDNS responders (${found.length}; ${matched.length} matched, ${networkOnly.length} network-only):`);\n let n = 1;\n for (const m of [...matched, ...networkOnly]) {\n const isNetOnly = networkOnly.includes(m);\n const tag = isNetOnly ? \" [network only]\" : \" [installed]\";\n const model = modelFromTxt(m) ?? \"(unknown model)\";\n console.log(` #${n++} ${m.instanceName}${tag}`);\n console.log(` model: ${model}`);\n console.log(` hostname: ${m.hostname.replace(/\\.$/, \"\")}`);\n if (m.addresses.length > 0) {\n console.log(` address: ${m.addresses.join(\", \")}`);\n }\n console.log(` port: ${m.port}`);\n }\n }\n}\n\n/**\n * Pull a short identifier out of a Windows printer port: \"... on hostname\"\n * → hostname; raw IP/hostname kept as-is; USB ports kept as-is.\n */\nfunction shortenPort(portName: string): string {\n if (!portName) return \"(unknown)\";\n const onMatch = portName.match(/\\bon\\s+(\\S+)\\s*$/i);\n if (onMatch) return onMatch[1];\n const hostMatch = portName.match(/\\b(\\d{1,3}(?:\\.\\d{1,3}){3}|[\\w-]+\\.local|[\\w-]+\\.[\\w.-]+)\\b/);\n if (hostMatch) return hostMatch[1];\n return portName;\n}\n\n/**\n * Show details for a single resolved printer: name, port, driver, online\n * status, and the loaded media. For QL printers (auto-detected via the QL\n * TCP path) the media is read from the Windows driver's print ticket; for\n * PT printers detectTape queries the printer live (raw ESC i S status),\n * falling back to the driver ticket when the printer is unreachable.\n */\nasync function cmdPrinterInfo(printerName: string, qlHost: string | undefined): Promise<void> {\n const { listPrinters: coreListPrinters } = await import(\"@bobfrankston/label-core\");\n const all = await coreListPrinters(/brother|^pt-|^ql-/i);\n const info = all.find(p => p.name === printerName);\n\n console.log(`Printer: ${printerName}`);\n if (info?.portName) {\n console.log(`Port: ${info.portName}`);\n }\n if (info?.driverName) {\n console.log(`Driver: ${info.driverName}`);\n }\n try {\n const s = await brotherPrinter.getStatus(printerName);\n const statusStr = s.online ? \"online\" : `offline (${s.statusText}${s.error ? \", \" + s.error : \"\"})`;\n console.log(`Status: ${statusStr}`);\n console.log(`Queue: ${s.queueLength} job(s)`);\n for (const j of s.jobs) {\n console.log(` #${j.id} \"${j.documentName}\" -- ${j.statusText}${j.stuck ? \" [STUCK]\" : \"\"}`);\n }\n if (s.queueWarning) console.log(`Warning: ${s.queueWarning}`);\n } catch (e: any) {\n console.log(`Status: error: ${e.message}`);\n }\n\n if (!qlHost) {\n const { resolvePtModel } = await import(\"./ptdirect.js\");\n const model = resolvePtModel(printerName);\n const direct = await resolvePtPort(printerName);\n if (model && direct) {\n console.log(`Direct: ${direct.port} via ${direct.source}`);\n console.log(` profile ${model.name}${model.verified ? \"\" : \" — geometry not from this model's own manual\"}`);\n } else {\n console.log(`Direct: unavailable (${!model ? \"no raster profile for this model\" : \"no serial port found\"}) — prints via the spooler`);\n }\n }\n\n if (qlHost) {\n console.log(`QL host: ${qlHost} (TCP/9100)`);\n const { detectQLMediaFromWindows } = await import(\"./ql.js\");\n const media = await detectQLMediaFromWindows(printerName);\n if (media) {\n console.log(`Media: ${media.name} (id ${media.id}, ${media.widthMm}mm${media.heightMm ? `×${media.heightMm}mm` : \", continuous\"})`);\n console.log(` printArea ${media.printAreaDots} dots${media.dieCutMaskedAreaDots ? `, dieCut ${media.dieCutMaskedAreaDots} dots` : \"\"}`);\n } else {\n console.log(`Media: (not detected from Windows driver — pass -ql-media <id>)`);\n }\n } else {\n const detected = await detectTape(printerName);\n const src = detected?.source === \"printer\" ? \"live from printer\" : \"driver default — printer unreachable\";\n console.log(`Loaded tape: ${detected ? `${detected.tape}mm (${src})` : \"(not detected)\"}`);\n }\n}\n\nasync function cmdStatus(opts: Record<string, string | boolean>): Promise<void> {\n const name = (opts.printer as string) || undefined;\n const s = await brotherPrinter.getStatus(name);\n console.log(`Printer: ${s.name}`);\n console.log(`Online: ${s.online ? \"yes\" : \"no\"}`);\n console.log(`Status: ${s.statusText}`);\n if (s.error) console.log(`Error: ${s.error}`);\n console.log(`Queue: ${s.queueLength} job(s)`);\n for (const j of s.jobs) {\n console.log(` #${j.id} \"${j.documentName}\" -- ${j.statusText}${j.stuck ? \" [STUCK]\" : \"\"}`);\n }\n if (s.queueWarning) console.log(`Warning: ${s.queueWarning}`);\n if (s.workOffline) console.log(`Work offline flag: true`);\n}\n\nasync function cmdConfig(opts: Record<string, string | boolean>): Promise<void> {\n const hasUpdate = !!(opts.tape || opts.printer);\n if (!hasUpdate) {\n const cfg = getConfig();\n console.log(`Configuration:`);\n console.log(` File: ${getConfigPath()}`);\n console.log(` Default tape: ${cfg.defaultTape ? cfg.defaultTape + \"mm\" : \"(not set)\"}`);\n console.log(` Default printer: ${cfg.defaultPrinter ?? \"(not set)\"}`);\n console.log(\"\\nValid tape sizes: 6, 9, 12, 18, 24\");\n return;\n }\n if (opts.tape) {\n const t = parseTape(opts.tape as string);\n setConfig({ defaultTape: t });\n console.log(`Default tape set to: ${t}mm`);\n }\n if (opts.printer) {\n setConfig({ defaultPrinter: opts.printer as string });\n console.log(`Default printer set to: ${opts.printer}`);\n }\n}\n\nasync function resolveTape(opts: Record<string, string | boolean>): Promise<TapeSize> {\n /* Explicit -tape skips the status round-trip entirely: the user said\n * what they want, and the live query costs ~1s of PowerShell. */\n if (opts.tape) return parseTape(opts.tape as string);\n const detected = await detectTape(opts.printer as string | undefined);\n if (detected) return detected.tape;\n return getConfig().defaultTape ?? 24;\n}\n\nasync function cmdPrint(\n opts: Record<string, string | boolean>,\n segments: Segment[],\n inputs: string[]\n): Promise<void> {\n const tape = await resolveTape(opts);\n\n // If there are 2+ positional inputs, treat each as a text segment.\n // (A single positional input is handled below via classifyInput so it can\n // auto-detect file paths.)\n if (inputs.length > 1 || (inputs.length >= 1 && segments.length > 0)) {\n for (const inp of inputs) {\n segments.push({ type: \"text\", value: inp });\n }\n inputs.length = 0;\n }\n\n const baseOpts = {\n printer: opts.printer as string | undefined,\n wait: !opts.nowait,\n waitTimeoutMs: opts.timeout ? Math.round(parseFloat(opts.timeout as string) * 1000) : undefined,\n waitIntervalMs: opts.interval ? Math.round(parseFloat(opts.interval as string) * 1000) : undefined,\n onWaiting: makeWaitCallback(),\n log: (msg: string) => outln(msg),\n };\n\n const qlHost = typeof opts.ql === \"string\" ? opts.ql : undefined;\n const qlMediaId = typeof opts.qlMedia === \"string\" ? parseInt(opts.qlMedia, 10) : undefined;\n\n // Multi-segment mode: explicit -text/-qr (>=1 segment), with positional joined in\n if (segments.length > 1 || (segments.length === 1 && inputs.length === 0)) {\n const segOpts: SegmentOptions = {\n ...baseOpts,\n tape,\n textHeight: opts.height as string | undefined,\n space: opts.space as string | undefined,\n };\n let segDirectPort: string;\n if (opts.output) {\n const buffer = await renderSegments(segments, tape, opts.height as string | undefined, opts.space as string | undefined);\n fs.writeFileSync(opts.output as string, buffer);\n outln(`Saved to ${opts.output}`);\n } else if (qlHost) {\n const buffer = await renderSegments(segments, tape, opts.height as string | undefined, opts.space as string | undefined);\n const { printPngToQL } = await import(\"./ql.js\");\n await printPngToQL(qlHost, buffer, qlMediaId, opts.printer as string | undefined, !!opts.verbose);\n outln(`Printed ${segments.length} segment(s) on ${(opts.printer as string) || \"QL\"} @ ${qlHost}, ${tape}mm (direct TCP/9100)`);\n } else if (segDirectPort = await tryPrintDirect(\n await renderSegments(segments, tape, opts.height as string | undefined, opts.space as string | undefined),\n opts, tape)) {\n reportPrinted(`${segments.length} segment(s) `, opts, tape, segDirectPort, lastDirectConfirmed);\n } else {\n await printSegments(segments, segOpts);\n reportPrinted(`${segments.length} segment(s) `, opts, tape, null);\n }\n return;\n }\n\n // Single content op\n const printOpts: PrintOptions = {\n ...baseOpts,\n tape,\n aspect: opts.aspect as string | undefined,\n textHeight: opts.height as string | undefined,\n };\n\n if (opts.clip) {\n printOpts.clip = true;\n } else if (inputs.length === 1) {\n Object.assign(printOpts, classifyInput(inputs[0], opts));\n } else if (inputs.length === 0 && segments.length === 0) {\n if (opts.printer) {\n await cmdPrinterInfo(opts.printer as string, qlHost);\n return;\n }\n showHelp();\n return;\n }\n\n if (opts.output) {\n const buffer = await render(printOpts);\n fs.writeFileSync(opts.output as string, buffer);\n outln(`Saved to ${opts.output}`);\n return;\n }\n if (qlHost) {\n const buffer = await render(printOpts);\n const { printPngToQL } = await import(\"./ql.js\");\n await printPngToQL(qlHost, buffer, qlMediaId, opts.printer as string | undefined, !!opts.verbose);\n outln(`Printed on ${(opts.printer as string) || \"QL\"} @ ${qlHost} (direct TCP/9100)`);\n return;\n }\n const directPort = await tryPrintDirect(await render(printOpts), opts, tape);\n const directConfirmed = lastDirectConfirmed;\n if (directPort) {\n reportPrinted(\"\", opts, tape, directPort, directConfirmed);\n return;\n }\n await print(printOpts);\n reportPrinted(\"\", opts, tape, null);\n}\n\n/**\n * Name the printer, the tape and the route a label actually took.\n *\n * \"Printed on 24mm tape\" is not something the user can check: it does not say\n * which of four Brother printers took it, and it reads identically whether the\n * bytes reached the printer or merely reached the Windows queue -- which is\n * where labels disappear. Naming the target and the route makes the line\n * verifiable, and still means something when read back in a log later.\n */\nfunction describeTarget(opts: Record<string, string | boolean>, tape: TapeSize, port: string): string {\n const printer = (opts.printer as string) || getDefaultPrinter();\n return port\n ? `${printer}, ${tape}mm tape (direct to ${port})`\n : `${printer}, ${tape}mm tape`;\n}\n\n/**\n * The verb has to be honest about what happened. A direct write reached the\n * printer, so \"Printed\" is a claim we can stand behind. Handing a job to the\n * Windows spooler is not printing -- the job can sit Retained in Error behind\n * another dead job and never reach the tape, which is exactly how labels have\n * been going missing. Say \"Queued\" for that, and name the printer either way.\n */\nfunction reportPrinted(\n what: string,\n opts: Record<string, string | boolean>,\n tape: TapeSize,\n port: string,\n confirmed?: boolean\n): void {\n let verb: string;\n let tail: string;\n if (!port) {\n verb = \"Queued\";\n tail = \" -- the spooler has it; check the queue if nothing comes out\";\n } else if (confirmed) {\n verb = \"Printed\";\n tail = \"\";\n } else {\n /* The bytes were delivered, and that is all we know. This printer does\n * not report back, so it can still have refused the job -- wrong tape,\n * cover open, cutter jam -- with nothing to tell us. Claiming \"Printed\"\n * here is what made earlier failures look like successes. */\n verb = \"Sent\";\n tail = \" -- this printer does not confirm, so check the tape\";\n }\n outln(`${verb} ${what}on ${describeTarget(opts, tape, port)}${tail}`);\n}\n\n/**\n * Write the rendered label straight to the printer's port, skipping the\n * Windows spooler. Returns false when this printer has no direct path, so the\n * caller can fall back to the XPS/queue route.\n *\n * The direct route is the default because the queue is where labels go to die:\n * a job that fails is left Retained and blocks every later job until someone\n * clears it by hand, and `WorkOffline` discards jobs without a word. Writing\n * the bytes ourselves either succeeds or throws — there is no third state that\n * looks like success and prints nothing. `-queue` opts back in.\n */\nasync function tryPrintDirect(\n png: Buffer,\n opts: Record<string, string | boolean>,\n tape: TapeSize\n): Promise<string> {\n if (opts.queue) {\n /* A queue can be pointed at a discard port so the spooler stops\n * fighting us for the printer's serial port. Printing to it would\n * report success and put nothing on the tape, which is the one\n * outcome this whole module exists to prevent. */\n await refuseDiscardQueue(opts.printer as string);\n return null;\n }\n /* Fall back to the same default the spooler path uses, so omitting -p does\n * not silently drop the label into the queue. */\n const printerName = (opts.printer as string) || getDefaultPrinter();\n if (!printerName) return null;\n\n const { resolvePtModel, printPtDirect } = await import(\"./ptdirect.js\");\n const model = resolvePtModel(printerName);\n if (!model) return null;\n\n const port = (opts.port as string) || (await resolvePtPort(printerName))?.port;\n if (!port) return null;\n\n lastDirectConfirmed = model.confirmsPrint;\n const jobsBefore = await listJobIds(printerName);\n try {\n await printPtDirect(png, {\n port,\n printerName,\n tape,\n autoCut: !opts.nocut,\n log: opts.verbose ? (m: string) => outln(m) : undefined,\n });\n } finally {\n /* Clear it even when the write failed -- a failed open still leaves the\n * phantom behind, and that is precisely when a wedged queue is most\n * confusing to look at. */\n await clearPhantomJobs(printerName, jobsBefore);\n }\n return port;\n}\n\n/**\n * Whether the last direct print was confirmed by the printer. Set by\n * tryPrintDirect; read by the reporting call right after it. A module-level\n * value rather than a return field because the port string is already the\n * caller's success signal and threading a second one through both dispatch\n * sites obscures them.\n */\nlet lastDirectConfirmed = false;\n\n/** Ports that swallow whatever the spooler sends them. */\nconst DISCARD_PORTS = /^(nul|null|nul:|null:)$/i;\n\n/**\n * List the spooler's current job ids for a printer. Best-effort: a failure\n * here must never stop a label printing.\n */\nasync function listJobIds(printerName: string): Promise<Set<number>> {\n try {\n const { runScriptOrThrow } = await import(\"@bobfrankston/label-core\");\n const out = await runScriptOrThrow(\n `@(Get-PrintJob -PrinterName '${printerName.replace(/'/g, \"''\")}' -ErrorAction SilentlyContinue).Id -join ','`\n );\n return new Set(out.trim().split(\",\").map(Number).filter(n => !isNaN(n)));\n } catch {\n return new Set();\n }\n}\n\n/**\n * Remove the empty job Windows invents when we open the printer's port.\n *\n * Writing directly to a serial port that a print queue is bound to makes the\n * spooler materialise a zero-byte job -- proven with a script that only opens\n * the port and writes an initialise sequence. That job then parks itself in\n * Error and drags the queue down with it, which is what made the queue look\n * broken after every successful direct print.\n *\n * The queue has to stay bound to the port: that binding is what establishes\n * and holds the Bluetooth RFCOMM link. Open the port with the queue pointed\n * elsewhere and the link will not come up at all. So the phantom cannot be\n * prevented, only cleared.\n *\n * Scoped by identity, not by size: only jobs that did not exist before we\n * opened the port are removed. Size is no use as a filter -- the spooler\n * records a copy of the bytes we put on the wire, so these jobs are not empty\n * (1205 and 4373 bytes were observed for two ordinary labels).\n *\n * The residual risk is a real job submitted by another program during the\n * second or so a direct print takes. That window is narrow and the alternative\n * -- leaving the queue permanently in Error after every label -- is worse.\n */\nasync function clearPhantomJobs(printerName: string, before: Set<number>): Promise<void> {\n try {\n const { runScriptOrThrow } = await import(\"@bobfrankston/label-core\");\n const name = printerName.replace(/'/g, \"''\");\n const skip = [...before].join(\",\") || \"-1\";\n /* The spooler creates the job around the time the handle closes, so\n * give it a moment to appear before looking, and a moment to act on\n * the delete before returning -- a job caught mid-print lingers in\n * \"Deleting\" otherwise. */\n await runScriptOrThrow(`\n$ErrorActionPreference = 'SilentlyContinue'\n$before = @(${skip})\nStart-Sleep -Milliseconds 900\nGet-PrintJob -PrinterName '${name}' | Where-Object { $_.Id -notin $before } |\n ForEach-Object { Remove-PrintJob -PrinterName '${name}' -ID $_.Id }\nStart-Sleep -Milliseconds 600\n`);\n } catch { /* cosmetic cleanup; never fail a print over it */ }\n}\n\n/**\n * Refuse `-queue` when the printer's Windows queue points at a discard port.\n *\n * Repointing a queue away from the printer's real port is how we stop the\n * spooler from creating a phantom job every time we open that port. The cost\n * is that the queue no longer goes anywhere, so `-queue` must fail loudly\n * rather than cheerfully reporting a label that was never printed.\n */\nasync function refuseDiscardQueue(printerName: string): Promise<void> {\n const name = printerName || getDefaultPrinter();\n if (!name) return;\n const { listPrinters: coreListPrinters } = await import(\"@bobfrankston/label-core\");\n const info = (await coreListPrinters(/brother|^pt-|^ql-/i)).find(p => p.name === name);\n const portName = (info?.portName ?? \"\").replace(/:$/, \"\");\n if (!DISCARD_PORTS.test(portName)) return;\n throw new UserError(\n `${name}'s Windows queue points at \"${info.portName}\", which discards everything sent to it — ` +\n `-queue would report success and print nothing. Drop -queue to print directly, ` +\n `or repoint the queue at the printer's port with: Set-Printer -Name \"${name}\" -PortName \"COMn:\"`\n );\n}\n\n/**\n * Find the serial port to write a P-touch label to.\n *\n * The printer queue's PortName is the obvious source but it goes stale:\n * Windows reassigns a Bluetooth printer's outgoing COM number when it\n * re-pairs (the PT-D610BT here was installed on COM8 and came back on COM10),\n * and the queue keeps pointing at the old one. Worse, the abandoned number is\n * often still a valid *incoming* Bluetooth port with nothing behind it, so the\n * stale queue looks openable and simply swallows the job.\n *\n * So: ask Bluetooth which port actually belongs to this printer, and fall back\n * to the queue's port only when no Bluetooth match exists (a genuinely wired\n * serial printer). Returns null when neither yields a COM port.\n */\nasync function resolvePtPort(printerName: string): Promise<{ port: string; source: string }> {\n const { listPrinters: coreListPrinters, runScriptOrThrow } =\n await import(\"@bobfrankston/label-core\");\n\n /* Bluetooth SPP ports carry the remote device's address in their instance\n * id; BTHPORT maps that address to the advertised device name, which\n * contains the model (e.g. \"PT-D610BT5465\"). Match on the model token. */\n const model = /PT-([A-Z0-9]+)/i.exec(printerName)?.[1];\n if (model) {\n const script = [\n \"$ErrorActionPreference = 'SilentlyContinue'\",\n \"Get-PnpDevice -Class Ports -PresentOnly | Where-Object { $_.FriendlyName -match 'Bluetooth' } | ForEach-Object {\",\n \" if ($_.InstanceId -match '&0&([0-9A-Fa-f]{12})_') {\",\n \" $addr = $matches[1].ToLower()\",\n \" $raw = (Get-ItemProperty \\\"HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Services\\\\BTHPORT\\\\Parameters\\\\Devices\\\\$addr\\\").Name\",\n \" if ($raw -and $_.FriendlyName -match '\\\\((COM\\\\d+)\\\\)') {\",\n \" $com = $matches[1]\",\n \" $name = [System.Text.Encoding]::ASCII.GetString($raw).Trim([char]0)\",\n \" Write-Output \\\"$com=$name\\\"\",\n \" }\",\n \" }\",\n \"}\",\n ].join(\"\\n\");\n try {\n const out = (await runScriptOrThrow(script)).trim();\n for (const line of out.split(/\\r?\\n/)) {\n const eq = line.indexOf(\"=\");\n if (eq < 0) continue;\n const com = line.slice(0, eq).trim();\n const name = line.slice(eq + 1).trim();\n const squashed = name.replace(/[^A-Za-z0-9]/g, \"\").toUpperCase();\n if (com && squashed.includes(model.toUpperCase())) {\n return { port: com, source: `Bluetooth device ${name}` };\n }\n }\n } catch { /* fall through to the queue's port */ }\n }\n\n const info = (await coreListPrinters(/brother|^pt-/i)).find(p => p.name === printerName);\n const m = /^(COM\\d+):?$/i.exec(info?.portName ?? \"\");\n if (m) return { port: m[1], source: `printer queue port ${info.portName}` };\n return null;\n}\n\nfunction classifyInput(input: string, opts: Record<string, string | boolean>): Partial<CorePrintOptions> {\n if (opts.text) return { text: input };\n if (opts.html) return { htmlPath: path.resolve(input) };\n if (opts.image) return { imagePath: path.resolve(input) };\n\n const lower = input.toLowerCase();\n if (lower.endsWith(\".html\") || lower.endsWith(\".htm\")) return { htmlPath: path.resolve(input) };\n if (lower.endsWith(\".txt\")) return { textFile: path.resolve(input) };\n if (/\\.(png|jpg|jpeg|bmp|gif)$/i.test(lower)) return { imagePath: path.resolve(input) };\n if (fs.existsSync(input)) {\n const ext = path.extname(lower);\n if (ext === \".html\" || ext === \".htm\") return { htmlPath: path.resolve(input) };\n return { textFile: path.resolve(input) };\n }\n return { text: input };\n}\n\nfunction makeWaitCallback() {\n let lastReport = -Infinity;\n return (status: PrinterStatus, elapsedMs: number) => {\n const secs = Math.floor(elapsedMs / 1000);\n // Non-TTY (redirected output) can't rewrite in place; report sparsely.\n if (!process.stderr.isTTY) {\n if (secs - lastReport < 30) return;\n lastReport = secs;\n }\n statusLine.update(`[brother-print] waiting for ${status.name} (${status.statusText}${status.error ? \", \" + status.error : \"\"}); ${secs}s`);\n };\n}\n\nmain();\n"]}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,WAAW,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,EACH,sBAAsB,EACtB,SAAS,GACZ,MAAM,0BAA0B,CAAC;AAQlC,OAAO,EACH,KAAK,EACL,MAAM,EACN,cAAc,EACd,aAAa,EACb,SAAS,EACT,SAAS,EACT,aAAa,EACb,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,cAAc,GACjB,MAAM,UAAU,CAAC;AAGlB;;;kCAGkC;AAClC,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AACpC,MAAM,WAAW,GAAe,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAEnD,SAAS,SAAS,CAAC,KAAa;IAC5B,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAa,CAAC;IAC9D,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,SAAS,CAAC,sBAAsB,KAAK,YAAY,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,MAAM,MAAM,GAAuB;IAC/B,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,EAAiB,GAAG,EAAE,MAAM,EAAE;IAChD,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,EAAQ,GAAG,EAAE,SAAS,EAAE;IACnD,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAc,GAAG,EAAE,YAAY,EAAE;IACtD,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,EAAS,GAAG,EAAE,QAAQ,EAAE;IAClD,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,EAAS,GAAG,EAAE,QAAQ,EAAE;IAClD,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,EAAQ,GAAG,EAAE,QAAQ,EAAE;IAClD,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAU,GAAG,EAAE,OAAO,EAAE;IACjD,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAc,GAAG,EAAE,SAAS,EAAE;IACnD,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAa,GAAG,EAAE,UAAU,EAAE;IACpD,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAmB,GAAG,EAAE,IAAI,EAAE;IAC9C,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAa,GAAG,EAAE,SAAS,EAAE;IACnD,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,EAAiB,GAAG,EAAE,MAAM,EAAE;CACnD,CAAC;AAEF,MAAM,OAAO,GAAsB;IAC/B,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAW,GAAG,EAAE,MAAM,EAAE;IAChD,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAU,GAAG,EAAE,OAAO,EAAE;IACjD,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAoB,GAAG,EAAE,MAAM,EAAE;IAChD,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAW,GAAG,EAAE,MAAM,EAAE;IAChD,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,EAAG,GAAG,EAAE,QAAQ,EAAE;IAClD,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,EAAiB,GAAG,EAAE,MAAM,EAAE;IAChD,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,EAAO,GAAG,EAAE,SAAS,EAAE;IACnD,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAgB,GAAG,EAAE,OAAO,EAAE;IACjD,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAK,GAAG,EAAE,OAAO,EAAE;IACjD,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAK,GAAG,EAAE,MAAM,EAAE;IAChD,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,EAAQ,GAAG,EAAE,SAAS,EAAE;CACtD,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAEjD,SAAS,QAAQ;IACb,OAAO,CAAC,GAAG,CAAC,8BAA8B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCA8CjB,CAAC,CAAC;AACtC,CAAC;AAED,0EAA0E;AAC1E,MAAM,SAAU,SAAQ,KAAK;IAChB,WAAW,GAAG,IAAI,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,UAAU,GAAG;IACf,MAAM,EAAE,KAAK;IACb,MAAM,CAAC,GAAW;QACd,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;YACxC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACvB,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;IACL,CAAC;IACD,KAAK;QACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACxB,CAAC;IACL,CAAC;CACJ,CAAC;AAEF,8DAA8D;AAC9D,SAAS,KAAK,CAAC,GAAW;IACtB,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,KAAK,UAAU,IAAI;IACf,MAAM,IAAI,GAAG,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACD,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAC3D,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,sBAAsB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED;;uDAEmD;IACnD,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,gCAAgC,CAAC,CAAC;QACzE,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,iCAAiC,CAAC,GAAG,CAAC,CAAC;QAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAAC,QAAQ,EAAE,CAAC;QAAC,OAAO;IAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAE1D,IAAI,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAChE;;mFAEuE;YACvE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACtD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACtD,IAAI,IAAI;oBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;YACpC,CAAC;QACL,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YAC7C,MAAM,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC5C,OAAO;QACX,CAAC;QACD,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC;YACrB,KAAK,MAAM;gBAAI,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAAC,OAAO;YAClD,KAAK,QAAQ;gBAAE,MAAM,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAAC,OAAO;YACpD,KAAK,QAAQ;gBAAE,MAAM,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAAC,OAAO;QACxD,CAAC;QACD,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QACd,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB;mCAC2B;QAC3B,IAAI,CAAC,EAAE,WAAW,IAAI,8CAA8C,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1F,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QACD,WAAW,CAAC,CAAC,CAAC,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC7B,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAAC,WAAmB;IAC5C,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GACtD,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IACnD,IAAI,CAAC,IAAI,EAAE,QAAQ;QAAE,OAAO,SAAS,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG;;8BAEW,IAAI;;CAEjC,CAAC;IACE,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACpD,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,OAAO,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,KAAK,UAAU,cAAc,CAAC,IAAY;IACtC,IAAI,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,IAAI,CAAC;QACD,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;QAChE,IAAI,YAAY,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACjE,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,MAAM,EAAE,CAAC;YACtC,IAAI,CAAC;gBACD,MAAM,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC5B,OAAO,SAAS,CAAC;YACrB,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACd,CAAC;IACL,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC;IAC7D,IAAI,CAAC;QACD,MAAM,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3B,OAAO,QAAQ,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,IAAI,CAAC;QACD,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;YAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACtD,OAAO,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,GAAG,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;QACH,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,IAAI,cAAoC,CAAC;AACzC;;;;;GAKG;AACH,KAAK,UAAU,cAAc;IACzB,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAC1C,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG;;;;;;;CAOlB,CAAC;IACE,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC3C,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACL,cAAc,GAAG,EAAE,CAAC;IACxB,CAAC;IACD,OAAO,cAAc,CAAC;AAC1B,CAAC;AAGD;;;GAGG;AACH;;;;;GAKG;AACH,SAAS,WAAW,CAAC,CAAM;IACvB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAC3C,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrD,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5C,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,GAAG,EAAE,CAAC;QACT,MAAM,MAAM,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC;QACnD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,GAAG,EAAE,CAAC,CAAC;QAC9C,IAAI,GAAG,CAAC,IAAI;YAAG,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,GAAG,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QACnD,IAAI,GAAG,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC;QAChB,KAAK,EAAE,CAAC;QACR,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;YAAC,MAAM;QAAC,CAAC;IACpF,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,uBAAuB,IAAI,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IAChG,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,CAAC;QAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAAC,SAAS,GAAG,IAAI,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAEpF,IAAI,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACnE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;AACL,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,IAAsC;IACzD,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC;;+BAE2B;IAC3B,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IACpF,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAElD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAClD,CAAC;SAAM,CAAC;QACJ,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CAAC,qBAAqB,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;QACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,SAAS,GAAG,GAAG,CAAC;YACpB,IAAI,YAAY,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC;gBACD,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACjD,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;gBAC9F,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC;YAClC,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBACd,SAAS,GAAG,iBAAiB,CAAC,CAAC,OAAO,EAAE,CAAC;YAC7C,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;YAC7D,MAAM,MAAM,GAAG,IAAI,EAAE,UAAU,IAAI,WAAW,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACtC,IAAI,IAAI,EAAE,OAAO;gBAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACxE,IAAI,IAAI,EAAE,QAAQ;gBAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACzE,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;YAC5C,IAAI,IAAI,EAAE,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAC3C,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,EAAE,CAAC,CAAC;YAC9C,IAAI,IAAI,EAAE,SAAS,IAAI,IAAI,CAAC,SAAS,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC/C,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAC1D,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,wBAAwB,SAAS,EAAE,CAAC,CAAC;YACjD,IAAI,YAAY;gBAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAC;QAC1E,CAAC;IACL,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,MAAM,EAAE,mBAAmB,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,EAAE,GACxE,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,CAAC,MAAM,mBAAmB,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC9D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;YACvD,OAAO;QACX,CAAC;QACD,MAAM,cAAc,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/F,MAAM,OAAO,GAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QAE/F,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,aAAa,WAAW,CAAC,MAAM,iBAAiB,CAAC,CAAC;QACjH,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC;YAC3C,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,cAAc,CAAC;YAC3D,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,iBAAiB,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY,GAAG,GAAG,EAAE,CAAC,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;YACrE,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,QAAgB;IACjC,IAAI,CAAC,QAAQ;QAAE,OAAO,WAAW,CAAC;IAClC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACpD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAChG,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACnC,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,cAAc,CAAC,WAAmB,EAAE,MAA0B;IACzE,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IACpF,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IAEnD,OAAO,CAAC,GAAG,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAC;IAC3C,IAAI,IAAI,EAAE,QAAQ,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACtD,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QACpG,OAAO,CAAC,GAAG,CAAC,gBAAgB,SAAS,EAAE,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,WAAW,SAAS,CAAC,CAAC;QACpD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY,QAAQ,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7G,CAAC;QACD,IAAI,CAAC,CAAC,YAAY;YAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;QAChD,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,IAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,wBAAwB,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,8CAA8C,EAAE,CAAC,CAAC;QAC7H,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,sBAAsB,4BAA4B,CAAC,CAAC;QAC/I,CAAC;IACL,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,aAAa,CAAC,CAAC;QACjD,MAAM,EAAE,wBAAwB,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,MAAM,wBAAwB,CAAC,WAAW,CAAC,CAAC;QAC1D,IAAI,KAAK,EAAE,CAAC;YACR,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,IAAI,QAAQ,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC;YAC1I,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,CAAC,aAAa,QAAQ,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,oBAAoB,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxJ,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;QACzF,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,sCAAsC,CAAC;QAC1G,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC/F,CAAC;AACL,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAsC;IAC3D,MAAM,IAAI,GAAI,IAAI,CAAC,OAAkB,IAAI,SAAS,CAAC;IACnD,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,CAAC,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,WAAW,SAAS,CAAC,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY,QAAQ,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,IAAI,CAAC,CAAC,YAAY;QAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;IAChE,IAAI,CAAC,CAAC,WAAW;QAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,aAAa,CAAC,KAAa;IACtC,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;IACzC,SAAS,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,gBAAgB,aAAa,EAAE,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAsC;IAC3D,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,sBAAsB,aAAa,EAAE,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QAC5F,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,CAAC,cAAc,IAAI,WAAW,EAAE,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO;IACX,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;QACzC,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,gEAAgE;QAChE,SAAS,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,OAAiB,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3D,CAAC;AACL,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAsC;IAC7D;qEACiE;IACjE,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,OAA6B,CAAC,CAAC;IACtE,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAC;IACnC,OAAO,SAAS,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,KAAK,UAAU,QAAQ,CACnB,IAAsC,EACtC,QAAmB,EACnB,MAAgB;IAEhB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;IAErC,mEAAmE;IACnE,0EAA0E;IAC1E,2BAA2B;IAC3B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QACnE,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,MAAM,QAAQ,GAAG;QACb,OAAO,EAAE,IAAI,CAAC,OAA6B;QAC3C,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM;QAClB,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,OAAiB,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAC/F,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,QAAkB,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAClG,SAAS,EAAE,gBAAgB,EAAE;QAC7B,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;KACnC,CAAC;IAEF,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE5F,kFAAkF;IAClF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QACxE,MAAM,OAAO,GAAmB;YAC5B,GAAG,QAAQ;YACX,IAAI;YACJ,UAAU,EAAE,IAAI,CAAC,MAA4B;YAC7C,KAAK,EAAE,IAAI,CAAC,KAA2B;SAC1C,CAAC;QACF,IAAI,aAAqB,CAAC;QAC1B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,MAA4B,EAAE,IAAI,CAAC,KAA2B,CAAC,CAAC;YACzH,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,MAAgB,EAAE,MAAM,CAAC,CAAC;YAChD,KAAK,CAAC,YAAY,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,MAAM,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,MAA4B,EAAE,IAAI,CAAC,KAA2B,CAAC,CAAC;YACzH,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YACjD,MAAM,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,OAA6B,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClG,KAAK,CAAC,WAAW,QAAQ,CAAC,MAAM,kBAAmB,IAAI,CAAC,OAAkB,IAAI,IAAI,MAAM,MAAM,KAAK,IAAI,sBAAsB,CAAC,CAAC;QACnI,CAAC;aAAM,IAAI,aAAa,GAAG,MAAM,cAAc,CAC3C,MAAM,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,MAA4B,EAAE,IAAI,CAAC,KAA2B,CAAC,EACzG,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACd,aAAa,CAAC,GAAG,QAAQ,CAAC,MAAM,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,mBAAmB,CAAC,CAAC;QACpG,CAAC;aAAM,CAAC;YACJ,MAAM,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACvC,aAAa,CAAC,GAAG,QAAQ,CAAC,MAAM,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACtE,CAAC;QACD,OAAO;IACX,CAAC;IAED,oBAAoB;IACpB,MAAM,SAAS,GAAiB;QAC5B,GAAG,QAAQ;QACX,IAAI;QACJ,MAAM,EAAE,IAAI,CAAC,MAA4B;QACzC,UAAU,EAAE,IAAI,CAAC,MAA4B;KAChD,CAAC;IAEF,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC;IAC1B,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,cAAc,CAAC,IAAI,CAAC,OAAiB,EAAE,MAAM,CAAC,CAAC;YACrD,OAAO;QACX,CAAC;QACD,QAAQ,EAAE,CAAC;QACX,OAAO;IACX,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QACvC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,MAAgB,EAAE,MAAM,CAAC,CAAC;QAChD,KAAK,CAAC,YAAY,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACjC,OAAO;IACX,CAAC;IACD,IAAI,MAAM,EAAE,CAAC;QACT,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,OAA6B,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClG,KAAK,CAAC,cAAe,IAAI,CAAC,OAAkB,IAAI,IAAI,MAAM,MAAM,oBAAoB,CAAC,CAAC;QACtF,OAAO;IACX,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7E,MAAM,eAAe,GAAG,mBAAmB,CAAC;IAC5C,IAAI,UAAU,EAAE,CAAC;QACb,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;QAC3D,OAAO;IACX,CAAC;IACD,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;IACvB,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,cAAc,CAAC,IAAsC,EAAE,IAAc,EAAE,IAAY;IACxF,MAAM,OAAO,GAAI,IAAI,CAAC,OAAkB,IAAI,iBAAiB,EAAE,CAAC;IAChE,OAAO,IAAI;QACP,CAAC,CAAC,GAAG,OAAO,KAAK,IAAI,sBAAsB,IAAI,GAAG;QAClD,CAAC,CAAC,GAAG,OAAO,KAAK,IAAI,SAAS,CAAC;AACvC,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAClB,IAAY,EACZ,IAAsC,EACtC,IAAc,EACd,IAAY,EACZ,SAAmB;IAEnB,IAAI,IAAY,CAAC;IACjB,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,IAAI,GAAG,QAAQ,CAAC;QAChB,IAAI,GAAG,8DAA8D,CAAC;IAC1E,CAAC;SAAM,IAAI,SAAS,EAAE,CAAC;QACnB,IAAI,GAAG,SAAS,CAAC;QACjB,IAAI,GAAG,EAAE,CAAC;IACd,CAAC;SAAM,CAAC;QACJ;;;qEAG6D;QAC7D,IAAI,GAAG,MAAM,CAAC;QACd,IAAI,GAAG,sDAAsD,CAAC;IAClE,CAAC;IACD,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,MAAM,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,cAAc,CACzB,GAAW,EACX,IAAsC,EACtC,IAAc;IAEd,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACb;;;0DAGkD;QAClD,MAAM,kBAAkB,CAAC,IAAI,CAAC,OAAiB,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IAChB,CAAC;IACD;qDACiD;IACjD,MAAM,WAAW,GAAI,IAAI,CAAC,OAAkB,IAAI,iBAAiB,EAAE,CAAC;IACpE,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAE9B,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,IAAI,GAAI,IAAI,CAAC,IAAe,IAAI,CAAC,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC;IAC/E,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,mBAAmB,GAAG,KAAK,CAAC,aAAa,CAAC;IAC1C,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;IACjD,IAAI,CAAC;QACD,MAAM,aAAa,CAAC,GAAG,EAAE;YACrB,IAAI;YACJ,WAAW;YACX,IAAI;YACJ,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK;YACpB,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;SAC1D,CAAC,CAAC;IACP,CAAC;YAAS,CAAC;QACP;;mCAE2B;QAC3B,MAAM,gBAAgB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,IAAI,mBAAmB,GAAG,KAAK,CAAC;AAEhC,0DAA0D;AAC1D,MAAM,aAAa,GAAG,0BAA0B,CAAC;AAEjD;;;GAGG;AACH,KAAK,UAAU,UAAU,CAAC,WAAmB;IACzC,IAAI,CAAC;QACD,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;QACtE,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAC9B,gCAAgC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,+CAA+C,CACjH,CAAC;QACF,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,GAAG,EAAE,CAAC;IACrB,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,KAAK,UAAU,gBAAgB,CAAC,WAAmB,EAAE,MAAmB;IACpE,IAAI,CAAC;QACD,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;QACtE,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;QAC3C;;;mCAG2B;QAC3B,MAAM,gBAAgB,CAAC;;cAEjB,IAAI;;6BAEW,IAAI;qDACoB,IAAI;;CAExD,CAAC,CAAC;IACC,CAAC;IAAC,MAAM,CAAC,CAAC,kDAAkD,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,kBAAkB,CAAC,WAAmB;IACjD,MAAM,IAAI,GAAG,WAAW,IAAI,iBAAiB,EAAE,CAAC;IAChD,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IACpF,MAAM,IAAI,GAAG,CAAC,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACvF,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO;IAC1C,MAAM,IAAI,SAAS,CACf,GAAG,IAAI,+BAA+B,IAAI,CAAC,QAAQ,4CAA4C;QAC/F,gFAAgF;QAChF,uEAAuE,IAAI,qBAAqB,CACnG,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,aAAa,CAAC,WAAmB;IAC5C,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GACtD,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAE7C;;8EAE0E;IAC1E,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvD,IAAI,KAAK,EAAE,CAAC;QACR,MAAM,MAAM,GAAG;YACX,6CAA6C;YAC7C,kHAAkH;YAClH,yDAAyD;YACzD,uCAAuC;YACvC,4HAA4H;YAC5H,mEAAmE;YACnE,gCAAgC;YAChC,iFAAiF;YACjF,yCAAyC;YACzC,WAAW;YACX,OAAO;YACP,GAAG;SACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACb,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,CAAC,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACpD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC7B,IAAI,EAAE,GAAG,CAAC;oBAAE,SAAS;gBACrB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;gBACjE,IAAI,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;oBAChD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,oBAAoB,IAAI,EAAE,EAAE,CAAC;gBAC7D,CAAC;YACL,CAAC;QACL,CAAC;QAAC,MAAM,CAAC,CAAC,sCAAsC,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IACzF,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;IACrD,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,sBAAsB,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;IAC5E,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,KAAa,EAAE,IAAsC;IACxE,IAAI,IAAI,CAAC,IAAI;QAAG,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACvC,IAAI,IAAI,CAAC,IAAI;QAAG,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IACzD,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IAE1D,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IAChG,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAG,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IACtE,IAAI,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAW,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IACjG,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,MAAM;YAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChF,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,gBAAgB;IACrB,IAAI,UAAU,GAAG,CAAC,QAAQ,CAAC;IAC3B,OAAO,CAAC,MAAqB,EAAE,SAAiB,EAAE,EAAE;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;QAC1C,uEAAuE;QACvE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,IAAI,GAAG,UAAU,GAAG,EAAE;gBAAE,OAAO;YACnC,UAAU,GAAG,IAAI,CAAC;QACtB,CAAC;QACD,UAAU,CAAC,MAAM,CAAC,+BAA+B,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,GAAG,CAAC,CAAC;IAC/I,CAAC,CAAC;AACN,CAAC;AAED,IAAI,EAAE,CAAC","sourcesContent":["#!/usr/bin/env node\n/**\n * Brother Label Printer CLI\n * Thin wrapper around api.ts using shared CLI primitives from label-core.\n */\n\nimport * as fs from \"fs\";\nimport packageJson from \"./package.json\" with { type: \"json\" };\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport * as dns from \"dns/promises\";\nimport {\n preprocessSingleQuotes,\n parseArgs,\n} from \"@bobfrankston/label-core\";\nimport type {\n PrintOptions as CorePrintOptions,\n PrinterStatus,\n Segment,\n ValuedOptionSpec,\n BooleanFlagSpec,\n} from \"@bobfrankston/label-core\";\nimport {\n print,\n render,\n renderSegments,\n printSegments,\n getConfig,\n setConfig,\n getConfigPath,\n listPrinters,\n resolvePrinter,\n getDefaultPrinter,\n detectTape,\n brotherPrinter,\n} from \"./api.js\";\nimport type { TapeSize, PrintOptions, SegmentOptions } from \"./api.js\";\n\n/* Claude Code 2026-09-01: was a hardcoded \"1.1.0\", 23 patch releases stale by\n * the time anyone noticed -- `-version` and `-help` both reported a number that\n * was not the one installed. Read it from the package instead; there is exactly\n * one place a version belongs. */\nconst VERSION = packageJson.version;\nconst VALID_TAPES: TapeSize[] = [6, 9, 12, 18, 24];\n\nfunction parseTape(value: string): TapeSize {\n const num = parseInt(value.replace(\"mm\", \"\"), 10) as TapeSize;\n if (!VALID_TAPES.includes(num)) {\n throw new UserError(`Invalid tape size: ${value}. Valid: ${VALID_TAPES.join(\", \")}`);\n }\n return num;\n}\n\nconst VALUED: ValuedOptionSpec[] = [\n { names: [\"-tape\"], key: \"tape\" },\n { names: [\"-p\", \"-printer\"], key: \"printer\" },\n { names: [\"-default\"], key: \"setDefault\" },\n { names: [\"-o\", \"-output\"], key: \"output\" },\n { names: [\"-a\", \"-aspect\"], key: \"aspect\" },\n { names: [\"-ht\", \"-height\"], key: \"height\" },\n { names: [\"-s\", \"-space\"], key: \"space\" },\n { names: [\"-timeout\"], key: \"timeout\" },\n { names: [\"-interval\"], key: \"interval\" },\n { names: [\"-ql\"], key: \"ql\" },\n { names: [\"-ql-media\"], key: \"qlMedia\" },\n { names: [\"-port\"], key: \"port\" },\n];\n\nconst BOOLEAN: BooleanFlagSpec[] = [\n { names: [\"-w\", \"-html\"], key: \"html\" },\n { names: [\"-i\", \"-image\"], key: \"image\" },\n { names: [\"-t\"], key: \"text\" },\n { names: [\"-c\", \"-clip\"], key: \"clip\" },\n { names: [\"-no-wait\", \"-nowait\"], key: \"nowait\" },\n { names: [\"-mdns\"], key: \"mdns\" },\n { names: [\"-vb\", \"-verbose\"], key: \"verbose\" },\n { names: [\"-queue\"], key: \"queue\" },\n { names: [\"-no-cut\", \"-nocut\"], key: \"nocut\" },\n { names: [\"-help\", \"-h\", \"-?\"], key: \"help\" },\n { names: [\"-version\", \"-v\"], key: \"version\" },\n];\n\nconst SUBCOMMANDS = [\"list\", \"status\", \"config\"];\n\nfunction showHelp(): void {\n console.log(`Brother Label Printer CLI v${VERSION}\n\nUsage:\n brother-print [options] <text> Print text\n brother-print [options] <file> Print html/txt/image file (auto-detected)\n brother-print -clip [options] Print clipboard contents (image or text)\n brother-print -text <v> -qr <v> ... Print ordered text/qr segments\n brother-print -list [-mdns] List Brother printers and status\n (-mdns also discovers network printers)\n brother-print -status [-p <name>] Show printer status\n brother-print -config Show / set defaults\n\nCommands take a leading dash so they can never be confused with label content:\na bare word is always something to print, a dashed word is always a command.\n\nTape size is auto-detected from the printer. Use -tape to override.\nSingle quotes can wrap arguments: '7\"' 'line1\\\\nline2'\n\nOptions:\n -tape <size> Tape size: 6, 9, 12, 18, 24 (mm) [auto-detected]\n -p, -printer <name> Printer queue name\n -default <name> Set the default printer (used when -p is omitted)\n -o, -output <file> Save PNG to file instead of printing\n -a, -aspect <r> Aspect ratio width:height for HTML (e.g. 3.5:2)\n -ht, -height <size> Text height: 12mm, .5in, or 50% (of tape height)\n -s, -space <size> Space between segments: 12px, 1mm, .2in\n -t, -text Force input as literal text (-text <v> for segments)\n -qr <data> QR code segment\n -w, -html Force input as HTML file path\n -i, -image Force input as image file path\n -c, -clip Read content from clipboard (image preferred, then text)\n -no-wait Fail immediately if printer is offline (default: wait)\n -timeout <secs> Max wait time when printer is offline\n -interval <secs> Polling interval while waiting (default 2)\n -mdns With -list: also discover network printers via mDNS\n -ql <host> Print to a Brother QL series printer over TCP/9100\n (bypasses Windows queue; e.g. -ql ql720 or -ql 1.2.3.4)\n -ql-media <id> QL media id (e.g. 271=DK-11201 29×90mm, 259=DK-22205 62mm)\n Required when the printer doesn't respond to status\n -queue Print through the Windows spooler (XPS) instead of\n writing raster bytes straight to the printer's port\n -port <COMn> Serial/Bluetooth port for direct printing (overrides\n the port looked up from the printer queue)\n -no-cut Do not cut the tape after the label (direct path only)\n -vb, -verbose Print extra QL diagnostic messages (status, media source)\n -help Show this help\n -version Show version`);\n}\n\n/** Expected user-facing error: prints one line, no log file, no stack. */\nclass UserError extends Error {\n readonly isUserError = true;\n}\n\n/**\n * Single-line status display: on a TTY the line is rewritten in place\n * (CR + erase-line) instead of scrolling; callers must clear() before any\n * normal output so it doesn't collide with the pending status line.\n */\nconst statusLine = {\n active: false,\n update(msg: string): void {\n if (process.stderr.isTTY) {\n process.stderr.write(`\\r\\x1b[2K${msg}`);\n this.active = true;\n } else {\n console.error(msg);\n }\n },\n clear(): void {\n if (this.active) {\n process.stderr.write(`\\r\\x1b[2K`);\n this.active = false;\n }\n },\n};\n\n/** console.log that first clears any in-place status line. */\nfunction outln(msg: string): void {\n statusLine.clear();\n console.log(msg);\n}\n\nasync function main(): Promise<void> {\n const argv = preprocessSingleQuotes(process.argv.slice(2));\n let parsed;\n try {\n parsed = parseArgs(argv, VALUED, BOOLEAN, SUBCOMMANDS);\n } catch (e: any) {\n console.error(`Error: ${e.message}`);\n process.exit(1);\n }\n\n if (parsed.unknown.length > 0) {\n console.error(`Unknown option(s): ${parsed.unknown.join(\", \")}`);\n console.error(`Run \"brother-print -help\" for usage.`);\n process.exit(1);\n }\n\n /* Bare `list` used to be the command syntax; it is now `-list`. Refusing\n * beats guessing: printing a label that says \"list\" and listing printers\n * are both plausible readings of the same word. */\n if (parsed.ambiguous.length > 0) {\n const w = parsed.ambiguous[0];\n console.error(`Ambiguous argument: \"${w}\" -- commands now take a dash.`);\n console.error(` brother-print -${w} run the ${w} command`);\n console.error(` brother-print -text ${w} print a label that says \"${w}\"`);\n process.exit(1);\n }\n\n if (parsed.opts.help) { showHelp(); return; }\n if (parsed.opts.version) { console.log(VERSION); return; }\n\n try {\n if (typeof parsed.opts.printer === \"string\") {\n parsed.opts.printer = await resolvePrinter(parsed.opts.printer);\n /* Auto-route QL series through the QL TCP path. The XPS / CustomMediaSize\n * pipeline is P-touch-only; sending it to a QL queue produces an XPS\n * error. If the user already passed -ql explicitly, leave it alone. */\n if (!parsed.opts.ql && isQLPrinter(parsed.opts.printer)) {\n const host = await resolveQLHost(parsed.opts.printer);\n if (host) parsed.opts.ql = host;\n }\n }\n if (typeof parsed.opts.setDefault === \"string\") {\n await cmdSetDefault(parsed.opts.setDefault);\n return;\n }\n switch (parsed.command) {\n case \"list\": await cmdList(parsed.opts); return;\n case \"status\": await cmdStatus(parsed.opts); return;\n case \"config\": await cmdConfig(parsed.opts); return;\n }\n await cmdPrint(parsed.opts, parsed.segments, parsed.inputs);\n } catch (e: any) {\n statusLine.clear();\n /* Timeout/offline are expected conditions, not crashes — one line,\n * no error-report file. */\n if (e?.isUserError || /^Timed out waiting for printer|is offline \\(/.test(e?.message ?? \"\")) {\n console.error(`Error: ${e.message}`);\n process.exit(1);\n }\n reportError(e);\n process.exit(1);\n }\n}\n\nfunction isQLPrinter(name: string): boolean {\n return /\\bQL-/i.test(name);\n}\n\n/**\n * Look up the TCP host for a QL printer's installed Windows queue. Pulls the\n * port name via label-core, then asks PowerShell for that port's\n * PrinterHostAddress. Returns undefined if the port isn't a TCP/IP port (e.g.\n * the QL-820NWB's BRWxxxx Bluetooth port has no host address).\n */\nasync function resolveQLHost(printerName: string): Promise<string | undefined> {\n const { listPrinters: coreListPrinters, runScriptOrThrow } =\n await import(\"@bobfrankston/label-core\");\n const all = await coreListPrinters(/brother|^pt-|^ql-/i);\n const info = all.find(p => p.name === printerName);\n if (!info?.portName) return undefined;\n const port = info.portName.replace(/'/g, \"''\");\n const script = `\n$ErrorActionPreference = 'SilentlyContinue'\n$p = Get-PrinterPort -Name '${port}'\nif ($p -and $p.PrinterHostAddress) { Write-Output $p.PrinterHostAddress }\n`;\n try {\n const out = (await runScriptOrThrow(script)).trim();\n if (!out) return undefined;\n return await resolvableHost(out);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Brother's installer often writes a bare NetBIOS-style hostname (BRWxxxx)\n * as the port's PrinterHostAddress, which won't resolve in environments where\n * the DNS suffix isn't auto-appended. Resolution tiers, in order:\n * 1. as-is via the OS resolver\n * 2. <host>.<suffix> for every DNS suffix the OS knows about (global search\n * list, per-connection suffix, computer domain) — covers the case where\n * the user pings as FQDN manually because Windows isn't auto-appending\n * 3. <host>.local via the OS resolver (Windows 10 1803+ native mDNS)\n * 4. multicast mDNS query directly (bypasses OS resolver — works even when\n * Windows .local resolution is disabled, common in AD/domain environments)\n */\nasync function resolvableHost(host: string): Promise<string> {\n if (/^\\d{1,3}(\\.\\d{1,3}){3}$/.test(host)) return host;\n try {\n await dns.lookup(host);\n return host;\n } catch {}\n if (!host.includes(\".\")) {\n const suffixes = await getDnsSuffixes();\n const { default_fqdn } = await import(\"@bobfrankston/miscinfo\");\n if (default_fqdn && !suffixes.includes(default_fqdn.toLowerCase())) {\n suffixes.push(default_fqdn.toLowerCase());\n }\n for (const suffix of suffixes) {\n const candidate = `${host}.${suffix}`;\n try {\n await dns.lookup(candidate);\n return candidate;\n } catch {}\n }\n }\n const mdnsName = host.includes(\".\") ? host : host + \".local\";\n try {\n await dns.lookup(mdnsName);\n return mdnsName;\n } catch {}\n try {\n const { discoverPdlPrinters } = await import(\"./mdns.js\");\n const printers = await discoverPdlPrinters(2500);\n const target = host.toLowerCase();\n const hit = printers.find(p => {\n const h = p.hostname.toLowerCase().replace(/\\.$/, \"\");\n return h === target || h === target + \".local\" || h.startsWith(target + \".\");\n });\n if (hit && hit.addresses.length > 0) return hit.addresses[0];\n } catch {}\n return host;\n}\n\nlet dnsSuffixCache: string[] | undefined;\n/**\n * Read every DNS suffix the system knows about: the global SuffixSearchList,\n * each adapter's ConnectionSpecificSuffix, and the computer's AD/workgroup\n * domain. Cached per-process. Returns lowercased, de-duplicated, in priority\n * order (search list first since that's what the user explicitly configured).\n */\nasync function getDnsSuffixes(): Promise<string[]> {\n if (dnsSuffixCache) return dnsSuffixCache;\n const { runScriptOrThrow } = await import(\"@bobfrankston/label-core\");\n const script = `\n$ErrorActionPreference = 'SilentlyContinue'\n$out = @()\n$out += (Get-DnsClientGlobalSetting).SuffixSearchList\n$out += Get-DnsClient | Select-Object -ExpandProperty ConnectionSpecificSuffix\n$out += (Get-CimInstance Win32_ComputerSystem).Domain\n$out | Where-Object { $_ -and $_ -ne 'WORKGROUP' } | ForEach-Object { $_.ToLower() } | Select-Object -Unique\n`;\n try {\n const out = await runScriptOrThrow(script);\n dnsSuffixCache = out.split(/\\r?\\n/).map(s => s.trim()).filter(Boolean);\n } catch {\n dnsSuffixCache = [];\n }\n return dnsSuffixCache;\n}\n\n\n/**\n * Print an error with full context: message, cause chain (Node's fetch and\n * other newer APIs put the actual cause in error.cause), and stack on -v.\n */\n/**\n * Report an error: print a one-line summary to stderr and write the full\n * cause-chain (with stacks, codes, paths) to a temp file. Avoids dumping\n * walls of error text into the user's terminal. Set BROTHER_PRINT_DEBUG=1\n * to also include the full chain inline.\n */\nfunction reportError(e: any): void {\n const lines: string[] = [];\n lines.push(`# brother-print error report`);\n lines.push(`# timestamp: ${new Date().toISOString()}`);\n lines.push(`# argv: ${process.argv.join(\" \")}`);\n lines.push(`# cwd: ${process.cwd()}`);\n lines.push(`# pid: ${process.pid}`);\n lines.push(\"\");\n\n let cur = e;\n let depth = 0;\n while (cur) {\n const prefix = depth === 0 ? \"Error\" : \"Caused by\";\n const name = cur.name && cur.name !== \"Error\" ? ` ${cur.name}` : \"\";\n const code = cur.code ? ` [${cur.code}]` : \"\";\n const msg = cur.message ?? String(cur);\n lines.push(`${prefix}${name}${code}: ${msg}`);\n if (cur.path) lines.push(` path: ${cur.path}`);\n if (cur.input) lines.push(` input: ${cur.input}`);\n if (cur.stack) lines.push(String(cur.stack));\n lines.push(\"\");\n cur = cur.cause;\n depth++;\n if (depth > 8) { lines.push(\"... (cause chain truncated at 8 levels)\"); break; }\n }\n\n const dump = lines.join(\"\\n\");\n const tempPath = path.join(os.tmpdir(), `brother-print-error-${Date.now()}-${process.pid}.log`);\n let wroteFile = false;\n try { fs.writeFileSync(tempPath, dump); wroteFile = true; } catch { /* fallback */ }\n\n if (wroteFile) {\n console.error(`Error: ${tempPath}`);\n } else {\n console.error(dump);\n }\n if (process.env.BROTHER_PRINT_DEBUG) {\n console.error(\"--- full report (BROTHER_PRINT_DEBUG enabled) ---\");\n console.error(dump);\n }\n}\n\nasync function cmdList(opts: Record<string, string | boolean>): Promise<void> {\n const printers = await listPrinters();\n /* Brother's listPrinters returns just { name } (legacy shape). To get\n * portName/driverName for the diagnostic line, query label-core's\n * coreListPrinters too. */\n const { listPrinters: coreListPrinters } = await import(\"@bobfrankston/label-core\");\n const all = await coreListPrinters(/brother|^pt-|^ql-/i);\n const byName = new Map(all.map(p => [p.name, p]));\n\n if (printers.length === 0) {\n console.log(\"No installed Brother printers.\");\n } else {\n const sorted = [...printers].sort((a, b) => a.name.localeCompare(b.name));\n console.log(`Brother printers (${sorted.length}):`);\n for (let i = 0; i < sorted.length; i++) {\n const p = sorted[i];\n const info = byName.get(p.name);\n let statusStr = \"?\";\n let queueWarning = \"\";\n try {\n const s = await brotherPrinter.getStatus(p.name);\n statusStr = s.online ? \"online\" : `offline (${s.statusText}${s.error ? \", \" + s.error : \"\"})`;\n queueWarning = s.queueWarning;\n } catch (e: any) {\n statusStr = `status error: ${e.message}`;\n }\n const port = info ? shortenPort(info.portName) : \"(unknown)\";\n const driver = info?.driverName ?? \"(unknown)\";\n console.log(` #${i + 1} ${p.name}`);\n if (info?.comment) console.log(` description: ${info.comment}`);\n if (info?.location) console.log(` location: ${info.location}`);\n console.log(` port: ${port}`);\n if (info?.portName && info.portName !== port) {\n console.log(` full port: ${info.portName}`);\n }\n console.log(` driver: ${driver}`);\n if (info?.shareName && info.shareName !== p.name) {\n console.log(` share name: ${info.shareName}`);\n }\n console.log(` status: ${statusStr}`);\n if (queueWarning) console.log(` warning: ${queueWarning}`);\n }\n }\n\n if (opts.mdns) {\n const { discoverPdlPrinters, isBrother, modelFromTxt, matchesInstalledPort } =\n await import(\"./mdns.js\");\n console.log(\"\");\n console.log(\"Browsing mDNS for _pdl-datastream._tcp (3s)...\");\n const found = (await discoverPdlPrinters()).filter(isBrother);\n if (found.length === 0) {\n console.log(\"No Brother printers responded via mDNS.\");\n return;\n }\n const installedPorts = all.map(p => p.portName);\n const networkOnly = found.filter(m => !installedPorts.some(pn => matchesInstalledPort(m, pn)));\n const matched = found.filter(m => installedPorts.some(pn => matchesInstalledPort(m, pn)));\n\n console.log(`mDNS responders (${found.length}; ${matched.length} matched, ${networkOnly.length} network-only):`);\n let n = 1;\n for (const m of [...matched, ...networkOnly]) {\n const isNetOnly = networkOnly.includes(m);\n const tag = isNetOnly ? \" [network only]\" : \" [installed]\";\n const model = modelFromTxt(m) ?? \"(unknown model)\";\n console.log(` #${n++} ${m.instanceName}${tag}`);\n console.log(` model: ${model}`);\n console.log(` hostname: ${m.hostname.replace(/\\.$/, \"\")}`);\n if (m.addresses.length > 0) {\n console.log(` address: ${m.addresses.join(\", \")}`);\n }\n console.log(` port: ${m.port}`);\n }\n }\n}\n\n/**\n * Pull a short identifier out of a Windows printer port: \"... on hostname\"\n * → hostname; raw IP/hostname kept as-is; USB ports kept as-is.\n */\nfunction shortenPort(portName: string): string {\n if (!portName) return \"(unknown)\";\n const onMatch = portName.match(/\\bon\\s+(\\S+)\\s*$/i);\n if (onMatch) return onMatch[1];\n const hostMatch = portName.match(/\\b(\\d{1,3}(?:\\.\\d{1,3}){3}|[\\w-]+\\.local|[\\w-]+\\.[\\w.-]+)\\b/);\n if (hostMatch) return hostMatch[1];\n return portName;\n}\n\n/**\n * Show details for a single resolved printer: name, port, driver, online\n * status, and the loaded media. For QL printers (auto-detected via the QL\n * TCP path) the media is read from the Windows driver's print ticket; for\n * PT printers detectTape queries the printer live (raw ESC i S status),\n * falling back to the driver ticket when the printer is unreachable.\n */\nasync function cmdPrinterInfo(printerName: string, qlHost: string | undefined): Promise<void> {\n const { listPrinters: coreListPrinters } = await import(\"@bobfrankston/label-core\");\n const all = await coreListPrinters(/brother|^pt-|^ql-/i);\n const info = all.find(p => p.name === printerName);\n\n console.log(`Printer: ${printerName}`);\n if (info?.portName) {\n console.log(`Port: ${info.portName}`);\n }\n if (info?.driverName) {\n console.log(`Driver: ${info.driverName}`);\n }\n try {\n const s = await brotherPrinter.getStatus(printerName);\n const statusStr = s.online ? \"online\" : `offline (${s.statusText}${s.error ? \", \" + s.error : \"\"})`;\n console.log(`Status: ${statusStr}`);\n console.log(`Queue: ${s.queueLength} job(s)`);\n for (const j of s.jobs) {\n console.log(` #${j.id} \"${j.documentName}\" -- ${j.statusText}${j.stuck ? \" [STUCK]\" : \"\"}`);\n }\n if (s.queueWarning) console.log(`Warning: ${s.queueWarning}`);\n } catch (e: any) {\n console.log(`Status: error: ${e.message}`);\n }\n\n if (!qlHost) {\n const { resolvePtModel } = await import(\"./ptdirect.js\");\n const model = resolvePtModel(printerName);\n const direct = await resolvePtPort(printerName);\n if (model && direct) {\n console.log(`Direct: ${direct.port} via ${direct.source}`);\n console.log(` profile ${model.name}${model.verified ? \"\" : \" — geometry not from this model's own manual\"}`);\n } else {\n console.log(`Direct: unavailable (${!model ? \"no raster profile for this model\" : \"no serial port found\"}) — prints via the spooler`);\n }\n }\n\n if (qlHost) {\n console.log(`QL host: ${qlHost} (TCP/9100)`);\n const { detectQLMediaFromWindows } = await import(\"./ql.js\");\n const media = await detectQLMediaFromWindows(printerName);\n if (media) {\n console.log(`Media: ${media.name} (id ${media.id}, ${media.widthMm}mm${media.heightMm ? `×${media.heightMm}mm` : \", continuous\"})`);\n console.log(` printArea ${media.printAreaDots} dots${media.dieCutMaskedAreaDots ? `, dieCut ${media.dieCutMaskedAreaDots} dots` : \"\"}`);\n } else {\n console.log(`Media: (not detected from Windows driver — pass -ql-media <id>)`);\n }\n } else {\n const detected = await detectTape(printerName);\n const src = detected?.source === \"printer\" ? \"live from printer\" : \"driver default — printer unreachable\";\n console.log(`Loaded tape: ${detected ? `${detected.tape}mm (${src})` : \"(not detected)\"}`);\n }\n}\n\nasync function cmdStatus(opts: Record<string, string | boolean>): Promise<void> {\n const name = (opts.printer as string) || undefined;\n const s = await brotherPrinter.getStatus(name);\n console.log(`Printer: ${s.name}`);\n console.log(`Online: ${s.online ? \"yes\" : \"no\"}`);\n console.log(`Status: ${s.statusText}`);\n if (s.error) console.log(`Error: ${s.error}`);\n console.log(`Queue: ${s.queueLength} job(s)`);\n for (const j of s.jobs) {\n console.log(` #${j.id} \"${j.documentName}\" -- ${j.statusText}${j.stuck ? \" [STUCK]\" : \"\"}`);\n }\n if (s.queueWarning) console.log(`Warning: ${s.queueWarning}`);\n if (s.workOffline) console.log(`Work offline flag: true`);\n}\n\n/**\n * Set the default printer. `-default <name>` and `-config -printer <name>` are\n * the same operation and share this one setter -- two ways to say it, one\n * mechanism deciding what gets stored.\n *\n * The name goes through resolvePrinter first so what lands in the config is a\n * real queue name: \"710\" is stored as \"Brother PT-P710BT\", and a name matching\n * nothing is rejected here rather than at the next print.\n * Claude Code 2026-09-01.\n */\nasync function cmdSetDefault(value: string): Promise<void> {\n const name = await resolvePrinter(value);\n setConfig({ defaultPrinter: name });\n console.log(`Default printer set to: ${name}`);\n console.log(` (stored in ${getConfigPath()})`);\n}\n\nasync function cmdConfig(opts: Record<string, string | boolean>): Promise<void> {\n const hasUpdate = !!(opts.tape || opts.printer);\n if (!hasUpdate) {\n const cfg = getConfig();\n console.log(`Configuration:`);\n console.log(` File: ${getConfigPath()}`);\n console.log(` Default tape: ${cfg.defaultTape ? cfg.defaultTape + \"mm\" : \"(not set)\"}`);\n console.log(` Default printer: ${cfg.defaultPrinter ?? \"(not set)\"}`);\n console.log(\"\\nValid tape sizes: 6, 9, 12, 18, 24\");\n return;\n }\n if (opts.tape) {\n const t = parseTape(opts.tape as string);\n setConfig({ defaultTape: t });\n console.log(`Default tape set to: ${t}mm`);\n }\n if (opts.printer) {\n /* main() already resolved opts.printer to a real queue name. */\n setConfig({ defaultPrinter: opts.printer as string });\n console.log(`Default printer set to: ${opts.printer}`);\n }\n}\n\nasync function resolveTape(opts: Record<string, string | boolean>): Promise<TapeSize> {\n /* Explicit -tape skips the status round-trip entirely: the user said\n * what they want, and the live query costs ~1s of PowerShell. */\n if (opts.tape) return parseTape(opts.tape as string);\n const detected = await detectTape(opts.printer as string | undefined);\n if (detected) return detected.tape;\n return getConfig().defaultTape ?? 24;\n}\n\nasync function cmdPrint(\n opts: Record<string, string | boolean>,\n segments: Segment[],\n inputs: string[]\n): Promise<void> {\n const tape = await resolveTape(opts);\n\n // If there are 2+ positional inputs, treat each as a text segment.\n // (A single positional input is handled below via classifyInput so it can\n // auto-detect file paths.)\n if (inputs.length > 1 || (inputs.length >= 1 && segments.length > 0)) {\n for (const inp of inputs) {\n segments.push({ type: \"text\", value: inp });\n }\n inputs.length = 0;\n }\n\n const baseOpts = {\n printer: opts.printer as string | undefined,\n wait: !opts.nowait,\n waitTimeoutMs: opts.timeout ? Math.round(parseFloat(opts.timeout as string) * 1000) : undefined,\n waitIntervalMs: opts.interval ? Math.round(parseFloat(opts.interval as string) * 1000) : undefined,\n onWaiting: makeWaitCallback(),\n log: (msg: string) => outln(msg),\n };\n\n const qlHost = typeof opts.ql === \"string\" ? opts.ql : undefined;\n const qlMediaId = typeof opts.qlMedia === \"string\" ? parseInt(opts.qlMedia, 10) : undefined;\n\n // Multi-segment mode: explicit -text/-qr (>=1 segment), with positional joined in\n if (segments.length > 1 || (segments.length === 1 && inputs.length === 0)) {\n const segOpts: SegmentOptions = {\n ...baseOpts,\n tape,\n textHeight: opts.height as string | undefined,\n space: opts.space as string | undefined,\n };\n let segDirectPort: string;\n if (opts.output) {\n const buffer = await renderSegments(segments, tape, opts.height as string | undefined, opts.space as string | undefined);\n fs.writeFileSync(opts.output as string, buffer);\n outln(`Saved to ${opts.output}`);\n } else if (qlHost) {\n const buffer = await renderSegments(segments, tape, opts.height as string | undefined, opts.space as string | undefined);\n const { printPngToQL } = await import(\"./ql.js\");\n await printPngToQL(qlHost, buffer, qlMediaId, opts.printer as string | undefined, !!opts.verbose);\n outln(`Printed ${segments.length} segment(s) on ${(opts.printer as string) || \"QL\"} @ ${qlHost}, ${tape}mm (direct TCP/9100)`);\n } else if (segDirectPort = await tryPrintDirect(\n await renderSegments(segments, tape, opts.height as string | undefined, opts.space as string | undefined),\n opts, tape)) {\n reportPrinted(`${segments.length} segment(s) `, opts, tape, segDirectPort, lastDirectConfirmed);\n } else {\n await printSegments(segments, segOpts);\n reportPrinted(`${segments.length} segment(s) `, opts, tape, null);\n }\n return;\n }\n\n // Single content op\n const printOpts: PrintOptions = {\n ...baseOpts,\n tape,\n aspect: opts.aspect as string | undefined,\n textHeight: opts.height as string | undefined,\n };\n\n if (opts.clip) {\n printOpts.clip = true;\n } else if (inputs.length === 1) {\n Object.assign(printOpts, classifyInput(inputs[0], opts));\n } else if (inputs.length === 0 && segments.length === 0) {\n if (opts.printer) {\n await cmdPrinterInfo(opts.printer as string, qlHost);\n return;\n }\n showHelp();\n return;\n }\n\n if (opts.output) {\n const buffer = await render(printOpts);\n fs.writeFileSync(opts.output as string, buffer);\n outln(`Saved to ${opts.output}`);\n return;\n }\n if (qlHost) {\n const buffer = await render(printOpts);\n const { printPngToQL } = await import(\"./ql.js\");\n await printPngToQL(qlHost, buffer, qlMediaId, opts.printer as string | undefined, !!opts.verbose);\n outln(`Printed on ${(opts.printer as string) || \"QL\"} @ ${qlHost} (direct TCP/9100)`);\n return;\n }\n const directPort = await tryPrintDirect(await render(printOpts), opts, tape);\n const directConfirmed = lastDirectConfirmed;\n if (directPort) {\n reportPrinted(\"\", opts, tape, directPort, directConfirmed);\n return;\n }\n await print(printOpts);\n reportPrinted(\"\", opts, tape, null);\n}\n\n/**\n * Name the printer, the tape and the route a label actually took.\n *\n * \"Printed on 24mm tape\" is not something the user can check: it does not say\n * which of four Brother printers took it, and it reads identically whether the\n * bytes reached the printer or merely reached the Windows queue -- which is\n * where labels disappear. Naming the target and the route makes the line\n * verifiable, and still means something when read back in a log later.\n */\nfunction describeTarget(opts: Record<string, string | boolean>, tape: TapeSize, port: string): string {\n const printer = (opts.printer as string) || getDefaultPrinter();\n return port\n ? `${printer}, ${tape}mm tape (direct to ${port})`\n : `${printer}, ${tape}mm tape`;\n}\n\n/**\n * The verb has to be honest about what happened. A direct write reached the\n * printer, so \"Printed\" is a claim we can stand behind. Handing a job to the\n * Windows spooler is not printing -- the job can sit Retained in Error behind\n * another dead job and never reach the tape, which is exactly how labels have\n * been going missing. Say \"Queued\" for that, and name the printer either way.\n */\nfunction reportPrinted(\n what: string,\n opts: Record<string, string | boolean>,\n tape: TapeSize,\n port: string,\n confirmed?: boolean\n): void {\n let verb: string;\n let tail: string;\n if (!port) {\n verb = \"Queued\";\n tail = \" -- the spooler has it; check the queue if nothing comes out\";\n } else if (confirmed) {\n verb = \"Printed\";\n tail = \"\";\n } else {\n /* The bytes were delivered, and that is all we know. This printer does\n * not report back, so it can still have refused the job -- wrong tape,\n * cover open, cutter jam -- with nothing to tell us. Claiming \"Printed\"\n * here is what made earlier failures look like successes. */\n verb = \"Sent\";\n tail = \" -- this printer does not confirm, so check the tape\";\n }\n outln(`${verb} ${what}on ${describeTarget(opts, tape, port)}${tail}`);\n}\n\n/**\n * Write the rendered label straight to the printer's port, skipping the\n * Windows spooler. Returns false when this printer has no direct path, so the\n * caller can fall back to the XPS/queue route.\n *\n * The direct route is the default because the queue is where labels go to die:\n * a job that fails is left Retained and blocks every later job until someone\n * clears it by hand, and `WorkOffline` discards jobs without a word. Writing\n * the bytes ourselves either succeeds or throws — there is no third state that\n * looks like success and prints nothing. `-queue` opts back in.\n */\nasync function tryPrintDirect(\n png: Buffer,\n opts: Record<string, string | boolean>,\n tape: TapeSize\n): Promise<string> {\n if (opts.queue) {\n /* A queue can be pointed at a discard port so the spooler stops\n * fighting us for the printer's serial port. Printing to it would\n * report success and put nothing on the tape, which is the one\n * outcome this whole module exists to prevent. */\n await refuseDiscardQueue(opts.printer as string);\n return null;\n }\n /* Fall back to the same default the spooler path uses, so omitting -p does\n * not silently drop the label into the queue. */\n const printerName = (opts.printer as string) || getDefaultPrinter();\n if (!printerName) return null;\n\n const { resolvePtModel, printPtDirect } = await import(\"./ptdirect.js\");\n const model = resolvePtModel(printerName);\n if (!model) return null;\n\n const port = (opts.port as string) || (await resolvePtPort(printerName))?.port;\n if (!port) return null;\n\n lastDirectConfirmed = model.confirmsPrint;\n const jobsBefore = await listJobIds(printerName);\n try {\n await printPtDirect(png, {\n port,\n printerName,\n tape,\n autoCut: !opts.nocut,\n log: opts.verbose ? (m: string) => outln(m) : undefined,\n });\n } finally {\n /* Clear it even when the write failed -- a failed open still leaves the\n * phantom behind, and that is precisely when a wedged queue is most\n * confusing to look at. */\n await clearPhantomJobs(printerName, jobsBefore);\n }\n return port;\n}\n\n/**\n * Whether the last direct print was confirmed by the printer. Set by\n * tryPrintDirect; read by the reporting call right after it. A module-level\n * value rather than a return field because the port string is already the\n * caller's success signal and threading a second one through both dispatch\n * sites obscures them.\n */\nlet lastDirectConfirmed = false;\n\n/** Ports that swallow whatever the spooler sends them. */\nconst DISCARD_PORTS = /^(nul|null|nul:|null:)$/i;\n\n/**\n * List the spooler's current job ids for a printer. Best-effort: a failure\n * here must never stop a label printing.\n */\nasync function listJobIds(printerName: string): Promise<Set<number>> {\n try {\n const { runScriptOrThrow } = await import(\"@bobfrankston/label-core\");\n const out = await runScriptOrThrow(\n `@(Get-PrintJob -PrinterName '${printerName.replace(/'/g, \"''\")}' -ErrorAction SilentlyContinue).Id -join ','`\n );\n return new Set(out.trim().split(\",\").map(Number).filter(n => !isNaN(n)));\n } catch {\n return new Set();\n }\n}\n\n/**\n * Remove the empty job Windows invents when we open the printer's port.\n *\n * Writing directly to a serial port that a print queue is bound to makes the\n * spooler materialise a zero-byte job -- proven with a script that only opens\n * the port and writes an initialise sequence. That job then parks itself in\n * Error and drags the queue down with it, which is what made the queue look\n * broken after every successful direct print.\n *\n * The queue has to stay bound to the port: that binding is what establishes\n * and holds the Bluetooth RFCOMM link. Open the port with the queue pointed\n * elsewhere and the link will not come up at all. So the phantom cannot be\n * prevented, only cleared.\n *\n * Scoped by identity, not by size: only jobs that did not exist before we\n * opened the port are removed. Size is no use as a filter -- the spooler\n * records a copy of the bytes we put on the wire, so these jobs are not empty\n * (1205 and 4373 bytes were observed for two ordinary labels).\n *\n * The residual risk is a real job submitted by another program during the\n * second or so a direct print takes. That window is narrow and the alternative\n * -- leaving the queue permanently in Error after every label -- is worse.\n */\nasync function clearPhantomJobs(printerName: string, before: Set<number>): Promise<void> {\n try {\n const { runScriptOrThrow } = await import(\"@bobfrankston/label-core\");\n const name = printerName.replace(/'/g, \"''\");\n const skip = [...before].join(\",\") || \"-1\";\n /* The spooler creates the job around the time the handle closes, so\n * give it a moment to appear before looking, and a moment to act on\n * the delete before returning -- a job caught mid-print lingers in\n * \"Deleting\" otherwise. */\n await runScriptOrThrow(`\n$ErrorActionPreference = 'SilentlyContinue'\n$before = @(${skip})\nStart-Sleep -Milliseconds 900\nGet-PrintJob -PrinterName '${name}' | Where-Object { $_.Id -notin $before } |\n ForEach-Object { Remove-PrintJob -PrinterName '${name}' -ID $_.Id }\nStart-Sleep -Milliseconds 600\n`);\n } catch { /* cosmetic cleanup; never fail a print over it */ }\n}\n\n/**\n * Refuse `-queue` when the printer's Windows queue points at a discard port.\n *\n * Repointing a queue away from the printer's real port is how we stop the\n * spooler from creating a phantom job every time we open that port. The cost\n * is that the queue no longer goes anywhere, so `-queue` must fail loudly\n * rather than cheerfully reporting a label that was never printed.\n */\nasync function refuseDiscardQueue(printerName: string): Promise<void> {\n const name = printerName || getDefaultPrinter();\n if (!name) return;\n const { listPrinters: coreListPrinters } = await import(\"@bobfrankston/label-core\");\n const info = (await coreListPrinters(/brother|^pt-|^ql-/i)).find(p => p.name === name);\n const portName = (info?.portName ?? \"\").replace(/:$/, \"\");\n if (!DISCARD_PORTS.test(portName)) return;\n throw new UserError(\n `${name}'s Windows queue points at \"${info.portName}\", which discards everything sent to it — ` +\n `-queue would report success and print nothing. Drop -queue to print directly, ` +\n `or repoint the queue at the printer's port with: Set-Printer -Name \"${name}\" -PortName \"COMn:\"`\n );\n}\n\n/**\n * Find the serial port to write a P-touch label to.\n *\n * The printer queue's PortName is the obvious source but it goes stale:\n * Windows reassigns a Bluetooth printer's outgoing COM number when it\n * re-pairs (the PT-D610BT here was installed on COM8 and came back on COM10),\n * and the queue keeps pointing at the old one. Worse, the abandoned number is\n * often still a valid *incoming* Bluetooth port with nothing behind it, so the\n * stale queue looks openable and simply swallows the job.\n *\n * So: ask Bluetooth which port actually belongs to this printer, and fall back\n * to the queue's port only when no Bluetooth match exists (a genuinely wired\n * serial printer). Returns null when neither yields a COM port.\n */\nasync function resolvePtPort(printerName: string): Promise<{ port: string; source: string }> {\n const { listPrinters: coreListPrinters, runScriptOrThrow } =\n await import(\"@bobfrankston/label-core\");\n\n /* Bluetooth SPP ports carry the remote device's address in their instance\n * id; BTHPORT maps that address to the advertised device name, which\n * contains the model (e.g. \"PT-D610BT5465\"). Match on the model token. */\n const model = /PT-([A-Z0-9]+)/i.exec(printerName)?.[1];\n if (model) {\n const script = [\n \"$ErrorActionPreference = 'SilentlyContinue'\",\n \"Get-PnpDevice -Class Ports -PresentOnly | Where-Object { $_.FriendlyName -match 'Bluetooth' } | ForEach-Object {\",\n \" if ($_.InstanceId -match '&0&([0-9A-Fa-f]{12})_') {\",\n \" $addr = $matches[1].ToLower()\",\n \" $raw = (Get-ItemProperty \\\"HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Services\\\\BTHPORT\\\\Parameters\\\\Devices\\\\$addr\\\").Name\",\n \" if ($raw -and $_.FriendlyName -match '\\\\((COM\\\\d+)\\\\)') {\",\n \" $com = $matches[1]\",\n \" $name = [System.Text.Encoding]::ASCII.GetString($raw).Trim([char]0)\",\n \" Write-Output \\\"$com=$name\\\"\",\n \" }\",\n \" }\",\n \"}\",\n ].join(\"\\n\");\n try {\n const out = (await runScriptOrThrow(script)).trim();\n for (const line of out.split(/\\r?\\n/)) {\n const eq = line.indexOf(\"=\");\n if (eq < 0) continue;\n const com = line.slice(0, eq).trim();\n const name = line.slice(eq + 1).trim();\n const squashed = name.replace(/[^A-Za-z0-9]/g, \"\").toUpperCase();\n if (com && squashed.includes(model.toUpperCase())) {\n return { port: com, source: `Bluetooth device ${name}` };\n }\n }\n } catch { /* fall through to the queue's port */ }\n }\n\n const info = (await coreListPrinters(/brother|^pt-/i)).find(p => p.name === printerName);\n const m = /^(COM\\d+):?$/i.exec(info?.portName ?? \"\");\n if (m) return { port: m[1], source: `printer queue port ${info.portName}` };\n return null;\n}\n\nfunction classifyInput(input: string, opts: Record<string, string | boolean>): Partial<CorePrintOptions> {\n if (opts.text) return { text: input };\n if (opts.html) return { htmlPath: path.resolve(input) };\n if (opts.image) return { imagePath: path.resolve(input) };\n\n const lower = input.toLowerCase();\n if (lower.endsWith(\".html\") || lower.endsWith(\".htm\")) return { htmlPath: path.resolve(input) };\n if (lower.endsWith(\".txt\")) return { textFile: path.resolve(input) };\n if (/\\.(png|jpg|jpeg|bmp|gif)$/i.test(lower)) return { imagePath: path.resolve(input) };\n if (fs.existsSync(input)) {\n const ext = path.extname(lower);\n if (ext === \".html\" || ext === \".htm\") return { htmlPath: path.resolve(input) };\n return { textFile: path.resolve(input) };\n }\n return { text: input };\n}\n\nfunction makeWaitCallback() {\n let lastReport = -Infinity;\n return (status: PrinterStatus, elapsedMs: number) => {\n const secs = Math.floor(elapsedMs / 1000);\n // Non-TTY (redirected output) can't rewrite in place; report sparsely.\n if (!process.stderr.isTTY) {\n if (secs - lastReport < 30) return;\n lastReport = secs;\n }\n statusLine.update(`[brother-print] waiting for ${status.name} (${status.statusText}${status.error ? \", \" + status.error : \"\"}); ${secs}s`);\n };\n}\n\nmain();\n"]}
package/cli.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import * as fs from "fs";
8
+ import packageJson from "./package.json" with { type: "json" };
8
9
  import * as os from "os";
9
10
  import * as path from "path";
10
11
  import * as dns from "dns/promises";
@@ -35,7 +36,11 @@ import {
35
36
  } from "./api.js";
36
37
  import type { TapeSize, PrintOptions, SegmentOptions } from "./api.js";
37
38
 
38
- const VERSION = "1.1.0";
39
+ /* Claude Code 2026-09-01: was a hardcoded "1.1.0", 23 patch releases stale by
40
+ * the time anyone noticed -- `-version` and `-help` both reported a number that
41
+ * was not the one installed. Read it from the package instead; there is exactly
42
+ * one place a version belongs. */
43
+ const VERSION = packageJson.version;
39
44
  const VALID_TAPES: TapeSize[] = [6, 9, 12, 18, 24];
40
45
 
41
46
  function parseTape(value: string): TapeSize {
@@ -49,6 +54,7 @@ function parseTape(value: string): TapeSize {
49
54
  const VALUED: ValuedOptionSpec[] = [
50
55
  { names: ["-tape"], key: "tape" },
51
56
  { names: ["-p", "-printer"], key: "printer" },
57
+ { names: ["-default"], key: "setDefault" },
52
58
  { names: ["-o", "-output"], key: "output" },
53
59
  { names: ["-a", "-aspect"], key: "aspect" },
54
60
  { names: ["-ht", "-height"], key: "height" },
@@ -98,6 +104,7 @@ Single quotes can wrap arguments: '7"' 'line1\\nline2'
98
104
  Options:
99
105
  -tape <size> Tape size: 6, 9, 12, 18, 24 (mm) [auto-detected]
100
106
  -p, -printer <name> Printer queue name
107
+ -default <name> Set the default printer (used when -p is omitted)
101
108
  -o, -output <file> Save PNG to file instead of printing
102
109
  -a, -aspect <r> Aspect ratio width:height for HTML (e.g. 3.5:2)
103
110
  -ht, -height <size> Text height: 12mm, .5in, or 50% (of tape height)
@@ -200,6 +207,10 @@ async function main(): Promise<void> {
200
207
  if (host) parsed.opts.ql = host;
201
208
  }
202
209
  }
210
+ if (typeof parsed.opts.setDefault === "string") {
211
+ await cmdSetDefault(parsed.opts.setDefault);
212
+ return;
213
+ }
203
214
  switch (parsed.command) {
204
215
  case "list": await cmdList(parsed.opts); return;
205
216
  case "status": await cmdStatus(parsed.opts); return;
@@ -544,6 +555,23 @@ async function cmdStatus(opts: Record<string, string | boolean>): Promise<void>
544
555
  if (s.workOffline) console.log(`Work offline flag: true`);
545
556
  }
546
557
 
558
+ /**
559
+ * Set the default printer. `-default <name>` and `-config -printer <name>` are
560
+ * the same operation and share this one setter -- two ways to say it, one
561
+ * mechanism deciding what gets stored.
562
+ *
563
+ * The name goes through resolvePrinter first so what lands in the config is a
564
+ * real queue name: "710" is stored as "Brother PT-P710BT", and a name matching
565
+ * nothing is rejected here rather than at the next print.
566
+ * Claude Code 2026-09-01.
567
+ */
568
+ async function cmdSetDefault(value: string): Promise<void> {
569
+ const name = await resolvePrinter(value);
570
+ setConfig({ defaultPrinter: name });
571
+ console.log(`Default printer set to: ${name}`);
572
+ console.log(` (stored in ${getConfigPath()})`);
573
+ }
574
+
547
575
  async function cmdConfig(opts: Record<string, string | boolean>): Promise<void> {
548
576
  const hasUpdate = !!(opts.tape || opts.printer);
549
577
  if (!hasUpdate) {
@@ -561,6 +589,7 @@ async function cmdConfig(opts: Record<string, string | boolean>): Promise<void>
561
589
  console.log(`Default tape set to: ${t}mm`);
562
590
  }
563
591
  if (opts.printer) {
592
+ /* main() already resolved opts.printer to a real queue name. */
564
593
  setConfig({ defaultPrinter: opts.printer as string });
565
594
  console.log(`Default printer set to: ${opts.printer}`);
566
595
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/brother-label",
3
- "version": "1.1.22",
3
+ "version": "1.1.24",
4
4
  "description": "API and CLI for printing labels on Brother P-touch printers",
5
5
  "type": "module",
6
6
  "main": "index.js",