@bobfrankston/label-core
v0.1.11
Published
Shared rendering, CLI, and printer-handling primitives for label printers (used by brother-label and dymo-print)
Maintainers
Readme
@bobfrankston/label-core
Shared printer-agnostic primitives for label printers. Used by:
@bobfrankston/brother-label— Brother P-touch (continuous tape)@bobfrankston/dymo-print— DYMO LabelWriter (die-cut labels)
This package is a library, not a CLI. It exports the LabelPrinter interface, content-rendering primitives (text, QR, HTML), Windows printer-status helpers, clipboard accessors, and the CLI argument-parsing primitives both drivers share.
Why a single core?
Brother and Dymo printers use very different drivers, paper systems, and OS plumbing — but the user-facing surface is nearly identical: render some text/HTML/QR/image to a bitmap and send it to a printer. By extracting the shared parts here, both drivers get the same behavior and bug fixes for free, and consumers can program against one interface (LabelPrinter) and switch drivers without code changes.
Installation
npm install @bobfrankston/label-coreYou usually don't install this directly — install the driver package for your printer (brother-label or dymo-print), which depends on this.
The unified interface
Every driver exports a singleton implementing this:
interface LabelPrinter {
readonly driverName: string;
render(opts: PrintOptions): Promise<Buffer>;
print(opts: PrintOptions): Promise<PrintResult>;
renderSegments(segments: Segment[], opts?: SegmentOptions): Promise<Buffer>;
printSegments(segments: Segment[], opts?: SegmentOptions): Promise<PrintResult>;
listPrinters(): Promise<PrinterInfo[]>;
getStatus(printerName?: string): Promise<PrinterStatus>;
waitOnline(printerName?: string, opts?: WaitOptions): Promise<PrinterStatus>;
listMedia(): MediaInfo[];
getMedia(id: string): MediaInfo;
detectMedia(printerName?: string): Promise<MediaInfo>;
getConfig(): PrinterConfig;
setConfig(config: Partial<PrinterConfig>): void;
getConfigPath(): string;
}Cross-driver example:
import type { LabelPrinter } from "@bobfrankston/label-core";
import { brotherPrinter } from "@bobfrankston/brother-label";
import { dymoPrinter } from "@bobfrankston/dymo-print";
async function printOnEither(p: LabelPrinter) {
await p.print({ text: "Hello world", media: "12" }); // 12mm tape on Brother, label 12 on Dymo
}
await printOnEither(brotherPrinter);
await printOnEither(dymoPrinter);What's in here
| Module | Exports | Purpose |
|---|---|---|
| types.ts | LabelPrinter, PrintOptions, PrinterStatus, MediaInfo, etc. | The unified interface and shared types |
| render.ts | renderHtmlString, renderHtmlFile, renderHtmlUrl, closeBrowser | Puppeteer HTML→PNG with <img qr="..."> inlining |
| segments.ts | renderText, renderQr, renderSegments | Jimp text/QR rendering, side-by-side composition |
| content.ts | resolveContent, validateContent, mmToPx, pxToMm | Dispatch PrintOptions to a PNG buffer |
| clipboard.ts | getClipboard, getClipboardText, getClipboardImage | Windows clipboard via PowerShell |
| printer.ts | getPrinterStatus, listPrinters, waitOnline, listPrinterStatuses | Windows print queue status & online wait |
| parse.ts | parseSize, parseTextHeight, parseAspect, preprocessSingleQuotes, parseArgs | CLI primitives |
| powershell.ts | runPowerShell, runPowerShellOrThrow | Spawn-based PS invocation (uses -EncodedCommand to sidestep quoting) |
| config.ts | readJsonConfig, writeJsonConfig, mergeJsonConfig | File-backed JSON config |
Library conventions
- No
console.*output. Errors throw. Diagnostic messages go through an injectedlog: (msg: string) => voidcallback (seePrintOptions.log,WaitOptions.log). - Windows-only currently (PowerShell + WMI under the hood).
- Spawn with arg arrays, never
exec— handles paths/names with spaces. - All input sizing accepts
12px,1mm,.2in,50%.
Offline waiting
The most common Dymo gripe ("printer is asleep, jobs vanish") is handled at the core level:
import { waitOnline, getPrinterStatus } from "@bobfrankston/label-core";
const status = await getPrinterStatus("DymoBlack");
if (!status.online) {
await waitOnline("DymoBlack", {
timeoutMs: 60_000,
intervalMs: 2_000,
onWaiting: (s, elapsed, alts) => {
console.log(`Still waiting (${s.statusText}); ${elapsed/1000}s elapsed`);
if (alts.length) console.log(`Alternatives online now: ${alts.map(a => a.name).join(", ")}`);
},
});
}The driver wrappers call this automatically when you print() — set wait: false in PrintOptions to opt out.
Clipboard
import { getClipboard } from "@bobfrankston/label-core";
const c = await getClipboard();
if (c.kind === "image") {
// c.image is a Buffer (PNG)
} else if (c.kind === "text") {
console.log(c.text);
} else {
console.log("Clipboard is empty");
}License
MIT
