npm package: @inteli.city/node-red-contrib-latex-pdf
Description: A Node-RED node that renders LaTeX using Nunjucks and compiles it to PDF using Tectonic.
Latest version: 1.0.0

# node-red-contrib-latex-pdf

A Node-RED node that renders LaTeX using Nunjucks and compiles it to PDF using Tectonic.

## Table of Contents

- [Overview](#overview)
- [When to Use](#when-to-use)
- [Mental Model](#mental-model)
- [Contract](#contract)
- [Installation](#installation)
- [How It Works](#how-it-works)
- [Template Context](#template-context)
- [Rendering Data](#rendering-data)
- [Inline Assets (asset helper)](#inline-assets-asset-helper)
- [Error Handling](#error-handling)
- [Queue / Concurrency](#queue--concurrency)
- [Examples](#examples)
- [Limitations](#limitations)

---

## Overview

This node renders a Nunjucks template into a LaTeX document and compiles it to PDF using Tectonic.

The result is a PDF `Buffer` in `msg.payload`.

**Requirements:** Tectonic must be installed and available in `PATH`.

Install Tectonic: https://tectonic-typesetting.github.io/en-US/install.html

---

## When to Use

Use this node when you need:
- dynamic PDF generation
- structured reports (logs, invoices, summaries)
- embedding binary data (images, diagrams) into documents

Do **not** use this node for:
- simple text formatting (use the built-in template node)
- high-frequency, low-latency flows (PDF compilation is expensive)
- very large documents (Tectonic runs per message)

---

## Mental Model

This node executes a template as a document generation program.

- `payload` → input data
- template → logic + layout
- `asset()` → converts Buffers into files for LaTeX

Think of it as:

```
data → template → files → PDF
```

The template controls rendering. The node does not transform data implicitly.

---

## Contract

**The node expects:**
- `msg.payload` — any data (including Buffers)
- A valid Nunjucks template that produces valid LaTeX after rendering
- No external file inputs — all files must be created via `asset()`

**The node guarantees:**
- PDF output as a `Buffer` in `msg.payload`
- Isolated execution per message (temporary directory)
- Cleanup of all temporary files after execution

**The node will fail if:**
- The template uses `msg.*` syntax
- `asset()` receives a non-Buffer value
- LaTeX compilation fails (Tectonic error)

---

## Installation

```bash
cd ~/.node-red
npm install node-red-contrib-latex-pdf
```

---

## How It Works

```
Nunjucks template → LaTeX → Tectonic → PDF → msg.payload
```

Each message is processed in an isolated temporary directory. All files (`.tex`, assets, output `.pdf`) are deleted after compilation.

---

## Template Context

Message properties are exposed at the root of the template context. Reference them directly — do **not** use `msg.*`.

| Variable | Value |
|---|---|
| `{{ payload }}` | `msg.payload` |
| `{{ topic }}` | `msg.topic` |
| `{{ flow.get("key") }}` | Flow context variable |
| `{{ global.get("key") }}` | Global context variable |
| `{{ env.MY_VAR }}` | OS environment variable |

> Using `msg.` inside a template triggers a node error. Use `{{ payload }}` style instead.

---

## Rendering Data

`msg.payload` is passed to the template as-is — no automatic stringification.

To render objects as text, use the `dump` filter:

```latex
{{ payload | dump }}
```

This is required to preserve Buffers and binary data. Passing a raw object to LaTeX without `dump` will render as `[object Object]`.

---

## Inline Assets (asset helper)

`asset()` is the only supported way to embed files. It writes a Buffer to a temporary file and returns the filename for LaTeX to reference:

```latex
\includegraphics{ {{ asset(payload.image, "png") }} }
```

Each call generates a unique filename (`asset-0.png`, `asset-1.png`, …).

Loops are supported:

```latex
{% for img in payload.images %}
\includegraphics{ {{ asset(img, "png") }} }
{% endfor %}
```

**Constraints:**
- First argument must be a `Buffer` — anything else throws an error
- Extension is sanitized (alphanumeric only); defaults to `bin`
- Files are not persisted after execution

---

## Error Handling

The node fails fast on invalid input. Errors are reported via `node.error()` and attached to `msg.error`.

| Situation | Error message |
|---|---|
| Template uses `msg.*` | `Use {{ payload }} style, not {{ msg.* }}.` |
| `asset()` receives non-Buffer | `asset() expects a Buffer` |
| Tectonic compilation fails | Tectonic stderr output |

The queue continues processing subsequent messages after a failure.

---

## Queue / Concurrency

The node processes messages using a FIFO queue with configurable concurrency.

Set the **Queue** field in the node editor to control how many compilations can run in parallel. Default is `1` (fully sequential).

Status format:

```
<queued> (<running>/<max>)
```

Examples:

```
0 (0/1)   → idle
0 (1/1)   → one compiling
3 (5/5)   → saturated, 3 waiting
```

---

## Examples

### Basic — render text payload

```latex
\documentclass{article}
\begin{document}
{{ payload | dump }}
\end{document}
```

### Report with image

```latex
\documentclass{article}
\usepackage{graphicx}
\begin{document}

\section*{ {{ payload.title }} }

{{ payload.description }}

\includegraphics{ {{ asset(payload.image, "png") }} }

\end{document}
```

### Multiple images

```latex
\documentclass{article}
\usepackage{graphicx}
\begin{document}
{% for img in payload.images %}
\includegraphics{ {{ asset(img, "png") }} }
{% endfor %}
\end{document}
```

---

## Limitations

Templates are rendered from a single string. The following Nunjucks features are not supported:

- `{% include "file.njk" %}`
- `{% extends "base.njk" %}`
- `{% import "macros.njk" %}`

Templates must be self-contained. Macros can be defined and used within a single template.

- Files must be provided as Buffers inside the template via `asset()`

Full Nunjucks documentation (not all features are supported):
https://mozilla.github.io/nunjucks/templating.html