@beltype/cli 0.1.6 → 0.1.8
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.
- package/README.md +11 -6
- package/assets/merge/NOTICE +7 -0
- package/assets/merge/merge.js +106 -0
- package/dist/src/check.js +127 -13
- package/dist/src/compare.js +47 -8
- package/dist/src/flags.js +2 -2
- package/dist/src/in-page.js +33 -6
- package/dist/src/main.js +23 -12
- package/dist/src/merge-tab.js +139 -0
- package/dist/src/print.js +10 -6
- package/dist/src/run.js +17 -4
- package/dist/src/serve.js +249 -57
- package/package.json +19 -7
package/README.md
CHANGED
|
@@ -19,7 +19,8 @@ beltype print paper/index.html --flag caster.shaper=fontkit --flag cicero.compos
|
|
|
19
19
|
|
|
20
20
|
- `--printer caster|chromium`: who prints the pages Cicero presented. Chromium prints them one sheet to a page; it refuses, naming `--printer caster`, when the pages are not all one size.
|
|
21
21
|
- `--trace <file.json>`: where the run's time went. `process` is node's clock around each step (launch, context, load, cut, print, transfer, close, write), `cicero` is Cicero's own `performance.measure` entries, `caster` is Caster's report (`ms` per stage and `timing`; `null` under Chromium), with the versions and the resolved flags. It is written even when the run refuses, with the step that refused.
|
|
22
|
-
- `--check`: the
|
|
22
|
+
- `--check` and `--check=report` (need `npm install mupdf@1.28.1`: mupdf is under the AGPL-3.0, so this package does not bring it): the PDF compared with the pages Cicero presented in the same run. Each presented page is screenshotted at 96 dpi, the PDF is rasterised at 96 dpi and the pairs are diffed into `<name>.check/` (`screen-N.png`, `print-N.png`, `diff-N.png`, `check.json`), with a share of differing pixels per page, its worst tile, whether it passes, and a mean. It is the proof that the printer drew what the engine cut, not a proof against an outside oracle: Caster's acceptance suite for the cast road is that. Under `--check` a page over 3.5 % differing, or a page count that differs between screen and print, fails the run with one line a page (`check page 2 fails: 25.70% differ, over 3.5%; <name>.check/diff-2.png`); `--check=report` writes the same report and never fails. It tolerates one pixel of slip, because the screen's pages sit at fractional heights (A4 is 1122.52 px) and Skia and mupdf shade letter edges differently; a text page still reads 0.3 to 1.8 %, so a small defect (a 120 by 30 px block is 0.4 % of an A4 page) passes the share. The diff is also read in 24 px tiles, and a page whose worst tile differs over 40 % fails (`check page 1 fails: tile at (48, 168) differs 58%, over the 40% floor for a picture page; <name>.check/diff-1.png`); `check.json` carries each page's worst tile, where it is, and its kind, `text` or `picture` (an image, a canvas, an SVG, a background image, a blend, a filter, a shadow or an opacity on the page). A print grown round its page by a bleed and print marks is cropped to the page first, which sits at the PDF's origin. A tile over the floor is excused where Caster's report confessed a region over it, a transform or a guess (`black-text`, `cmyk-image`, `undecodable-image`, `raster-shadow`, `blend`, `opacity` and the rest), and the page's line names the confession (`worst tile 44% at (48, 72) excused by black-text on h1[0]`); a tile straddling a region's edge is excused only when its part outside, on its own, is under the floor, and the share is never excused. Excusing needs a Caster whose report carries `confessions`, which the pinned 0.1.7 does not: under it nothing is excused.
|
|
23
|
+
- `--no-sandbox`: launch Chromium without its sandbox. By default it runs in it; a container that runs as root needs this, since Chromium will not start sandboxed as root. Give the container a user of its own instead where you can.
|
|
23
24
|
- `SOURCE_DATE_EPOCH=<seconds>` (an environment variable, not a flag): the moment the file says it was made, whole seconds since 1970 as the reproducible-builds convention has it. Set, the file's `/CreationDate` and `/ModDate` are that instant and the same document printed twice gives the same bytes; unset, they are the wall clock.
|
|
24
25
|
|
|
25
26
|
The document is plain HTML, CSS and the files beside it. The run answers every request from the document's folder, on a made-up `.invalid` address, and refuses anything else by name: a document that asks for a file it does not have, or for anything on a network, prints nothing. Fonts must be declared with `@font-face` and their files, because Caster embeds every face it draws.
|
|
@@ -33,10 +34,14 @@ beltype serve --port 3000
|
|
|
33
34
|
curl -F index.html=@index.html -F paper.css=@paper.css -F fonts/a.woff2=@fonts/a.woff2 -F caster.writer=forme http://127.0.0.1:3000/print -o out.pdf
|
|
34
35
|
```
|
|
35
36
|
|
|
36
|
-
- `POST /print`, `multipart/form-data`. `index.html` is required; every other file keeps its form field name as its path relative to the document (`fonts/a.woff2`), plain segments with `/` separators, never absolute and never `..`. A field that is not a file is a flag, `<owner>.<name>` = value (`caster.writer=forme`, `cicero.…`); `beltype.check` is refused. A field `created` (an ISO 8601 instant) fixes the file's dates, else `SOURCE_DATE_EPOCH`, else the clock. The answer is `200 application/pdf` with `X-Beltype-Pages`, `X-Beltype-Words`
|
|
37
|
+
- `POST /print`, `multipart/form-data`. `index.html` is required; every other file keeps its form field name as its path relative to the document (`fonts/a.woff2`), plain segments with `/` separators, never absolute and never `..`. A field that is not a file is a flag, `<owner>.<name>` = value (`caster.writer=forme`, `cicero.…`); `beltype.check` is refused. A field `created` (an ISO 8601 instant) fixes the file's dates, else `SOURCE_DATE_EPOCH`, else the clock. The answer is `200 application/pdf` with `X-Beltype-Pages`, `X-Beltype-Words`, `X-Beltype-Warnings` (the count), `X-Beltype-Deferred` (the count of Caster's deferrals) and `X-Beltype-Standard`, what the file claims as Caster reports it: `pdf-2.0; pdf-ua-2`, or `pdf-2.0` alone under `caster.standard=none` or where Caster guessed a tag and withdrew the claim (a print under `beltype.printer=chromium` is Chromium's own file and carries none); `422` with `beltype print`'s sentence where the document is refused (a file it asked for and was not given, among them); `400` for a bad request; `413` over the upload limit; `504` over the time limit; `500` otherwise, after which the browser is restarted.
|
|
37
38
|
- `GET /health`: `{ "status": "up", "chromium": …, "prints": …, "queued": … }`, or `503` with `"status": "restarting"` while the browser starts again.
|
|
38
|
-
- `--host 127.0.0.1`, `--port 3000`, `--max-upload 50` (MB), `--timeout 60` (seconds per print), `--restart-after 100` (prints before the browser is restarted).
|
|
39
|
-
- A
|
|
39
|
+
- `--host 127.0.0.1`, `--port 3000`, `--max-upload 50` (MB), `--timeout 60` (seconds per print), `--restart-after 100` (prints before the browser is restarted), `--allowed-hosts <name[:port],…>` (the `Host` values it answers besides the bound address; a name with no port is that name on any port), `--no-sandbox` (as `beltype print`'s).
|
|
40
|
+
- A request whose `Host` is not the bound address and port, or whose `Origin` is another page's, is refused with `403` before its body is read, since any page in a browser can post a form without asking first. Bound to `0.0.0.0` or `::`, the server cannot know the name it is reached by, so it answers only the names `--allowed-hosts` lists, and without the list it refuses to start: `beltype serve --host 0.0.0.0 --port 3000 --allowed-hosts beltype-serve:3000`, for a container its neighbours reach as `beltype-serve`. On a loopback bind the list is accepted and not needed.
|
|
41
|
+
- Why a list: a page in your browser can make a name it controls resolve to your machine (DNS rebinding), and its requests then arrive from its own origin under its own `Host`, so the `Origin` check alone passes them. Only a server that knows which names it answers can refuse them, and on a wildcard bind only you can tell it.
|
|
42
|
+
- A document whose text, its JSON-LD data blocks (`<script type="application/ld+json">`, which never run) aside, holds no `<script`, `<iframe`, `<object`, `<embed`, `<frame`, `<portal`, `javascript:` or `on…=` attribute is printed on one kept page, re-seated for each print as Caster's kept frame is (`document.open()` keeps the realm, so Caster's registry and the companions' modules stay warm); any other document gets a page of its own, because a script's timers, listeners and globals would outlive it on a kept `Window`. The log line of each print names the road (`road kept` or `road fresh`) and the time of every step. A print that fails or times out closes the kept page.
|
|
43
|
+
- `POST /templates`: a mail merge's template, the same form as `/print`, once. It answers `201` and `{ "template": "<id>" }`; uploading the same files and flags again is the same id. A template has a data block (`<script type="application/ld+json">`) and no script of its own. The server keeps the last sixteen.
|
|
44
|
+
- `POST /templates/<id>/print`: one customer as JSON, `{ "values": { … }, "rows": { "<table>": [ { … } ] }, "created": "…" }`. `values` are set on the document's item, `rows` fill each `<template data-repeat>` of that name, and a cell is a string or, for a typed column, `{ "value": 7398.4, "text": "7.398,4" }`. It answers what `/print` answers. The merge runs in the tab with `prosemirror-stores`, on the same page for every customer: only the top-level boxes that changed are replaced, and the PDF is the one `/print` makes of the same merged document. A customer who changes the shape of the body, such as rows directly in `<body>`, has the template seated again, and the log line says why.
|
|
40
45
|
- One print runs at a time; the others wait their turn. After every start the server prints a built-in document twice under forme (the log shows both writes), so the first request is warm.
|
|
41
46
|
- It binds `127.0.0.1` unless `--host` says otherwise, and fetches nothing from a network: a document that asks for anything it was not posted is refused by name, as in `beltype print`. The built-in warm-up document ships one font, Source Sans 3 (SIL OFL), in `assets/warmup/`.
|
|
42
47
|
|
|
@@ -60,7 +65,7 @@ Found while writing the sample, and left out of it until the companions print th
|
|
|
60
65
|
|
|
61
66
|
- `counter(pages)` in a margin box: Caster refuses the content.
|
|
62
67
|
- SVG text under `transform="rotate(…)"`: Caster draws it broken.
|
|
63
|
-
- `content()` in `string-set` includes the heading's `::before
|
|
68
|
+
- `content()` in `string-set` includes the heading's `::before`, so the sample's running section reads "3. Results" from `content()` alone. This is Caster's, not Cicero's: Caster's preparation turns the heading's `::before` into a real span before Cicero cuts, and `content()` then reads it.
|
|
64
69
|
|
|
65
70
|
## Requirements
|
|
66
71
|
|
|
@@ -70,7 +75,7 @@ Node 22 or later, and Playwright's headless shell for `playwright-core` 1.63.0:
|
|
|
70
75
|
npx playwright-core@1.63.0 install chromium-headless-shell
|
|
71
76
|
```
|
|
72
77
|
|
|
73
|
-
The companions come from
|
|
78
|
+
The companions come from npm, pinned exactly: `@beltype/cicero` 0.1.10, `@beltype/caster` 0.2.5 and `@beltype/common` 0.1.2.
|
|
74
79
|
|
|
75
80
|
## Working on it
|
|
76
81
|
|