@ulvio/utilities
v0.2.0
Published
Official TypeScript SDK for the Ulvio Utilities service (MJML, LiquidJS, Markdown, image transform).
Readme
@ulvio/utilities
Official TypeScript SDK for the standalone Ulvio Utilities service — MJML compilation, LiquidJS template rendering, Markdown-to-HTML conversion, and image transformation.
This is a thin, direct client for the Utilities HTTP service (the endpoints under /api/*). The service has no authentication, so the SDK only needs a baseUrl. Requests and responses are validated at runtime with zod.
Talking to the Ulvio platform instead of a standalone service? Use
@ulvio/client, whose.utilitiessub-client proxies these same operations through the gateway with an API key.
Install
npm install @ulvio/utilitiesRequires Node.js 24+.
Usage
import { Utilities } from '@ulvio/utilities';
const utilities = new Utilities({ baseUrl: 'http://localhost:3002' });
// MJML → HTML
const { html, errors } = await utilities.compileMjml({
mjml: '<mjml><mj-body><mj-text>Hi</mj-text></mj-body></mjml>',
options: { minify: true },
});
// Liquid render + variable extraction
const rendered = await utilities.renderLiquid({ template: 'Hi {{ name }}', data: { name: 'Ada' } });
const { variables } = await utilities.extractLiquidVariables({ template: 'Hi {{ name }}' });
// Markdown → HTML
const md = await utilities.renderMarkdown({ markdown: '# Title' });
// Combined: Liquid interpolation → MJML compile, in one call
const email = await utilities.renderEmail({
mjml: '<mjml><mj-body><mj-text>Hi {{ name }}</mj-text></mj-body></mjml>',
data: { name: 'Ada' },
});Image transform (streaming)
POST /api/image/transform streams progress over Server-Sent Events. transformImage drives that stream, forwards progress to optional callbacks, and resolves with the final result.
const result = await utilities.transformImage(
{
source: { url: 'https://cdn.example.com/img.jpg' }, // or { base64: '...' }
outputMode: 'base64', // or 'upload'
variants: [
{ name: 'thumbnail', resize: { width: 400 }, format: { type: 'avif', quality: 70 } },
],
},
{
onQueued: ({ position }) => console.log('queued at', position),
onProcessing: ({ step, progress }) => console.log(step, `${progress}%`),
},
);
// base64 mode → each variant has { name, contentType, bytes, width, height, base64 }
// upload mode → each variant has { name, contentType, bytes, width, height, uploaded: true }
// (in 'upload' mode, give every variant a presigned `uploadUrl`)PDF preview (streaming)
POST /api/pdf/preview renders the first page of a PDF into a preview image, streaming progress the same way. The default 1600 px width is deliberately generous, so you can crop the result (e.g. show only the top of the page) without upscaling.
const preview = await utilities.previewPdf(
{
source: { base64: pdfBase64 }, // or { url: 'https://…/doc.pdf' } (presigned GET is fine)
outputMode: 'base64', // or 'upload' with a presigned `uploadUrl`
width: 1600, // 64–4000, default 1600
format: { type: 'png' }, // png | jpeg | webp (+ optional quality)
},
{ onProcessing: ({ step, progress }) => console.log(step, `${progress}%`) },
);
// base64 mode → { contentType, bytes, width, height, pageCount, base64 }
// upload mode → { contentType, bytes, width, height, pageCount, uploaded: true }Sources are capped at 50 MB, and the service renders in a recyclable worker process — a corrupt or pathological document fails this call, not the service.
Errors
Every failure is a UtilitiesError with a stable string code, the HTTP status (when the service responded), and the parsed error response:
import { UtilitiesError, NOT_CONFIGURED_CODE } from '@ulvio/utilities';
try {
await utilities.compileMjml({ mjml: '' });
} catch (err) {
if (err instanceof UtilitiesError) {
console.error(err.code, err.status, err.message);
}
}code is not_configured (missing baseUrl), network_error (fetch failed), or a status-derived code such as bad_request / server_error. Streaming failures surface as image_transform_failed / pdf_preview_failed (error event) or truncated (stream ended early).
API
| Method | Endpoint |
| --- | --- |
| health() | GET /api/health |
| compileMjml(req) | POST /api/mjml/compile |
| renderLiquid(req) | POST /api/liquidjs/render |
| extractLiquidVariables(req) | POST /api/liquidjs/variables |
| renderMarkdown(req) | POST /api/markdown/render |
| renderEmail(req) | POST /api/render-email |
| transformImage(req, callbacks?) | POST /api/image/transform (SSE) |
| previewPdf(req, callbacks?) | POST /api/pdf/preview (SSE) |
All request/response types are exported (MjmlCompileRequest, ImageTransformResponse, …).
License
UNLICENSED — internal Ulvio package.
