beastprint-sdk
v0.1.8
Published
Unified legacy browser printing and BeastPrint cloud printing.
Maintainers
Readme
beastprint-sdk
Unified web printing for:
- BeastPrint cloud printing (template or HTML)
- Printdesk‑style local printing (HTML to a local agent)
- Legacy browser printing (
window.print, iframe, popup)
The recommended way to use it is:
strategy: 'auto'→ BeastPrint → Printdesk → Legacy
so you configure one call and the SDK picks the best available path.
Quick start: strategy: 'auto'
These are the three most common setup patterns:
- Auto with a BeastPrint template (recommended if you have Beast templates).
- Auto with shared HTML.
- Auto with a shared URL.
1. Auto with a BeastPrint template (recommended)
Use this if you have a BeastPrint printer + template and want Printdesk/Legacy as fallback.
import { print } from 'beastprint-sdk';
await print({
strategy: 'auto',
// Optional shared URL that Legacy/Printdesk can fall back to
url: '/test/print', // or 'https://example.com/printable-receipt'
beast: {
// Template mode – primary signal for BeastPrint
templateId: 'default-receipt',
widthMm: 80,
data: {
store: {
name: 'My Store',
address: 'Milk street 4',
phone: '+4580808080',
},
order: {
number: 123,
date: '2025-08-12 12:05',
staff: 'Hanne',
},
},
printer: {
key: 'YOUR_BEAST_PRINTER_KEY', // required
profileKey: 'epson-tm-m30ii', // optional
},
},
// Optional: Printdesk as second priority (local agent)
printdesk: {
// No html/url here; auto will use template or shared html/url when needed
pdfOptions: {
// These override internal defaults field-by-field
pageSize: { width: '58000' }, // keep default height "90000", override width
copies: 1,
},
printer: {
// Only name is really needed for your agent; others are optional
name: 'EPSON_TM-m30II',
// id / description / status can be added if your agent needs them
},
},
// Optional: Legacy as last fallback (browser print)
legacy: {
pageWidthMm: 80,
marginMm: 0,
hideAppChrome: true,
},
});Runtime behavior:
BeastPrint
- Uses
beast.templateId,beast.data, andbeast.printer. - If it fails or isn’t configured, auto logs and moves on.
- Uses
Printdesk
- If it has no own
html/url, auto renders the Beast template viahttps://print.beastscan.com/render/htmland uses that HTML. - Sends to
printdesk.localUrl(defaulthttp://127.0.0.1:43594/print) with payload:{ "payload": { "html": "<html>…rendered template…</html>", "pdfOptions": { "...merged defaults + overrides..." }, "printer": { "name": "EPSON_TM-m30II" } } }
- If it has no own
Legacy
- If needed, renders the same template to HTML and prints via iframe/popup.
2. Auto with shared HTML
Use this if your app already has the complete HTML.
import { print } from 'beastprint-sdk';
await print({
strategy: 'auto',
// Shared HTML, available to all strategies
html: `
<html>
<body style="font-family: system-ui, sans-serif;">
<h1>Shared HTML receipt</h1>
<p>This HTML can be reused by BeastPrint, Printdesk, and Legacy.</p>
</body>
</html>
`,
// Beast: HTML mode (no templateId) – mode will be inferred as 'html'
beast: {
widthMm: 80,
printer: {
key: 'YOUR_BEAST_PRINTER_KEY',
profileKey: 'epson-tm-m30ii',
},
// beast.html is optional; auto injects shared html when mode is html
},
// Printdesk: auto will inject shared html into printdesk.html if empty
printdesk: {
pdfOptions: {
copies: 1,
},
printer: {
name: 'EPSON_TM-m30II',
},
},
legacy: {
pageWidthMm: 80,
marginMm: 0,
hideAppChrome: true,
},
});Behavior:
- BeastPrint
- No
templateId, but html present → auto uses HTML mode and sends the shared HTML to Beast.
- No
- Printdesk
- If Beast is not used / fails, auto sets
printdesk.htmlfrom shared HTML and sends it.
- If Beast is not used / fails, auto sets
- Legacy
- As a final fallback, prints the same HTML via iframe/popup.
3. Auto with shared URL
Use this if you already have a hosted “printable” page.
import { print } from 'beastprint-sdk';
await print({
strategy: 'auto',
// Shared URL that returns printable HTML
url: 'https://example.com/receipt/123',
// BeastPrint: HTML mode via URL – auto injects shared url into beast.url
beast: {
widthMm: 80,
printer: {
key: 'YOUR_BEAST_PRINTER_KEY',
profileKey: 'epson-tm-m30ii',
},
// beast.url can be omitted; auto will set beast.url = options.url
},
// Printdesk: will use html/url from its own fields or shared url
printdesk: {
// printdesk.url can be omitted; auto will set it from options.url if needed
pdfOptions: {
copies: 1,
},
printer: {
name: 'EPSON_TM-m30II',
},
},
// Legacy: URL-based browser printing as last fallback
legacy: {
// If everything else fails, legacy will open/print this URL (popup/iframe)
hideAppChrome: true,
},
});Behavior:
- BeastPrint
beast.urlcomes fromoptions.url; Beast fetches and prints as HTML.
- Printdesk
- If it needs HTML and has none, it fetches the same URL to get HTML.
- Legacy
- If needed, opens the URL in an iframe or popup and triggers
window.print().
- If needed, opens the URL in an iframe or popup and triggers
Installation
npm install beastprint-sdk
# or
yarn add beastprint-sdk
# or
pnpm add beastprint-sdkAPI overview
print(options?: PrintOptions): Promise<void>
Top-level function that routes print jobs to:
- BeastPrint (cloud API)
- Printdesk (local agent)
- Legacy (browser)
Types
export type LegacyPrintOptions = {
html?: string; // raw HTML string to print
url?: string; // URL to open and print
// Page / print CSS size control
pageWidthMm?: number; // e.g. 80 for 80mm receipt paper
pageHeightMm?: number; // optional; if omitted, browser paginates
marginMm?: number; // uniform margin in mm (default 0)
hideAppChrome?: boolean; // hide header/footer/nav etc in print
// Popup-style printing (alternative to iframe)
popup?: boolean; // if true, open new window instead of iframe
popupWidthPx?: number; // popup window width in pixels
popupHeightPx?: number; // popup window height in pixels
// Load URL into a hidden iframe and print, instead of opening popup
urlInIframe?: boolean;
};
export type BeastPrintPrinter = {
key: string;
profileKey?: string;
};
export type BeastPrintOptions = {
mode?: 'template' | 'html'; // auto-inferred if not set
templateId?: string;
widthMm?: number;
data?: Record<string, any>;
printer?: BeastPrintPrinter;
html?: string; // used when mode === 'html'
url?: string; // URL to fetch HTML from when mode === 'html'
};
export type PrintdeskPdfOptions = {
margins?: {
marginType?: number;
};
pageSize?: {
height?: string;
width?: string;
};
color?: boolean;
copies?: number;
scaleFactor?: string;
landscape?: boolean;
dpi?: string;
};
export type PrintdeskPrinter = {
name: string;
description?: string;
id?: string;
status?: string;
};
export type PrintdeskOptions = {
/**
* Raw HTML string to send to the local Printdesk service.
* If not provided, URL-based fetching will be used.
*/
html?: string;
/**
* URL to fetch HTML from. Used if html is not provided.
* If not set here, the shared top-level url will be used as a fallback.
*/
url?: string;
/**
* URL of the local Printdesk endpoint.
* Defaults to 'http://127.0.0.1:43594/print'.
*/
localUrl?: string;
/**
* Optional PDF options forwarded to the Printdesk agent.
* These override the built‑in defaults on a per-field basis.
*/
pdfOptions?: PrintdeskPdfOptions;
/**
* Optional printer selection for the agent.
* If omitted, the agent's own default printer is used.
*/
printer?: PrintdeskPrinter;
};
export type PrintStrategy = 'auto' | 'legacy' | 'beast' | 'printdesk';
export type PrintOptions = {
strategy?: PrintStrategy;
legacy?: LegacyPrintOptions;
beast?: BeastPrintOptions;
printdesk?: PrintdeskOptions;
/**
* Top-level HTML payload that can be reused by multiple strategies.
* For example:
* - used as legacy.html if legacy.html is not provided
* - used as beast.html when beast.mode === 'html' and beast.html is not provided
*/
html?: string;
/**
* Top-level URL payload that can be reused by multiple strategies.
* For example, used as legacy.url if legacy.url is not provided.
*/
url?: string;
/**
* Enable debug logging only for this call.
* Overrides the global configureDebug() setting for this invocation.
*/
debug?: boolean;
/**
* If true, non-legacy strategies (beast, printdesk, auto) will fall back to
* legacy printing instead of throwing, when possible.
* (Explicit 'legacy' strategy is never affected.)
*/
fallbackToLegacyOnError?: boolean;
};How strategy: 'auto' works (details)
High-level, auto tries:
BeastPrint → Printdesk → Legacy
using these priorities.
BeastPrint (first priority)
Configured if:
beast.printer.keyis a non-empty string.
Priority:
If
beast.templateIdis set:- Template mode (regardless of
mode): sends:{ "mode": "template", "templateId": "...", "widthMm": 80, "data": { "...data..." }, "printer": { "key": "...", "profileKey": "..." } }
- Template mode (regardless of
Else, HTML mode:
modeis auto-chosen if not set:- If
htmlorurlexists →'html' - Otherwise
'template'(and fails withouttemplateId).
- If
- In HTML mode:
beast.html(or sharedhtmlinjected earlier).beast.url(or sharedurlinjected earlier), fetched as HTML.
- Sends:
{ "mode": "html", "content": "<!doctype html>..." }
If BeastPrint fails, auto logs and continues to Printdesk.
Printdesk (second priority)
Configuration sources in auto:
printdesk.htmlprintdesk.urlbeast.templateId→ rendered to HTML via Beast/render/html- shared
html(options.html) - shared
url(options.url)
In auto, when Printdesk is considered usable, it fills printdeskOpts like:
- Prefer existing
printdesk.html. - Else existing
printdesk.url(or sharedurlalready injected). - If still no html and Beast has template:
- Render template to HTML and set
printdesk.html.
- Render template to HTML and set
- If still no html and shared
htmlexists:- Set
printdesk.html = sharedHtml.
- Set
- If still no url and shared
urlexists:- Set
printdesk.url = sharedUrl.
- Set
printdeskPrint then:
Uses
options.htmlif present.Else fetches
options.urlas HTML.Merges
pdfOptionswith defaults:const defaultPdfOptions: PrintdeskPdfOptions = { margins: { marginType: 0 }, pageSize: { height: '90000', width: '90000' }, color: false, copies: 1, scaleFactor: '100', landscape: false, dpi: '300', };Sends to
localUrl(defaulthttp://127.0.0.1:43594/print) as:{ "payload": { "html": "<html>…</html>", "pdfOptions": { "...merged..." }, "printer": { "name": "EPSON_TM-m30II" } } }
If Printdesk fails, auto logs and continues to Legacy.
Legacy (third priority)
Configuration sources:
legacy.htmllegacy.urlbeast.templateId→ rendered to HTML ifhtmlis missing- shared
html(options.html) - shared
url(options.url)
In auto:
- If
legacyis present or shared html/url exists, it buildslegacyOpts:- Fill
htmlfromlegacy.htmlor sharedhtml. - Fill
urlfromlegacy.urlor sharedurl.
- Fill
- If no
legacy.htmland Beast has template:- Render template HTML into
legacyOpts.html.
- Render template HTML into
legacyPrint then prefers:
- HTML printing (iframe or popup) if
htmlis present. - Else URL printing:
- popup vs iframe based on
popupand same-origin checks.
- popup vs iframe based on
If none of Beast/Printdesk/Legacy is usable, auto throws an error explaining that no usable configuration was found.
Debug logging
Enable global debug logs:
import { print, configureDebug } from 'beastprint-sdk';
configureDebug({ enabled: true });
await print({ strategy: 'auto', /* ... */ });Or per-call:
await print({ strategy: 'auto', debug: true, /* ... */ });Logs show the decision flow, for example:
[beastprint:debug] print called { strategy: 'auto', ... }
[beastprint:debug] auto: beast configuration check { hasBeastConfig: true, ... }
[beastprint:debug] auto → trying BeastPrint first
[beastprint:debug] auto → BeastPrint failed ...
[beastprint:debug] auto: printdesk configuration check { hasPrintdeskConfig: true, ... }
[beastprint:debug] auto → trying Printdesk next
[beastprint:debug] auto → Printdesk succeededOther usage modes
You can still call the explicit strategies directly:
strategy: 'legacy'– only browser printing.strategy: 'beast'– BeastPrint only.strategy: 'printdesk'– local agent only.
The test harness (test/index.html) contains working examples of these explicit modes.
Development
npm install
npm run build
npm run test:server
# then open http://localhost:3000/test/index.htmlLicense
MIT © Michael Holm
