@bobfrankston/brother-label 1.1.5 → 1.1.7
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 +1 -1
- package/api.js +3 -3
- package/api.js.map +1 -1
- package/api.ts +3 -3
- package/cli.js +88 -13
- package/cli.js.map +1 -1
- package/cli.ts +78 -11
- package/package.json +5 -16
- package/probe-ql820.d.ts +2 -0
- package/probe-ql820.d.ts.map +1 -0
- package/probe-ql820.js +94 -0
- package/probe-ql820.js.map +1 -0
- package/probe-ql820.ts +102 -0
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
|
-
| `-
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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: ["-
|
|
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
|
-
-
|
|
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" :
|
|
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
|
|
127
|
-
|
|
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 >
|
|
131
|
-
|
|
150
|
+
if (depth > 8) {
|
|
151
|
+
lines.push("... (cause chain truncated at 8 levels)");
|
|
132
152
|
break;
|
|
133
153
|
}
|
|
134
154
|
}
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
145
|
-
|
|
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
|
-
|
|
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: ["-
|
|
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
|
-
-
|
|
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" :
|
|
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
|
|
147
|
-
|
|
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 >
|
|
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
|
-
|
|
162
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "1.1.7",
|
|
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.
|
|
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.
|
|
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
|
}
|
package/probe-ql820.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe-ql820.d.ts","sourceRoot":"","sources":["probe-ql820.ts"],"names":[],"mappings":""}
|
package/probe-ql820.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Probe a QL-820 over TCP 9100. Sends:
|
|
2
|
+
// 200x NUL flush command buffer
|
|
3
|
+
// ESC @ initialize
|
|
4
|
+
// ESC i a 01 switch to raster mode
|
|
5
|
+
// ESC i S status request -> returns 32-byte status block
|
|
6
|
+
// Documents what's loaded (media width, error state, model).
|
|
7
|
+
import * as net from "net";
|
|
8
|
+
const HOST = process.argv[2];
|
|
9
|
+
const PORT = 9100;
|
|
10
|
+
if (!HOST) {
|
|
11
|
+
console.error("usage: probe-ql820 <host-or-ip>");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
const FLUSH = Buffer.alloc(200, 0);
|
|
15
|
+
const INIT = Buffer.from([0x1b, 0x40]); // ESC @
|
|
16
|
+
const MODE_RASTER = Buffer.from([0x1b, 0x69, 0x61, 0x01]); // ESC i a 01
|
|
17
|
+
const STATUS_REQUEST = Buffer.from([0x1b, 0x69, 0x53]); // ESC i S
|
|
18
|
+
const sock = net.createConnection({ host: HOST, port: PORT, timeout: 15000 });
|
|
19
|
+
const chunks = [];
|
|
20
|
+
sock.on("connect", () => {
|
|
21
|
+
console.log(`connected to ${HOST}:${PORT}`);
|
|
22
|
+
sock.write(FLUSH);
|
|
23
|
+
sock.write(INIT);
|
|
24
|
+
sock.write(MODE_RASTER);
|
|
25
|
+
sock.write(STATUS_REQUEST);
|
|
26
|
+
console.log("sent: 200xNUL, ESC @, ESC i a 01, ESC i S — waiting for 32-byte reply...");
|
|
27
|
+
});
|
|
28
|
+
sock.on("data", (buf) => {
|
|
29
|
+
chunks.push(buf);
|
|
30
|
+
const total = Buffer.concat(chunks);
|
|
31
|
+
console.log(`received ${buf.length} bytes (total ${total.length})`);
|
|
32
|
+
if (total.length >= 32) {
|
|
33
|
+
decode(total.subarray(0, 32));
|
|
34
|
+
sock.end();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
sock.on("timeout", () => {
|
|
38
|
+
console.error("timeout — no 32-byte status reply");
|
|
39
|
+
if (chunks.length > 0) {
|
|
40
|
+
const t = Buffer.concat(chunks);
|
|
41
|
+
console.error(`partial: ${t.length} bytes: ${t.toString("hex")}`);
|
|
42
|
+
}
|
|
43
|
+
sock.destroy();
|
|
44
|
+
process.exit(2);
|
|
45
|
+
});
|
|
46
|
+
sock.on("error", (e) => {
|
|
47
|
+
console.error("socket error:", e.message);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
});
|
|
50
|
+
sock.on("close", () => {
|
|
51
|
+
if (chunks.length === 0)
|
|
52
|
+
console.error("closed with no data");
|
|
53
|
+
});
|
|
54
|
+
function decode(b) {
|
|
55
|
+
const modelMap = {
|
|
56
|
+
0x4f: "QL-500/550", 0x31: "QL-560", 0x32: "QL-570", 0x33: "QL-580N",
|
|
57
|
+
0x51: "QL-650TD", 0x35: "QL-700", 0x34: "QL-1050", 0x36: "QL-1060N",
|
|
58
|
+
0x37: "QL-720NW", 0x38: "QL-710W", 0x39: "QL-810W", 0x41: "QL-820NWB",
|
|
59
|
+
0x43: "QL-1100", 0x44: "QL-1110NWB", 0x45: "QL-1115NWB",
|
|
60
|
+
};
|
|
61
|
+
const mediaTypeMap = {
|
|
62
|
+
0x00: "no media", 0x0a: "continuous tape", 0x0b: "die-cut labels",
|
|
63
|
+
};
|
|
64
|
+
console.log("\n--- 32-byte status block ---");
|
|
65
|
+
console.log("hex:", (b.toString("hex").match(/../g) || []).join(" "));
|
|
66
|
+
console.log(` print head mark: 0x${b[0].toString(16)} (expect 0x80)`);
|
|
67
|
+
console.log(` size (32): ${b[1]}`);
|
|
68
|
+
console.log(` brother code 'B': 0x${b[2].toString(16)}`);
|
|
69
|
+
console.log(` series code: 0x${b[3].toString(16)}`);
|
|
70
|
+
console.log(` model code: 0x${b[4].toString(16)} -> ${modelMap[b[4]] ?? "unknown"}`);
|
|
71
|
+
console.log(` country code: 0x${b[5].toString(16)}`);
|
|
72
|
+
console.log(` battery (820): 0x${b[6].toString(16)}`);
|
|
73
|
+
console.log(` extended err: 0x${b[7].toString(16)}`);
|
|
74
|
+
console.log(` error info 1: 0x${b[8].toString(16)}`);
|
|
75
|
+
console.log(` error info 2: 0x${b[9].toString(16)}`);
|
|
76
|
+
console.log(` media width: ${b[10]} mm`);
|
|
77
|
+
console.log(` media type: 0x${b[11].toString(16)} -> ${mediaTypeMap[b[11]] ?? "?"}`);
|
|
78
|
+
console.log(` number of colors: 0x${b[12].toString(16)}`);
|
|
79
|
+
console.log(` fonts: 0x${b[13].toString(16)}`);
|
|
80
|
+
console.log(` jp font: 0x${b[14].toString(16)}`);
|
|
81
|
+
console.log(` mode: 0x${b[15].toString(16)}`);
|
|
82
|
+
console.log(` density: 0x${b[16].toString(16)}`);
|
|
83
|
+
console.log(` media length: ${b[17]} mm`);
|
|
84
|
+
console.log(` status type: 0x${b[18].toString(16)}`);
|
|
85
|
+
console.log(` phase type: 0x${b[19].toString(16)}`);
|
|
86
|
+
console.log(` phase number: ${(b[20] << 8) | b[21]}`);
|
|
87
|
+
console.log(` notification: 0x${b[22].toString(16)}`);
|
|
88
|
+
console.log(` expansion area: 0x${b[23].toString(16)}`);
|
|
89
|
+
console.log(` tape color info: 0x${b[24].toString(16)}`);
|
|
90
|
+
console.log(` text color info: 0x${b[25].toString(16)}`);
|
|
91
|
+
console.log(` hw setting: ${b.subarray(26, 30).toString("hex")}`);
|
|
92
|
+
console.log(` reserved: ${b.subarray(30, 32).toString("hex")}`);
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=probe-ql820.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe-ql820.js","sourceRoot":"","sources":["probe-ql820.ts"],"names":[],"mappings":"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","sourcesContent":["// Probe a QL-820 over TCP 9100. Sends:\n// 200x NUL flush command buffer\n// ESC @ initialize\n// ESC i a 01 switch to raster mode\n// ESC i S status request -> returns 32-byte status block\n// Documents what's loaded (media width, error state, model).\n\nimport * as net from \"net\";\n\nconst HOST = process.argv[2];\nconst PORT = 9100;\nif (!HOST) {\n console.error(\"usage: probe-ql820 <host-or-ip>\");\n process.exit(1);\n}\n\nconst FLUSH = Buffer.alloc(200, 0);\nconst INIT = Buffer.from([0x1b, 0x40]); // ESC @\nconst MODE_RASTER = Buffer.from([0x1b, 0x69, 0x61, 0x01]); // ESC i a 01\nconst STATUS_REQUEST = Buffer.from([0x1b, 0x69, 0x53]); // ESC i S\n\nconst sock = net.createConnection({ host: HOST, port: PORT, timeout: 15000 });\nconst chunks: Buffer[] = [];\n\nsock.on(\"connect\", () => {\n console.log(`connected to ${HOST}:${PORT}`);\n sock.write(FLUSH);\n sock.write(INIT);\n sock.write(MODE_RASTER);\n sock.write(STATUS_REQUEST);\n console.log(\"sent: 200xNUL, ESC @, ESC i a 01, ESC i S — waiting for 32-byte reply...\");\n});\n\nsock.on(\"data\", (buf: Buffer) => {\n chunks.push(buf);\n const total = Buffer.concat(chunks);\n console.log(`received ${buf.length} bytes (total ${total.length})`);\n if (total.length >= 32) {\n decode(total.subarray(0, 32));\n sock.end();\n }\n});\n\nsock.on(\"timeout\", () => {\n console.error(\"timeout — no 32-byte status reply\");\n if (chunks.length > 0) {\n const t = Buffer.concat(chunks);\n console.error(`partial: ${t.length} bytes: ${t.toString(\"hex\")}`);\n }\n sock.destroy();\n process.exit(2);\n});\n\nsock.on(\"error\", (e) => {\n console.error(\"socket error:\", (e as Error).message);\n process.exit(1);\n});\n\nsock.on(\"close\", () => {\n if (chunks.length === 0) console.error(\"closed with no data\");\n});\n\nfunction decode(b: Buffer): void {\n const modelMap: Record<number, string> = {\n 0x4f: \"QL-500/550\", 0x31: \"QL-560\", 0x32: \"QL-570\", 0x33: \"QL-580N\",\n 0x51: \"QL-650TD\", 0x35: \"QL-700\", 0x34: \"QL-1050\", 0x36: \"QL-1060N\",\n 0x37: \"QL-720NW\", 0x38: \"QL-710W\", 0x39: \"QL-810W\", 0x41: \"QL-820NWB\",\n 0x43: \"QL-1100\", 0x44: \"QL-1110NWB\", 0x45: \"QL-1115NWB\",\n };\n const mediaTypeMap: Record<number, string> = {\n 0x00: \"no media\", 0x0a: \"continuous tape\", 0x0b: \"die-cut labels\",\n };\n console.log(\"\\n--- 32-byte status block ---\");\n console.log(\"hex:\", (b.toString(\"hex\").match(/../g) || []).join(\" \"));\n console.log(` print head mark: 0x${b[0].toString(16)} (expect 0x80)`);\n console.log(` size (32): ${b[1]}`);\n console.log(` brother code 'B': 0x${b[2].toString(16)}`);\n console.log(` series code: 0x${b[3].toString(16)}`);\n console.log(` model code: 0x${b[4].toString(16)} -> ${modelMap[b[4]] ?? \"unknown\"}`);\n console.log(` country code: 0x${b[5].toString(16)}`);\n console.log(` battery (820): 0x${b[6].toString(16)}`);\n console.log(` extended err: 0x${b[7].toString(16)}`);\n console.log(` error info 1: 0x${b[8].toString(16)}`);\n console.log(` error info 2: 0x${b[9].toString(16)}`);\n console.log(` media width: ${b[10]} mm`);\n console.log(` media type: 0x${b[11].toString(16)} -> ${mediaTypeMap[b[11]] ?? \"?\"}`);\n console.log(` number of colors: 0x${b[12].toString(16)}`);\n console.log(` fonts: 0x${b[13].toString(16)}`);\n console.log(` jp font: 0x${b[14].toString(16)}`);\n console.log(` mode: 0x${b[15].toString(16)}`);\n console.log(` density: 0x${b[16].toString(16)}`);\n console.log(` media length: ${b[17]} mm`);\n console.log(` status type: 0x${b[18].toString(16)}`);\n console.log(` phase type: 0x${b[19].toString(16)}`);\n console.log(` phase number: ${(b[20] << 8) | b[21]}`);\n console.log(` notification: 0x${b[22].toString(16)}`);\n console.log(` expansion area: 0x${b[23].toString(16)}`);\n console.log(` tape color info: 0x${b[24].toString(16)}`);\n console.log(` text color info: 0x${b[25].toString(16)}`);\n console.log(` hw setting: ${b.subarray(26, 30).toString(\"hex\")}`);\n console.log(` reserved: ${b.subarray(30, 32).toString(\"hex\")}`);\n}\n"]}
|
package/probe-ql820.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Probe a QL-820 over TCP 9100. Sends:
|
|
2
|
+
// 200x NUL flush command buffer
|
|
3
|
+
// ESC @ initialize
|
|
4
|
+
// ESC i a 01 switch to raster mode
|
|
5
|
+
// ESC i S status request -> returns 32-byte status block
|
|
6
|
+
// Documents what's loaded (media width, error state, model).
|
|
7
|
+
|
|
8
|
+
import * as net from "net";
|
|
9
|
+
|
|
10
|
+
const HOST = process.argv[2];
|
|
11
|
+
const PORT = 9100;
|
|
12
|
+
if (!HOST) {
|
|
13
|
+
console.error("usage: probe-ql820 <host-or-ip>");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const FLUSH = Buffer.alloc(200, 0);
|
|
18
|
+
const INIT = Buffer.from([0x1b, 0x40]); // ESC @
|
|
19
|
+
const MODE_RASTER = Buffer.from([0x1b, 0x69, 0x61, 0x01]); // ESC i a 01
|
|
20
|
+
const STATUS_REQUEST = Buffer.from([0x1b, 0x69, 0x53]); // ESC i S
|
|
21
|
+
|
|
22
|
+
const sock = net.createConnection({ host: HOST, port: PORT, timeout: 15000 });
|
|
23
|
+
const chunks: Buffer[] = [];
|
|
24
|
+
|
|
25
|
+
sock.on("connect", () => {
|
|
26
|
+
console.log(`connected to ${HOST}:${PORT}`);
|
|
27
|
+
sock.write(FLUSH);
|
|
28
|
+
sock.write(INIT);
|
|
29
|
+
sock.write(MODE_RASTER);
|
|
30
|
+
sock.write(STATUS_REQUEST);
|
|
31
|
+
console.log("sent: 200xNUL, ESC @, ESC i a 01, ESC i S — waiting for 32-byte reply...");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
sock.on("data", (buf: Buffer) => {
|
|
35
|
+
chunks.push(buf);
|
|
36
|
+
const total = Buffer.concat(chunks);
|
|
37
|
+
console.log(`received ${buf.length} bytes (total ${total.length})`);
|
|
38
|
+
if (total.length >= 32) {
|
|
39
|
+
decode(total.subarray(0, 32));
|
|
40
|
+
sock.end();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
sock.on("timeout", () => {
|
|
45
|
+
console.error("timeout — no 32-byte status reply");
|
|
46
|
+
if (chunks.length > 0) {
|
|
47
|
+
const t = Buffer.concat(chunks);
|
|
48
|
+
console.error(`partial: ${t.length} bytes: ${t.toString("hex")}`);
|
|
49
|
+
}
|
|
50
|
+
sock.destroy();
|
|
51
|
+
process.exit(2);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
sock.on("error", (e) => {
|
|
55
|
+
console.error("socket error:", (e as Error).message);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
sock.on("close", () => {
|
|
60
|
+
if (chunks.length === 0) console.error("closed with no data");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function decode(b: Buffer): void {
|
|
64
|
+
const modelMap: Record<number, string> = {
|
|
65
|
+
0x4f: "QL-500/550", 0x31: "QL-560", 0x32: "QL-570", 0x33: "QL-580N",
|
|
66
|
+
0x51: "QL-650TD", 0x35: "QL-700", 0x34: "QL-1050", 0x36: "QL-1060N",
|
|
67
|
+
0x37: "QL-720NW", 0x38: "QL-710W", 0x39: "QL-810W", 0x41: "QL-820NWB",
|
|
68
|
+
0x43: "QL-1100", 0x44: "QL-1110NWB", 0x45: "QL-1115NWB",
|
|
69
|
+
};
|
|
70
|
+
const mediaTypeMap: Record<number, string> = {
|
|
71
|
+
0x00: "no media", 0x0a: "continuous tape", 0x0b: "die-cut labels",
|
|
72
|
+
};
|
|
73
|
+
console.log("\n--- 32-byte status block ---");
|
|
74
|
+
console.log("hex:", (b.toString("hex").match(/../g) || []).join(" "));
|
|
75
|
+
console.log(` print head mark: 0x${b[0].toString(16)} (expect 0x80)`);
|
|
76
|
+
console.log(` size (32): ${b[1]}`);
|
|
77
|
+
console.log(` brother code 'B': 0x${b[2].toString(16)}`);
|
|
78
|
+
console.log(` series code: 0x${b[3].toString(16)}`);
|
|
79
|
+
console.log(` model code: 0x${b[4].toString(16)} -> ${modelMap[b[4]] ?? "unknown"}`);
|
|
80
|
+
console.log(` country code: 0x${b[5].toString(16)}`);
|
|
81
|
+
console.log(` battery (820): 0x${b[6].toString(16)}`);
|
|
82
|
+
console.log(` extended err: 0x${b[7].toString(16)}`);
|
|
83
|
+
console.log(` error info 1: 0x${b[8].toString(16)}`);
|
|
84
|
+
console.log(` error info 2: 0x${b[9].toString(16)}`);
|
|
85
|
+
console.log(` media width: ${b[10]} mm`);
|
|
86
|
+
console.log(` media type: 0x${b[11].toString(16)} -> ${mediaTypeMap[b[11]] ?? "?"}`);
|
|
87
|
+
console.log(` number of colors: 0x${b[12].toString(16)}`);
|
|
88
|
+
console.log(` fonts: 0x${b[13].toString(16)}`);
|
|
89
|
+
console.log(` jp font: 0x${b[14].toString(16)}`);
|
|
90
|
+
console.log(` mode: 0x${b[15].toString(16)}`);
|
|
91
|
+
console.log(` density: 0x${b[16].toString(16)}`);
|
|
92
|
+
console.log(` media length: ${b[17]} mm`);
|
|
93
|
+
console.log(` status type: 0x${b[18].toString(16)}`);
|
|
94
|
+
console.log(` phase type: 0x${b[19].toString(16)}`);
|
|
95
|
+
console.log(` phase number: ${(b[20] << 8) | b[21]}`);
|
|
96
|
+
console.log(` notification: 0x${b[22].toString(16)}`);
|
|
97
|
+
console.log(` expansion area: 0x${b[23].toString(16)}`);
|
|
98
|
+
console.log(` tape color info: 0x${b[24].toString(16)}`);
|
|
99
|
+
console.log(` text color info: 0x${b[25].toString(16)}`);
|
|
100
|
+
console.log(` hw setting: ${b.subarray(26, 30).toString("hex")}`);
|
|
101
|
+
console.log(` reserved: ${b.subarray(30, 32).toString("hex")}`);
|
|
102
|
+
}
|