# Postal labels — local source

Download `postal-labels.mjs` alongside this README. Import
`buildPostalLabels(csv)` in a JavaScript ES-module environment. It returns
`{ html, text, labels, rows, geometry }`: a complete printable HTML document,
plain-text address review, label count, address-row numbers with rendered
lines (the first data row is address row 1), and the fixed page geometry. The only other export is the frozen
`POSTAL_LABEL_GEOMETRY` object. Calling the module does not save, print or send
anything. No package installation or remote import is required.

## Input and limits

Prepare comma-separated CSV with this exact case-sensitive header and order:

```text
name,address1,address2,city,region,postal_code,country
```

Include 1–30 addresses. Every row must have seven cells. `address2` may be empty;
all other fields are required. Use printable ASCII characters only (space through
~); accented characters, tabs, controls and multiline cells are refused. Leading
and trailing spaces in cells are refused rather than silently trimmed. Quoted
commas and doubled quotes are supported by the same parser as the browser tool.
One leading UTF-8 BOM and a valid final newline are allowed. Inputs stay literal; no formulas are evaluated.

Each address has four or five lines: name; address1; optional address2;
`city, region postal_code`; country. Every complete rendered line must be at
most 28 characters. Input is capped at 100,000 characters; the shared CSV parser
also caps records/cells. Each complete HTML and text output is capped at
100,000 characters. Invalid input or an exceeded limit throws before any
result is returned. Nothing is silently clipped, wrapped, abbreviated or dropped.
This is a deliberately narrow label layout, not postal-address validation or
country-specific formatting. Verify spelling, postal codes, required country
conventions and deliverability yourself.

## Executable fictional example

Save the module and run this code as an ES module from the same directory.
It only prints the label count and layout; it creates no file and does not print
any address to the console. The two addresses are fictional QA data.

```js
import { buildPostalLabels, POSTAL_LABEL_GEOMETRY } from './postal-labels.mjs';
const csv = [
  'name,address1,address2,city,region,postal_code,country',
  'Alex Example,12 Sample Lane,,Ottawa,ON,K1A 0B1,Canada',
  'Sam Example,34 Fiction Road,Unit 2,Toronto,ON,M5V 2T6,Canada',
].join('\n');
const result = buildPostalLabels(csv);
console.log(`Labels: ${result.labels}`);
console.log(`Page: ${POSTAL_LABEL_GEOMETRY.pageWidthIn} x ${POSTAL_LABEL_GEOMETRY.pageHeightIn} in; ${POSTAL_LABEL_GEOMETRY.columns} x ${POSTAL_LABEL_GEOMETRY.rows} slots`);
// result.text and result.rows contain the complete address review.
// result.html contains the printable document; treat it as private address data.
```

Expected exact console output:

```text
Labels: 2
Page: 8.5 x 11 in; 3 x 10 slots
```

## Save and print manually

Review `result.text` or `result.rows` locally. To create a file, explicitly save
the exact `result.html` string as UTF-8 plain text named `postal-labels.html`,
using your own trusted editor or calling program. Choose a new filename to avoid
overwriting an existing file. Do not save the JavaScript module itself as HTML.
The browser job can also download its generated HTML after you review the input.
The module provides the string; your caller controls any file write or download.

Open the saved HTML in your browser. It contains escaped address text and fixed
local CSS, with no scripts, remote images, fonts, stylesheets or automatic print
action. Check all addresses, then manually open Print. Select Letter paper,
portrait orientation, 100%/actual-size scale and disable browser headers/footers.
Use the document's page layout, and inspect print preview for unexpected browser
margins or extra pages. First print a test on plain paper, compare it against
your blank sheet, and stop if positions, scale or line fit differ. Do not assume
that every printer/browser honors CSS page dimensions identically.

The single page has 30 slots filled across each row, then down: 3 columns and
10 rows. Each slot is 2.625 by 1 inch; top/bottom margins are 0.5 inch,
left/right margins 0.1875 inch, and horizontal gutters 0.125 inch. There is no
vertical gutter. Unused slots remain empty. It uses Courier at 10 points with
12-point line spacing and 6-point vertical/9-point horizontal inset. There is no
starting-slot control, partially used sheet mode, alternate stock layout or
multi-page batch. This explicit generic geometry is not a claim of compatibility
with a branded label stock, calibrated printer alignment, a generated PDF or
successful physical printing.

## Privacy and scope

The dependency-free module has no network, filesystem, process, credential,
telemetry, browser storage or sending access. Address characters are escaped
into HTML text, never interpreted as tags, scripts, attributes or formulas.
The generated HTML is a printable document, not an address-entry app or a PDF.
No Google account, Docs, Sheets, contacts, mail merge or postal service is called.

Your surrounding agent, logger, editor, browser, print service or application may
retain or transmit inputs and outputs. A saved HTML file or print job contains
address data. Choose an appropriate local environment and destination; the module
cannot make a remote agent or cloud printer private. Do not publish address
files or paste private output into diagnostic logs.

This example and parity checks are fictional QA. Source availability and passing
tests are not independent use, customer completion, repeat use or demand. No
installation, paid outcome, native Docs merge or printer acceptance is claimed.

## License

MIT License

Copyright (c) 2026 QuasiLife

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
