@lupinum/nuxt-pdf 0.4.0-beta.4 → 0.4.0-beta.6

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/CONFORMANCE.md +4 -4
  3. package/README.md +54 -12
  4. package/dist/agent/AGENTS.md +44 -0
  5. package/dist/agent/pages/docs/examples/supported-behavior.md +75 -0
  6. package/dist/agent/pages/docs/examples.md +163 -0
  7. package/dist/agent/pages/docs/getting-started/installation.md +75 -0
  8. package/dist/agent/pages/docs/getting-started/quickstart.md +126 -0
  9. package/dist/agent/pages/docs/getting-started.md +63 -0
  10. package/dist/agent/pages/docs/guides/contents-links-bookmarks.md +123 -0
  11. package/dist/agent/pages/docs/guides/deployment.md +118 -0
  12. package/dist/agent/pages/docs/guides/errors-and-debugging.md +90 -0
  13. package/dist/agent/pages/docs/guides/images-and-fonts.md +102 -0
  14. package/dist/agent/pages/docs/guides/recipes.md +258 -0
  15. package/dist/agent/pages/docs/guides/remote-images.md +72 -0
  16. package/dist/agent/pages/docs/guides/reusable-components.md +81 -0
  17. package/dist/agent/pages/docs/guides/standalone-node.md +107 -0
  18. package/dist/agent/pages/docs/guides/svg-graphics.md +165 -0
  19. package/dist/agent/pages/docs/guides/testing.md +119 -0
  20. package/dist/agent/pages/docs/learn/document-tree.md +91 -0
  21. package/dist/agent/pages/docs/learn/runtime-and-data.md +63 -0
  22. package/dist/agent/pages/docs/learn/styling-and-layout.md +79 -0
  23. package/dist/agent/pages/docs/learn/templates-and-registry.md +96 -0
  24. package/dist/agent/pages/docs/reference/composables.md +55 -0
  25. package/dist/agent/pages/docs/reference/define-pdf.md +96 -0
  26. package/dist/agent/pages/docs/reference/errors-and-limits.md +89 -0
  27. package/dist/agent/pages/docs/reference/module-options.md +104 -0
  28. package/dist/agent/pages/docs/reference/page-sizes.md +54 -0
  29. package/dist/agent/pages/docs/reference/primitives.md +216 -0
  30. package/dist/agent/pages/docs/reference/registry.md +185 -0
  31. package/dist/agent/pages/docs/reference/standalone.md +53 -0
  32. package/dist/agent/pages/docs/reference/styles.md +176 -0
  33. package/dist/agent/pages/docs/reference/test-utilities.md +128 -0
  34. package/dist/module.json +1 -1
  35. package/dist/module.mjs +1 -1
  36. package/dist/test.mjs +13 -1
  37. package/package.json +27 -48
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: "Overview"
3
+ description: "Decide whether Nuxt PDF fits the document you need to create."
4
+ url: "https://nuxt-pdf.lupinum.com/docs/getting-started"
5
+ route: "/docs/getting-started"
6
+ locale: "en"
7
+ section: "Documentation"
8
+ collection: "docs"
9
+ source: "ginko-content"
10
+ ---
11
+
12
+ # Overview
13
+
14
+ > Decide whether Nuxt PDF fits the document you need to create.
15
+
16
+ Nuxt PDF turns Vue components into PDFs on a Nuxt server. Put a typed Vue
17
+ template in `pdfs/`, pass it data from a Nitro route, and return the completed
18
+ PDF response.
19
+
20
+ Use Nuxt PDF when you control a structured, data-driven document:
21
+
22
+ - invoices, quotes, and receipts;
23
+ - reports and statements;
24
+ - certificates, tickets, and labels.
25
+
26
+ The package provides PDF layout primitives, local images and fonts, SVG
27
+ graphics, links, bookmarks, tables of contents, development previews, and test
28
+ helpers. Templates run on Node and stay out of the browser bundle.
29
+
30
+ ## Pick the right rendering tool
31
+
32
+ Pick a different tool when:
33
+
34
+ - **You want to print an existing web page.** Use headless Chromium through
35
+ Playwright or Puppeteer. Nuxt PDF does not compile HTML or browser CSS.
36
+ - **You want to display an existing PDF.** Use
37
+ [PDF.js](https://mozilla.github.io/pdf.js/). Nuxt PDF creates files; it is not
38
+ a viewer.
39
+ - **You want to edit, merge, fill, or sign an existing PDF.** Use
40
+ [pdf-lib](https://pdf-lib.js.org/) or a signing service. Nuxt PDF creates new
41
+ documents from application data.
42
+
43
+ ## Current scope
44
+
45
+ Nuxt PDF is in public beta. A minor release can contain a documented
46
+ breaking change before version 1.0.
47
+
48
+ The current release does not include an HTML or CSS compiler, a table engine, a
49
+ chart engine, form fields, signing, tagged PDF output, browser rendering, or
50
+ edge rendering. It does not promise byte-identical output across machines.
51
+
52
+ The [supported behavior](/raw/docs/examples/supported-behavior.md) page summarizes the
53
+ tested boundary. The repository's
54
+ [CONFORMANCE.md](https://github.com/lupinum-dev/nuxt-pdf/blob/main/CONFORMANCE.md)
55
+ contains the maintainer-grade evidence.
56
+
57
+ <cards cols="2">
58
+ <card title="Install Nuxt PDF" description="Add the module to a Nuxt 4 application." icon="lucide:download" to="/docs/getting-started/installation" />
59
+
60
+ <card title="Render your first PDF" description="Create and download a small invoice." icon="lucide:rocket" to="/docs/getting-started/quickstart" />
61
+ </cards>
62
+
63
+ Questions? Ask in the [Lupinum OSS Discord](https://discord.lupinum.com).
@@ -0,0 +1,123 @@
1
+ ---
2
+ title: "Add links, bookmarks, and a table of contents"
3
+ description: "usePdfPageNumbers, the multi-pass layout loop, convergence and maxPasses, internal links, and the bookmark outline."
4
+ url: "https://nuxt-pdf.lupinum.com/docs/guides/contents-links-bookmarks"
5
+ route: "/docs/guides/contents-links-bookmarks"
6
+ locale: "en"
7
+ section: "Documentation"
8
+ collection: "docs"
9
+ source: "ginko-content"
10
+ ---
11
+
12
+ # Add links, bookmarks, and a table of contents
13
+
14
+ > usePdfPageNumbers, the multi-pass layout loop, convergence and maxPasses, internal links, and the bookmark outline.
15
+
16
+ Nuxt PDF builds a table of contents, internal links, and a bookmark outline from
17
+ ordinary components. There is no TOC component and no automatic heading
18
+ collection. You author the list, and the engine resolves the page numbers.
19
+
20
+ ## Named destinations and internal links
21
+
22
+ Give any primitive an `id` to make it a named destination, then link to it with
23
+ `<PdfLink href="#id">`:
24
+
25
+ ```vue
26
+ <PdfText id="terms">Terms &amp; conditions</PdfText>
27
+
28
+ <PdfLink href="#terms">Jump to terms</PdfLink>
29
+ ```
30
+
31
+ Internal `#id` links resolve **by name in a single pass**. They do not trigger
32
+ the multi-pass loop and add no cost. A `#id` that does not match any destination
33
+ in the mounted document fails the render with `PDF_TREE_INVALID`.
34
+ The link and destination must both exist in the initial mounted tree and after
35
+ every page-number update; do not conditionally create a destination only after
36
+ its page number becomes available.
37
+
38
+ <info icon="lucide:info">
39
+ When an `id` sits on a node that spans a page boundary, both the printed page
40
+ number and the jump target resolve to the section's **first** page. This is a
41
+ deliberate divergence from React PDF, whose last-writer-wins table points at the
42
+ last page.
43
+ </info>
44
+
45
+ ## Printing page numbers: usePdfPageNumbers
46
+
47
+ To print the page a destination lands on, read the auto-imported
48
+ `usePdfPageNumbers()` composable. It returns a readonly, reactive map from `id`
49
+ to its 1-based page:
50
+
51
+ ```vue
52
+ <script setup lang="ts">
53
+ const pageNumbers = usePdfPageNumbers()
54
+
55
+ const entries = sections.map(s => ({ id: s.id, title: s.title }))
56
+ </script>
57
+
58
+ <template>
59
+ <PdfLink
60
+ v-for="entry in entries"
61
+ :key="entry.id"
62
+ :href="`#${entry.id}`"
63
+ >
64
+ {{ entry.title }} {{ pageNumbers[entry.id] ?? '' }}
65
+ </PdfLink>
66
+ </template>
67
+ ```
68
+
69
+ Reading the composable is the **only** signal that turns on multi-pass layout.
70
+ The engine lays out the document once per pass. Each pass feeds its destination
71
+ page map into the next pass until the map stops changing.
72
+
73
+ <warning icon="lucide:triangle-alert">
74
+ On the first pass every entry is `undefined`. Always keep a fallback
75
+ (`pageNumbers[id] ?? ''`) so the first pass renders a blank rather than throwing.
76
+ </warning>
77
+
78
+ Calling `usePdfPageNumbers()` outside a PDF render throws, rather than returning
79
+ an empty map that could be mistaken for first-pass state.
80
+
81
+ ## Convergence and maxPasses
82
+
83
+ The loop is a fixed point. An ordinary table of contents converges in **two
84
+ passes**: pass one fills the numbers in, pass two lays out with them and the map
85
+ no longer changes.
86
+
87
+ A document does not converge if its layout depends on the page numbers that it prints.
88
+ For example, a TOC entry can change height when its page number changes. After `maxPasses`
89
+ (a validated positive integer on `definePdf`, default 5) the render fails with a
90
+ `PDF_LIMIT_EXCEEDED` `NuxtPdfError`, attributed to the template:
91
+
92
+ ```ts
93
+ definePdf<Props>({
94
+ // Raise the cap only if a genuinely convergent document needs more passes.
95
+ maxPasses: 8,
96
+ })
97
+ ```
98
+
99
+ Non-convergence fails closed; the loop does not force a wrong answer. Raise
100
+ `maxPasses` only when you know the document actually settles.
101
+
102
+ ## Bookmarks (the outline)
103
+
104
+ Add a `bookmark` to any of `PdfPage`, `PdfView`, `PdfText`, or `PdfImage` to
105
+ build the PDF outline. The value is a title string, or an object:
106
+
107
+ ```vue
108
+ <PdfView :id="section.id" :bookmark="{ title: section.title, expanded: true }">
109
+ <PdfText :id="sub.id" :bookmark="sub.title">{{ sub.title }}</PdfText>
110
+ </PdfView>
111
+ ```
112
+
113
+ Nesting follows the component tree, so a child's bookmark nests under its
114
+ ancestor's. The outline carries title text, its initially expanded state, and
115
+ parent/child nesting. Nuxt PDF does not expose reader page-mode preferences or
116
+ bookmark destination geometry (`top`/`left`/`zoom`/`fit`).
117
+
118
+ ## A full example
119
+
120
+ `playground/pdfs/report.vue` in the repository demonstrates the whole feature: a
121
+ contents page linking to each section, live page numbers, per-section bookmarks,
122
+ and a fixed footer with a dynamic page counter. The engine resolves all these features through the
123
+ multi-pass loop.
@@ -0,0 +1,118 @@
1
+ ---
2
+ title: "Deploy and operate"
3
+ description: "Size, cache, queue, and monitor PDF rendering on a tested Node target."
4
+ url: "https://nuxt-pdf.lupinum.com/docs/guides/deployment"
5
+ route: "/docs/guides/deployment"
6
+ locale: "en"
7
+ section: "Documentation"
8
+ collection: "docs"
9
+ source: "ginko-content"
10
+ ---
11
+
12
+ # Deploy and operate
13
+
14
+ > Size, cache, queue, and monitor PDF rendering on a tested Node target.
15
+
16
+ Nuxt PDF renders on Node. The engine, the templates, and the embedded assets
17
+ live in the Nitro server output. The client bundle contains none of them.
18
+ For a separate Node worker, use the
19
+ [standalone registry build](/raw/docs/guides/standalone-node.md).
20
+
21
+ ## Pick a runtime
22
+
23
+ | Runtime | Support | Notes |
24
+ | --- | --- | --- |
25
+ | Node server (default Nitro preset) | Supported | The tested path. Use it for high-volume or large documents. |
26
+ | Standalone Node registry | Locally tested | Compile with the build entry. Test the deployed worker before production use. |
27
+ | Convex Node action | Not deployment-verified | A candidate for the standalone registry. Measure bundle size, memory, and execution limits on the target deployment. |
28
+ | Vercel serverless build | Build-verified | The package test verifies the Vercel Nitro output. Execute your deployed function before production use. |
29
+ | Other Node serverless functions | Expected, not verified | Use a Node-compatible Nitro preset and test the deployed runtime. |
30
+ | Edge workers | Not supported | The engine needs Node APIs. Do not target edge presets. |
31
+
32
+ ## Size the memory budget
33
+
34
+ One render holds the document tree, the laid-out pages, and the output bytes in
35
+ memory at the same time. Give each function or container headroom above your
36
+ largest expected document:
37
+
38
+ - Start from `pdf.limits.maxOutputBytes` (64 MB by default) plus the tree and
39
+ image budgets.
40
+ - Lower `pdf.limits.maxPages` and `pdf.limits.maxOutputBytes` to cap the worst
41
+ case for untrusted input.
42
+ - Load-test with your real templates before you pick an instance size.
43
+
44
+ ## Align timeouts
45
+
46
+ The render deadline lives in `pdf.limits.timeoutMs` (30 seconds by default).
47
+ The platform timeout must stay longer than that budget, or the platform kills
48
+ a render that Nuxt PDF would have finished.
49
+
50
+ ```ts [nuxt.config.ts]
51
+ export default defineNuxtConfig({
52
+ pdf: {
53
+ limits: {
54
+ timeoutMs: 10_000,
55
+ },
56
+ },
57
+ })
58
+ ```
59
+
60
+ Set the platform function timeout to at least the same value plus queueing
61
+ headroom.
62
+
63
+ ## Cache completed renders
64
+
65
+ Cache a PDF only when your application controls every input to the render. A
66
+ template can read the current time or imported application code. An allowlisted
67
+ remote image can also change without a props change. Nuxt PDF does not promise
68
+ that these renders produce the same bytes.
69
+
70
+ Build the cache key from the template version and the canonical render inputs.
71
+ Include the tenant or authorization boundary when documents differ between
72
+ customers. Store the completed bytes in a bounded cache, object store, or CDN
73
+ with an explicit expiry and invalidation rule.
74
+
75
+ Do not use a module-level `Map` as a production cache. It has no size limit,
76
+ does not persist reliably across serverless invocations, and can cross request
77
+ boundaries when its key is incomplete.
78
+
79
+ ## Queue long documents
80
+
81
+ A 200-page report can occupy a worker for seconds. Keep that work off the
82
+ request path when you can:
83
+
84
+ 1. Accept the request and return a job identifier.
85
+ 2. Render in a background worker.
86
+ 3. Store the bytes and let the client poll or subscribe.
87
+
88
+ This pattern also keeps interactive routes responsive while batch jobs run.
89
+
90
+ ## Serverless notes
91
+
92
+ Local fonts and images travel inside the server bundle as validated bytes. The
93
+ repository verifies the Vercel output structure but does not execute that
94
+ deployed function. Test the real target before you send production traffic.
95
+
96
+ - **Bundle size.** Every font and image under `pdfs/` adds to the bundle.
97
+ Remove assets that no template uses; the module embeds only discovered
98
+ files.
99
+ - **Cold starts.** The first invoke parses the bundle. Fewer embedded assets
100
+ mean faster cold starts.
101
+ - **Concurrency.** Size concurrency from load tests on your deployed runtime.
102
+ Nuxt PDF does not currently claim cross-render concurrency guarantees.
103
+ - **Filesystem access.** Templates read no files at runtime. Do not add code
104
+ that reads from the deployment filesystem during a render.
105
+
106
+ ## Monitor renders
107
+
108
+ Every render returns content-free diagnostics: duration, byte length, page
109
+ count, layout passes, layout warnings, and registered font faces. Log them next
110
+ to your request logs to spot slow or oversized documents before users do.
111
+
112
+ ```ts [server/api/invoice.get.ts]
113
+ export default defineEventHandler(async () => {
114
+ const result = await pdf.invoice.render(props)
115
+ console.info('invoice rendered', result.diagnostics)
116
+ return result.response()
117
+ })
118
+ ```
@@ -0,0 +1,90 @@
1
+ ---
2
+ title: "Diagnose render failures"
3
+ description: "Use template attribution, preview diagnostics, and exact error messages to recover from a failed render."
4
+ url: "https://nuxt-pdf.lupinum.com/docs/guides/errors-and-debugging"
5
+ route: "/docs/guides/errors-and-debugging"
6
+ locale: "en"
7
+ section: "Documentation"
8
+ collection: "docs"
9
+ source: "ginko-content"
10
+ ---
11
+
12
+ # Diagnose render failures
13
+
14
+ > Use template attribution, preview diagnostics, and exact error messages to recover from a failed render.
15
+
16
+ First identify whether the failure happens during module setup or during
17
+ `render()`.
18
+
19
+ - Setup validates configuration, template definitions, local images, and
20
+ fonts. Invalid setup can throw `TypeError` before a template render exists.
21
+ - Render failures use `NuxtPdfError` with a machine-readable `code` and
22
+ `templateKey`. Development also includes the relative `templateFile`.
23
+
24
+ The [errors and limits reference](/raw/docs/reference/errors-and-limits.md) defines
25
+ every code and default budget.
26
+
27
+ ## Inspect a render error
28
+
29
+ ```ts [server/api/report.get.ts]
30
+ import { NuxtPdfError, pdf } from '#pdf'
31
+
32
+ export default defineEventHandler(async () => {
33
+ try {
34
+ const result = await pdf.report.render(props)
35
+ return result.response()
36
+ }
37
+ catch (error) {
38
+ if (error instanceof NuxtPdfError) {
39
+ console.error(error.code, error.templateKey, error.templateFile)
40
+ }
41
+ throw error
42
+ }
43
+ })
44
+ ```
45
+
46
+ Log identifiers and diagnostics through the application's normal error system.
47
+ Do not log render props or document text unless the application has a separate
48
+ data-handling policy for them.
49
+
50
+ ## Use the development preview
51
+
52
+ Open `/_pdf/<template-key>`. The preview renders through the same public
53
+ template method as server code and shows duration, byte length, page count,
54
+ layout passes, and registered font faces.
55
+
56
+ When a render fails, the preview keeps document content out of the error panel.
57
+ It shows the code, template, relative source path, and a short message. If the
58
+ previous render succeeded, the old PDF stays visible with a stale marker.
59
+
60
+ ## Match the message to a fix
61
+
62
+ | Message or code | Inspect or change |
63
+ | --- | --- |
64
+ | `Cannot find module '#pdf'` or an untyped import | Run `pnpm nuxt prepare` or restart the development server. |
65
+ | `/_pdf` returns 404 | Use the preview only in development. It is absent from production output. |
66
+ | `PDF_TEMPLATE_NOT_FOUND` | Check the relative filename and registry key. Nested keys retain `/`. |
67
+ | `PDF_TREE_INVALID` | Read the named primitive and prop or nesting rule. Remove DOM attributes and put text inside `PdfText`. |
68
+ | `Font family not registered` | Register the requested family, weight, and style in `pdf.fonts`. |
69
+ | A font throws `TypeError` during setup | Check its relative path, extension, signature, size, and location under `pdfs/fonts`. |
70
+ | `PDF_ASSET_BLOCKED` | Check the image source type, HTTPS allowlist, redirects, and timeout. |
71
+ | `PDF_ASSET_INVALID` | Replace the admitted bytes with a valid PNG or JPEG of the declared format. |
72
+ | `PDF_LIMIT_EXCEEDED` | Read the named limit and cap. Reduce the input or raise only that limit for a known document. |
73
+
74
+ For `maxPasses`, fix layout that changes when destination page numbers appear.
75
+ Raising the cap does not make unstable geometry converge. See the
76
+ [table-of-contents guide](/raw/docs/guides/contents-links-bookmarks.md).
77
+
78
+ ## Monitor successful renders
79
+
80
+ Every completed result includes immutable metadata and diagnostics. Record
81
+ duration, output bytes, page count, layout passes, layout warnings, and
82
+ registered font faces.
83
+
84
+ The development preview explains each layout warning. For example, an
85
+ unbreakable `PdfView` that is taller than the page can render with overflow;
86
+ the preview names the page, node type, node height, and usable page height.
87
+ This is a warning rather than a render failure because the output is still a
88
+ valid PDF and some authors intentionally use oversized pages.
89
+ The failure shows up in a customer's invoice, not a test run. Alert on trends
90
+ before time or output budgets become routine failures.
@@ -0,0 +1,102 @@
1
+ ---
2
+ title: "Add images and fonts"
3
+ description: "Bundle local PNG, JPEG, TTF, OTF, and WOFF2 resources with a PDF template."
4
+ url: "https://nuxt-pdf.lupinum.com/docs/guides/images-and-fonts"
5
+ route: "/docs/guides/images-and-fonts"
6
+ locale: "en"
7
+ section: "Documentation"
8
+ collection: "docs"
9
+ source: "ginko-content"
10
+ ---
11
+
12
+ # Add images and fonts
13
+
14
+ > Bundle local PNG, JPEG, TTF, OTF, and WOFF2 resources with a PDF template.
15
+
16
+ Keep local images under `pdfs/assets` and fonts under `pdfs/fonts`. Nuxt PDF
17
+ validates and embeds them in the Nitro server output.
18
+
19
+ In development, each render reads and validates local image files again.
20
+ Image edits take effect without restarting the server.
21
+
22
+ ## Add a local image
23
+
24
+ Put a PNG or JPEG in `pdfs/assets`. Set `PdfImage.src` to the path relative to
25
+ that directory:
26
+
27
+ ```vue
28
+ <PdfImage
29
+ src="brand/logo.png"
30
+ :style="{ height: 40, objectFit: 'contain', width: 120 }"
31
+ />
32
+ ```
33
+
34
+ Public rendering accepts local paths, admitted PNG or JPEG byte sources, and
35
+ allowlisted HTTPS URLs. It blocks `data:` URL strings, absolute filesystem
36
+ paths, parent traversal, symlink escapes, and SVG files used as image sources.
37
+
38
+ Use [`PdfSvg`](/raw/docs/guides/svg-graphics.md) for vector graphics authored in the
39
+ document tree.
40
+
41
+ ## Register a local font
42
+
43
+ Put a TTF, OTF, or WOFF2 file in `pdfs/fonts`, then register one entry for each weight
44
+ and style used by the document:
45
+
46
+ ```ts [nuxt.config.ts]
47
+ export default defineNuxtConfig({
48
+ modules: ['@lupinum/nuxt-pdf'],
49
+ pdf: {
50
+ fonts: [
51
+ {
52
+ family: 'Invoice Sans',
53
+ src: 'InvoiceSans-Regular.ttf',
54
+ fontStyle: 'normal',
55
+ fontWeight: 400,
56
+ },
57
+ {
58
+ family: 'Invoice Sans',
59
+ src: 'InvoiceSans-Bold.ttf',
60
+ fontStyle: 'normal',
61
+ fontWeight: 700,
62
+ },
63
+ ],
64
+ },
65
+ })
66
+ ```
67
+
68
+ Set the family on a parent so text descendants inherit it:
69
+
70
+ ```vue
71
+ <PdfPage :style="{ fontFamily: 'Invoice Sans' }">
72
+ <PdfText>Invoice</PdfText>
73
+ </PdfPage>
74
+ ```
75
+
76
+ If a requested family, weight, or style was not registered, rendering fails
77
+ with `PDF_LAYOUT_ERROR`. If the configured file is invalid, module setup throws
78
+ a `TypeError` before a template render starts.
79
+
80
+ ## Check language coverage
81
+
82
+ A font must contain the glyphs used by the document. Latin Extended, Greek,
83
+ Cyrillic, and custom hyphenation are covered by the tested corpus with supplied
84
+ fonts. CJK, combining marks, Arabic, bidirectional text, and variable fonts need
85
+ application-specific semantic and raster tests. Emoji and fallback font chains
86
+ are not supported; use an admitted image for an emoji graphic.
87
+
88
+ ## Resource validation
89
+
90
+ The module checks four things:
91
+
92
+ - **Structure:** images must decode as PNG or JPEG; fonts need a valid TTF, OTF,
93
+ or WOFF2 structure and matching extension.
94
+ - **Size:** a local image is limited to 10 MB and a font to 5 MB.
95
+ - **Location:** the resolved path must remain inside its declared root.
96
+ - **Embedding:** validated bytes travel in the Nitro server output, so
97
+ production rendering does not read these files from disk.
98
+
99
+ Development reloads local image bytes for the next preview render. The
100
+ [module-options reference](/raw/docs/reference/module-options.md) lists the exact font
101
+ fields. Use the [remote-image guide](/raw/docs/guides/remote-images.md) for HTTPS
102
+ sources.