@bobfrankston/brother-label 1.1.5 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -75,7 +75,7 @@ brother-print -clip # auto-detect: image if present, else text
75
75
  | `-p, --printer <name>` | Printer name |
76
76
  | `-o, --output <file>` | Save to file instead of printing |
77
77
  | `-a, --aspect <ratio>` | Aspect ratio width:height for HTML (e.g., 3.5:2) |
78
- | `-H, --height <size>` | Text height: 12mm, .5in, or 50% (of tape height) |
78
+ | `-ht, --height <size>` | Text height: 12mm, .5in, or 50% (of tape height) |
79
79
  | `-s, --space <size>` | Space between segments: 12px, 1mm, .2in |
80
80
  | `-w, --html` | Force input as HTML file path |
81
81
  | `-i, --image` | Force input as image file path |
package/api.js CHANGED
@@ -11,7 +11,7 @@
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, runPowerShellOrThrow, readJsonConfig, mergeJsonConfig, } from "@bobfrankston/label-core";
14
+ import { validateContent, resolveContent, renderSegments as coreRenderSegments, listPrinters as coreListPrinters, getPrinterStatus, waitOnline as coreWaitOnline, runScriptOrThrow, readJsonConfig, mergeJsonConfig, } from "@bobfrankston/label-core";
15
15
  /* ----- Constants ----- */
16
16
  const CONFIG_PATH = path.join(os.homedir(), ".brother-label.json");
17
17
  const DEFAULT_PRINTER = "Brother PT-P710BT";
@@ -77,7 +77,7 @@ try {
77
77
  }
78
78
  `;
79
79
  try {
80
- const out = await runPowerShellOrThrow(script);
80
+ const out = await runScriptOrThrow(script);
81
81
  for (const [size, media] of Object.entries(MEDIA_OPTIONS)) {
82
82
  if (out.includes(media.name))
83
83
  return parseInt(size, 10);
@@ -346,7 +346,7 @@ $xpsDocForPrint.Close()
346
346
  Remove-Item $xpsPath -ErrorAction SilentlyContinue
347
347
  `;
348
348
  try {
349
- await runPowerShellOrThrow(script);
349
+ await runScriptOrThrow(script);
350
350
  }
351
351
  finally {
352
352
  if (fs.existsSync(tempPath))
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 runPowerShellOrThrow,\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/* ----- 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/**\n * Auto-detect tape size from printer's default print ticket. Returns null if\n * detection fails. Brother's driver embeds the loaded tape's CustomMediaSize\n * name in the default PrintTicket XML.\n */\nexport async function detectTapeSize(printerName?: string): Promise<TapeSize> {\n const config = getConfig();\n const printer = printerName ?? config.defaultPrinter ?? DEFAULT_PRINTER;\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 runPowerShellOrThrow(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/* ----- 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 ?? this.getConfig().defaultPrinter ?? DEFAULT_PRINTER;\n return getPrinterStatus(printer);\n }\n async waitOnline(printerName?: string, opts: WaitOptions = {}): Promise<PrinterStatus> {\n const printer = printerName ?? this.getConfig().defaultPrinter ?? DEFAULT_PRINTER;\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 ?? this.getConfig().defaultPrinter ?? DEFAULT_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 = opts.printer ?? this.getConfig().defaultPrinter ?? DEFAULT_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 if (status.online) return;\n if (opts.wait === false) {\n throw new Error(`Printer \"${printer}\" is offline (${status.statusText}${status.error ? \", \" + status.error : \"\"}). Use wait:true to wait, or pick another printer.`);\n }\n if (opts.log) opts.log(`[brother-label] ${printer} offline (${status.statusText}); waiting...`);\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 runPowerShellOrThrow(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 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/* ----- 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/**\n * Auto-detect tape size from printer's default print ticket. Returns null if\n * detection fails. Brother's driver embeds the loaded tape's CustomMediaSize\n * name in the default PrintTicket XML.\n */\nexport async function detectTapeSize(printerName?: string): Promise<TapeSize> {\n const config = getConfig();\n const printer = printerName ?? config.defaultPrinter ?? DEFAULT_PRINTER;\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/* ----- 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 ?? this.getConfig().defaultPrinter ?? DEFAULT_PRINTER;\n return getPrinterStatus(printer);\n }\n async waitOnline(printerName?: string, opts: WaitOptions = {}): Promise<PrinterStatus> {\n const printer = printerName ?? this.getConfig().defaultPrinter ?? DEFAULT_PRINTER;\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 ?? this.getConfig().defaultPrinter ?? DEFAULT_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 = opts.printer ?? this.getConfig().defaultPrinter ?? DEFAULT_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 if (status.online) return;\n if (opts.wait === false) {\n throw new Error(`Printer \"${printer}\" is offline (${status.statusText}${status.error ? \", \" + status.error : \"\"}). Use wait:true to wait, or pick another printer.`);\n }\n if (opts.log) opts.log(`[brother-label] ${printer} offline (${status.statusText}); waiting...`);\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
@@ -19,7 +19,7 @@ import {
19
19
  listPrinters as coreListPrinters,
20
20
  getPrinterStatus,
21
21
  waitOnline as coreWaitOnline,
22
- runPowerShellOrThrow,
22
+ runScriptOrThrow,
23
23
  readJsonConfig,
24
24
  mergeJsonConfig,
25
25
  } from "@bobfrankston/label-core";
@@ -143,7 +143,7 @@ try {
143
143
  }
144
144
  `;
145
145
  try {
146
- const out = await runPowerShellOrThrow(script);
146
+ const out = await runScriptOrThrow(script);
147
147
  for (const [size, media] of Object.entries(MEDIA_OPTIONS)) {
148
148
  if (out.includes(media.name)) return parseInt(size, 10) as TapeSize;
149
149
  }
@@ -422,7 +422,7 @@ $xpsDocForPrint.Close()
422
422
  Remove-Item $xpsPath -ErrorAction SilentlyContinue
423
423
  `;
424
424
  try {
425
- await runPowerShellOrThrow(script);
425
+ await runScriptOrThrow(script);
426
426
  } finally {
427
427
  if (fs.existsSync(tempPath)) fs.unlinkSync(tempPath);
428
428
  }
package/cli.js CHANGED
@@ -4,6 +4,7 @@
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 * as os from "os";
7
8
  import * as path from "path";
8
9
  import { preprocessSingleQuotes, parseArgs, } from "@bobfrankston/label-core";
9
10
  import { print, render, renderSegments, printSegments, getConfig, setConfig, getConfigPath, listPrinters, detectTapeSize, brotherPrinter, } from "./api.js";
@@ -21,7 +22,7 @@ const VALUED = [
21
22
  { names: ["-p", "-printer"], key: "printer" },
22
23
  { names: ["-o", "-output"], key: "output" },
23
24
  { names: ["-a", "-aspect"], key: "aspect" },
24
- { names: ["-H", "-height"], key: "height" },
25
+ { names: ["-ht", "-height"], key: "height" },
25
26
  { names: ["-s", "-space"], key: "space" },
26
27
  { names: ["-timeout"], key: "timeout" },
27
28
  { names: ["-interval"], key: "interval" },
@@ -56,7 +57,7 @@ Options:
56
57
  -p, -printer <name> Printer queue name
57
58
  -o, -output <file> Save PNG to file instead of printing
58
59
  -a, -aspect <r> Aspect ratio width:height for HTML (e.g. 3.5:2)
59
- -H, -height <size> Text height: 12mm, .5in, or 50% (of tape height)
60
+ -ht, -height <size> Text height: 12mm, .5in, or 50% (of tape height)
60
61
  -s, -space <size> Space between segments: 12px, 1mm, .2in
61
62
  -t, -text Force input as literal text (-text <v> for segments)
62
63
  -qr <data> QR code segment
@@ -115,25 +116,60 @@ async function main() {
115
116
  * Print an error with full context: message, cause chain (Node's fetch and
116
117
  * other newer APIs put the actual cause in error.cause), and stack on -v.
117
118
  */
119
+ /**
120
+ * Report an error: print a one-line summary to stderr and write the full
121
+ * cause-chain (with stacks, codes, paths) to a temp file. Avoids dumping
122
+ * walls of error text into the user's terminal. Set BROTHER_PRINT_DEBUG=1
123
+ * to also include the full chain inline.
124
+ */
118
125
  function reportError(e) {
126
+ const lines = [];
127
+ lines.push(`# brother-print error report`);
128
+ lines.push(`# timestamp: ${new Date().toISOString()}`);
129
+ lines.push(`# argv: ${process.argv.join(" ")}`);
130
+ lines.push(`# cwd: ${process.cwd()}`);
131
+ lines.push(`# pid: ${process.pid}`);
132
+ lines.push("");
119
133
  let cur = e;
120
134
  let depth = 0;
121
135
  while (cur) {
122
- const prefix = depth === 0 ? "Error" : `Caused by`;
136
+ const prefix = depth === 0 ? "Error" : "Caused by";
123
137
  const name = cur.name && cur.name !== "Error" ? ` ${cur.name}` : "";
124
- const msg = cur.message ?? String(cur);
125
138
  const code = cur.code ? ` [${cur.code}]` : "";
126
- const path = cur.path ? ` (${cur.path})` : cur.input ? ` (${cur.input})` : "";
127
- console.error(`${prefix}${name}${code}: ${msg}${path}`);
139
+ const msg = cur.message ?? String(cur);
140
+ lines.push(`${prefix}${name}${code}: ${msg}`);
141
+ if (cur.path)
142
+ lines.push(` path: ${cur.path}`);
143
+ if (cur.input)
144
+ lines.push(` input: ${cur.input}`);
145
+ if (cur.stack)
146
+ lines.push(String(cur.stack));
147
+ lines.push("");
128
148
  cur = cur.cause;
129
149
  depth++;
130
- if (depth > 5) {
131
- console.error("... (cause chain truncated)");
150
+ if (depth > 8) {
151
+ lines.push("... (cause chain truncated at 8 levels)");
132
152
  break;
133
153
  }
134
154
  }
135
- if (process.env.DEBUG && e.stack)
136
- console.error(e.stack);
155
+ const dump = lines.join("\n");
156
+ const tempPath = path.join(os.tmpdir(), `brother-print-error-${Date.now()}-${process.pid}.log`);
157
+ let wroteFile = false;
158
+ try {
159
+ fs.writeFileSync(tempPath, dump);
160
+ wroteFile = true;
161
+ }
162
+ catch { /* fallback */ }
163
+ const topMsg = e?.message ?? String(e);
164
+ console.error(`Error: ${topMsg}`);
165
+ if (wroteFile)
166
+ console.error(`Details: ${tempPath}`);
167
+ else
168
+ console.error(dump);
169
+ if (process.env.BROTHER_PRINT_DEBUG) {
170
+ console.error("--- full report (BROTHER_PRINT_DEBUG enabled) ---");
171
+ console.error(dump);
172
+ }
137
173
  }
138
174
  async function cmdList() {
139
175
  const printers = await listPrinters();
@@ -141,8 +177,17 @@ async function cmdList() {
141
177
  console.log("No Brother printers found.");
142
178
  return;
143
179
  }
144
- console.log(`Brother printers (${printers.length}):`);
145
- for (const p of printers) {
180
+ /* Brother's listPrinters returns just { name } (legacy shape). To get
181
+ * portName/driverName for the diagnostic line, query label-core's
182
+ * coreListPrinters too. */
183
+ const { listPrinters: coreListPrinters } = await import("@bobfrankston/label-core");
184
+ const all = await coreListPrinters(/brother|^pt-|^ql-/i);
185
+ const byName = new Map(all.map(p => [p.name, p]));
186
+ const sorted = [...printers].sort((a, b) => a.name.localeCompare(b.name));
187
+ console.log(`Brother printers (${sorted.length}):`);
188
+ for (let i = 0; i < sorted.length; i++) {
189
+ const p = sorted[i];
190
+ const info = byName.get(p.name);
146
191
  let statusStr = "?";
147
192
  try {
148
193
  const s = await brotherPrinter.getStatus(p.name);
@@ -151,9 +196,39 @@ async function cmdList() {
151
196
  catch (e) {
152
197
  statusStr = `status error: ${e.message}`;
153
198
  }
154
- console.log(` ${p.name} ${statusStr}`);
199
+ const port = info ? shortenPort(info.portName) : "(unknown)";
200
+ const driver = info?.driverName ?? "(unknown)";
201
+ console.log(` #${i + 1} ${p.name}`);
202
+ if (info?.comment)
203
+ console.log(` description: ${info.comment}`);
204
+ if (info?.location)
205
+ console.log(` location: ${info.location}`);
206
+ console.log(` port: ${port}`);
207
+ if (info?.portName && info.portName !== port) {
208
+ console.log(` full port: ${info.portName}`);
209
+ }
210
+ console.log(` driver: ${driver}`);
211
+ if (info?.shareName && info.shareName !== p.name) {
212
+ console.log(` share name: ${info.shareName}`);
213
+ }
214
+ console.log(` status: ${statusStr}`);
155
215
  }
156
216
  }
217
+ /**
218
+ * Pull a short identifier out of a Windows printer port: "... on hostname"
219
+ * → hostname; raw IP/hostname kept as-is; USB ports kept as-is.
220
+ */
221
+ function shortenPort(portName) {
222
+ if (!portName)
223
+ return "(unknown)";
224
+ const onMatch = portName.match(/\bon\s+(\S+)\s*$/i);
225
+ if (onMatch)
226
+ return onMatch[1];
227
+ const hostMatch = portName.match(/\b(\d{1,3}(?:\.\d{1,3}){3}|[\w-]+\.local|[\w-]+\.[\w.-]+)\b/);
228
+ if (hostMatch)
229
+ return hostMatch[1];
230
+ return portName;
231
+ }
157
232
  async function cmdStatus(opts) {
158
233
  const name = opts.printer || undefined;
159
234
  const s = await brotherPrinter.getStatus(name);
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 path from \"path\";\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 detectTapeSize,\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 Error(`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: [\"-H\", \"-height\"], key: \"height\" },\n { names: [\"-s\", \"-space\"], key: \"space\" },\n { names: [\"-timeout\"], key: \"timeout\" },\n { names: [\"-interval\"], key: \"interval\" },\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: [\"-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 List Brother printers and status\n brother-print status [-p <name>] Show printer status\n brother-print config Show / set defaults\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 -H, -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 -help Show this help\n -version Show version`);\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 if (parsed.opts.help) { showHelp(); return; }\n if (parsed.opts.version) { console.log(VERSION); return; }\n\n try {\n switch (parsed.command) {\n case \"list\": await cmdList(); 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 reportError(e);\n process.exit(1);\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 */\nfunction reportError(e: any): void {\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 msg = cur.message ?? String(cur);\n const code = cur.code ? ` [${cur.code}]` : \"\";\n const path = cur.path ? ` (${cur.path})` : cur.input ? ` (${cur.input})` : \"\";\n console.error(`${prefix}${name}${code}: ${msg}${path}`);\n cur = cur.cause;\n depth++;\n if (depth > 5) { console.error(\"... (cause chain truncated)\"); break; }\n }\n if (process.env.DEBUG && e.stack) console.error(e.stack);\n}\n\nasync function cmdList(): Promise<void> {\n const printers = await listPrinters();\n if (printers.length === 0) {\n console.log(\"No Brother printers found.\");\n return;\n }\n console.log(`Brother printers (${printers.length}):`);\n for (const p of printers) {\n let statusStr = \"?\";\n try {\n const s = await brotherPrinter.getStatus(p.name);\n statusStr = s.online ? \"online\" : `offline (${s.statusText}${s.error ? \", \" + s.error : \"\"})`;\n } catch (e: any) {\n statusStr = `status error: ${e.message}`;\n }\n console.log(` ${p.name} — ${statusStr}`);\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 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 const explicit = opts.tape ? parseTape(opts.tape as string) : null;\n const detected = await detectTapeSize(opts.printer as string | undefined);\n if (explicit) {\n if (detected && detected !== explicit) {\n console.warn(`Warning: -tape ${explicit}mm specified but printer reports ${detected}mm tape loaded`);\n }\n return explicit;\n }\n if (detected) return detected;\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) => console.log(msg),\n };\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 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 console.log(`Saved to ${opts.output}`);\n } else {\n await printSegments(segments, segOpts);\n console.log(`Printed ${segments.length} segment(s) on ${tape}mm tape`);\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 showHelp();\n return;\n }\n\n if (opts.output) {\n const buffer = await render(printOpts);\n fs.writeFileSync(opts.output as string, buffer);\n console.log(`Saved to ${opts.output}`);\n return;\n }\n await print(printOpts);\n console.log(`Printed on ${tape}mm tape`);\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 = 0;\n return (status: PrinterStatus, elapsedMs: number, alternatives: PrinterStatus[]) => {\n const secs = Math.floor(elapsedMs / 1000);\n if (secs - lastReport < 5) return;\n lastReport = secs;\n const altStr = alternatives.length > 0\n ? ` (online alternatives: ${alternatives.map(a => a.name).join(\", \")})`\n : \"\";\n console.log(`[brother-print] still waiting for ${status.name} (${status.statusText}${status.error ? \", \" + status.error : \"\"}); ${secs}s elapsed${altStr}`);\n };\n}\n\nmain();\n"]}
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 {\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 detectTapeSize,\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 Error(`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];\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: [\"-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 List Brother printers and status\n brother-print status [-p <name>] Show printer status\n brother-print config Show / set defaults\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 -help Show this help\n -version Show version`);\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 if (parsed.opts.help) { showHelp(); return; }\n if (parsed.opts.version) { console.log(VERSION); return; }\n\n try {\n switch (parsed.command) {\n case \"list\": await cmdList(); 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 reportError(e);\n process.exit(1);\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 const topMsg = e?.message ?? String(e);\n console.error(`Error: ${topMsg}`);\n if (wroteFile) console.error(`Details: ${tempPath}`);\n else console.error(dump);\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(): Promise<void> {\n const printers = await listPrinters();\n if (printers.length === 0) {\n console.log(\"No Brother printers found.\");\n return;\n }\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 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 try {\n const s = await brotherPrinter.getStatus(p.name);\n statusStr = s.online ? \"online\" : `offline (${s.statusText}${s.error ? \", \" + s.error : \"\"})`;\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 }\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\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 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 const explicit = opts.tape ? parseTape(opts.tape as string) : null;\n const detected = await detectTapeSize(opts.printer as string | undefined);\n if (explicit) {\n if (detected && detected !== explicit) {\n console.warn(`Warning: -tape ${explicit}mm specified but printer reports ${detected}mm tape loaded`);\n }\n return explicit;\n }\n if (detected) return detected;\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) => console.log(msg),\n };\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 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 console.log(`Saved to ${opts.output}`);\n } else {\n await printSegments(segments, segOpts);\n console.log(`Printed ${segments.length} segment(s) on ${tape}mm tape`);\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 showHelp();\n return;\n }\n\n if (opts.output) {\n const buffer = await render(printOpts);\n fs.writeFileSync(opts.output as string, buffer);\n console.log(`Saved to ${opts.output}`);\n return;\n }\n await print(printOpts);\n console.log(`Printed on ${tape}mm tape`);\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 = 0;\n return (status: PrinterStatus, elapsedMs: number, alternatives: PrinterStatus[]) => {\n const secs = Math.floor(elapsedMs / 1000);\n if (secs - lastReport < 5) return;\n lastReport = secs;\n const altStr = alternatives.length > 0\n ? ` (online alternatives: ${alternatives.map(a => a.name).join(\", \")})`\n : \"\";\n console.log(`[brother-print] still waiting for ${status.name} (${status.statusText}${status.error ? \", \" + status.error : \"\"}); ${secs}s elapsed${altStr}`);\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 * as os from "os";
8
9
  import * as path from "path";
9
10
  import {
10
11
  preprocessSingleQuotes,
@@ -47,7 +48,7 @@ const VALUED: ValuedOptionSpec[] = [
47
48
  { names: ["-p", "-printer"], key: "printer" },
48
49
  { names: ["-o", "-output"], key: "output" },
49
50
  { names: ["-a", "-aspect"], key: "aspect" },
50
- { names: ["-H", "-height"], key: "height" },
51
+ { names: ["-ht", "-height"], key: "height" },
51
52
  { names: ["-s", "-space"], key: "space" },
52
53
  { names: ["-timeout"], key: "timeout" },
53
54
  { names: ["-interval"], key: "interval" },
@@ -85,7 +86,7 @@ Options:
85
86
  -p, -printer <name> Printer queue name
86
87
  -o, -output <file> Save PNG to file instead of printing
87
88
  -a, -aspect <r> Aspect ratio width:height for HTML (e.g. 3.5:2)
88
- -H, -height <size> Text height: 12mm, .5in, or 50% (of tape height)
89
+ -ht, -height <size> Text height: 12mm, .5in, or 50% (of tape height)
89
90
  -s, -space <size> Space between segments: 12px, 1mm, .2in
90
91
  -t, -text Force input as literal text (-text <v> for segments)
91
92
  -qr <data> QR code segment
@@ -135,21 +136,51 @@ async function main(): Promise<void> {
135
136
  * Print an error with full context: message, cause chain (Node's fetch and
136
137
  * other newer APIs put the actual cause in error.cause), and stack on -v.
137
138
  */
139
+ /**
140
+ * Report an error: print a one-line summary to stderr and write the full
141
+ * cause-chain (with stacks, codes, paths) to a temp file. Avoids dumping
142
+ * walls of error text into the user's terminal. Set BROTHER_PRINT_DEBUG=1
143
+ * to also include the full chain inline.
144
+ */
138
145
  function reportError(e: any): void {
146
+ const lines: string[] = [];
147
+ lines.push(`# brother-print error report`);
148
+ lines.push(`# timestamp: ${new Date().toISOString()}`);
149
+ lines.push(`# argv: ${process.argv.join(" ")}`);
150
+ lines.push(`# cwd: ${process.cwd()}`);
151
+ lines.push(`# pid: ${process.pid}`);
152
+ lines.push("");
153
+
139
154
  let cur = e;
140
155
  let depth = 0;
141
156
  while (cur) {
142
- const prefix = depth === 0 ? "Error" : `Caused by`;
157
+ const prefix = depth === 0 ? "Error" : "Caused by";
143
158
  const name = cur.name && cur.name !== "Error" ? ` ${cur.name}` : "";
144
- const msg = cur.message ?? String(cur);
145
159
  const code = cur.code ? ` [${cur.code}]` : "";
146
- const path = cur.path ? ` (${cur.path})` : cur.input ? ` (${cur.input})` : "";
147
- console.error(`${prefix}${name}${code}: ${msg}${path}`);
160
+ const msg = cur.message ?? String(cur);
161
+ lines.push(`${prefix}${name}${code}: ${msg}`);
162
+ if (cur.path) lines.push(` path: ${cur.path}`);
163
+ if (cur.input) lines.push(` input: ${cur.input}`);
164
+ if (cur.stack) lines.push(String(cur.stack));
165
+ lines.push("");
148
166
  cur = cur.cause;
149
167
  depth++;
150
- if (depth > 5) { console.error("... (cause chain truncated)"); break; }
168
+ if (depth > 8) { lines.push("... (cause chain truncated at 8 levels)"); break; }
169
+ }
170
+
171
+ const dump = lines.join("\n");
172
+ const tempPath = path.join(os.tmpdir(), `brother-print-error-${Date.now()}-${process.pid}.log`);
173
+ let wroteFile = false;
174
+ try { fs.writeFileSync(tempPath, dump); wroteFile = true; } catch { /* fallback */ }
175
+
176
+ const topMsg = e?.message ?? String(e);
177
+ console.error(`Error: ${topMsg}`);
178
+ if (wroteFile) console.error(`Details: ${tempPath}`);
179
+ else console.error(dump);
180
+ if (process.env.BROTHER_PRINT_DEBUG) {
181
+ console.error("--- full report (BROTHER_PRINT_DEBUG enabled) ---");
182
+ console.error(dump);
151
183
  }
152
- if (process.env.DEBUG && e.stack) console.error(e.stack);
153
184
  }
154
185
 
155
186
  async function cmdList(): Promise<void> {
@@ -158,8 +189,18 @@ async function cmdList(): Promise<void> {
158
189
  console.log("No Brother printers found.");
159
190
  return;
160
191
  }
161
- console.log(`Brother printers (${printers.length}):`);
162
- for (const p of printers) {
192
+ /* Brother's listPrinters returns just { name } (legacy shape). To get
193
+ * portName/driverName for the diagnostic line, query label-core's
194
+ * coreListPrinters too. */
195
+ const { listPrinters: coreListPrinters } = await import("@bobfrankston/label-core");
196
+ const all = await coreListPrinters(/brother|^pt-|^ql-/i);
197
+ const byName = new Map(all.map(p => [p.name, p]));
198
+
199
+ const sorted = [...printers].sort((a, b) => a.name.localeCompare(b.name));
200
+ console.log(`Brother printers (${sorted.length}):`);
201
+ for (let i = 0; i < sorted.length; i++) {
202
+ const p = sorted[i];
203
+ const info = byName.get(p.name);
163
204
  let statusStr = "?";
164
205
  try {
165
206
  const s = await brotherPrinter.getStatus(p.name);
@@ -167,10 +208,36 @@ async function cmdList(): Promise<void> {
167
208
  } catch (e: any) {
168
209
  statusStr = `status error: ${e.message}`;
169
210
  }
170
- console.log(` ${p.name} ${statusStr}`);
211
+ const port = info ? shortenPort(info.portName) : "(unknown)";
212
+ const driver = info?.driverName ?? "(unknown)";
213
+ console.log(` #${i + 1} ${p.name}`);
214
+ if (info?.comment) console.log(` description: ${info.comment}`);
215
+ if (info?.location) console.log(` location: ${info.location}`);
216
+ console.log(` port: ${port}`);
217
+ if (info?.portName && info.portName !== port) {
218
+ console.log(` full port: ${info.portName}`);
219
+ }
220
+ console.log(` driver: ${driver}`);
221
+ if (info?.shareName && info.shareName !== p.name) {
222
+ console.log(` share name: ${info.shareName}`);
223
+ }
224
+ console.log(` status: ${statusStr}`);
171
225
  }
172
226
  }
173
227
 
228
+ /**
229
+ * Pull a short identifier out of a Windows printer port: "... on hostname"
230
+ * → hostname; raw IP/hostname kept as-is; USB ports kept as-is.
231
+ */
232
+ function shortenPort(portName: string): string {
233
+ if (!portName) return "(unknown)";
234
+ const onMatch = portName.match(/\bon\s+(\S+)\s*$/i);
235
+ if (onMatch) return onMatch[1];
236
+ const hostMatch = portName.match(/\b(\d{1,3}(?:\.\d{1,3}){3}|[\w-]+\.local|[\w-]+\.[\w.-]+)\b/);
237
+ if (hostMatch) return hostMatch[1];
238
+ return portName;
239
+ }
240
+
174
241
  async function cmdStatus(opts: Record<string, string | boolean>): Promise<void> {
175
242
  const name = (opts.printer as string) || undefined;
176
243
  const s = await brotherPrinter.getStatus(name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/brother-label",
3
- "version": "1.1.5",
3
+ "version": "1.1.6",
4
4
  "description": "API and CLI for printing labels on Brother P-touch printers",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -45,31 +45,20 @@
45
45
  "url": "https://github.com/BobFrankston/brother-label.git"
46
46
  },
47
47
  "dependencies": {
48
- "@bobfrankston/label-core": "^0.1.3",
49
- "jimp": "^1.6.0",
50
- "puppeteer": "^23.11.1",
51
- "qrcode": "^1.5.4"
48
+ "@bobfrankston/label-core": "^0.1.11"
52
49
  },
53
50
  "devDependencies": {
54
- "@types/node": "^25.2.1",
55
- "@types/qrcode": "^1.5.6",
56
- "typescript": "^5.0.0"
51
+ "@types/node": "^25.2.1"
57
52
  },
58
53
  "publishConfig": {
59
54
  "access": "public"
60
55
  },
61
56
  ".dependencies": {
62
- "@bobfrankston/label-core": "file:../../../utils/label-core",
63
- "jimp": "^1.6.0",
64
- "puppeteer": "^23.11.1",
65
- "qrcode": "^1.5.4"
57
+ "@bobfrankston/label-core": "file:../../../utils/label-core"
66
58
  },
67
59
  ".transformedSnapshot": {
68
60
  "dependencies": {
69
- "@bobfrankston/label-core": "^0.1.3",
70
- "jimp": "^1.6.0",
71
- "puppeteer": "^23.11.1",
72
- "qrcode": "^1.5.4"
61
+ "@bobfrankston/label-core": "^0.1.11"
73
62
  }
74
63
  }
75
64
  }