rapier-html 1.2.6 → 1.2.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/BUILD.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "package": "rapier-html",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "path": "dist/rapier.html",
5
- "bytes": 4952859,
6
- "sha256": "48b694df7db506a77f5a98e01098f37d54e7f9a88d6e5647ca09ea43578c3927",
7
- "builtAt": "2026-10-16T12:09:12.607Z",
5
+ "bytes": 5936307,
6
+ "sha256": "93e8ba922a0df18a75196a1a87971ac80d61b5a4a06630512abb25c94a23ff3f",
7
+ "builtAt": "2026-10-17T01:08:23.274Z",
8
8
  "node": "v22.23.3",
9
9
  "canonical": true,
10
10
  "packing": "zopfli",
@@ -14,15 +14,15 @@
14
14
  "delivery": "built-in",
15
15
  "kind": "script",
16
16
  "element": "rapier-plugin-math",
17
- "bytes": 691650,
18
- "packedBytes": 438088,
17
+ "bytes": 695410,
18
+ "packedBytes": 439180,
19
19
  "files": [
20
20
  {
21
21
  "id": "rapier-math",
22
- "name": "rapier-math-2.4.0.js",
23
- "version": "2.4.0",
24
- "bytes": 691650,
25
- "sri": "C92x26+pBI4q9FoWypMhBb8CqSGaaPLw8dpYigWiYNsYQRTcPVrFyPVjrhc/Tnwh"
22
+ "name": "rapier-math-2.5.0.js",
23
+ "version": "2.5.0",
24
+ "bytes": 695410,
25
+ "sri": "VDN0hcZbJ7LFS7fJjiUV/8THDfLxUWNfbGZQkggQptiaw4JaNAjZOmyK0kDRLNN3"
26
26
  }
27
27
  ]
28
28
  },
package/README.md CHANGED
@@ -2,28 +2,29 @@
2
2
 
3
3
  Turn Markdown into one offline HTML file that contains the full Rapier editor. It opens in any browser, on a phone or
4
4
  computer, with no account. People read, edit, draw and paint; agents hand over documents, show what changed and get
5
- the edited copy back. Start with `npx rapier-html@1.2.6 notes.md`.
5
+ the edited copy back. Start with `npx rapier-html@1.2.8 notes.md`.
6
6
 
7
7
  Use it for a plan to rearrange, a guide to annotate, a draft to keep writing, or a revision to review. The file works
8
8
  without any hosted workspace.
9
9
 
10
- - The page writes, draws and paints, saves Markdown, exports Word, PDF and a web page, and prints. It needs no account
11
- and fetches nothing to open, edit or save.
10
+ - The page writes, saves Markdown, exports Word, PDF and a web page, and prints. It needs no account and fetches
11
+ nothing to open, edit or save. It is the base editor (about 1.7 MB) with the plug-ins the document displays with
12
+ (Math, Mermaid); `--include draw` adds drawing and painting. Notes never travel.
12
13
  - `--return` adds a one-use Send back address from the agent door.
13
14
  - `--view draw` opens on Draw. `--compare original.md` opens the edit with its diff; `--by <name>` attributes it.
14
- - `wrap` and `unwrap` move a document into a page and back out, exactly.
15
+ - `writePage(text, name)` makes the page in one call; `unwrap` gives the document back, exactly.
15
16
 
16
17
  Needs Node 22 or newer.
17
18
 
18
19
  ```sh
19
- npx -- rapier-html@1.2.6 notes.md # the editor, notes.md inside it, written beside the file
20
- npx -- rapier-html@1.2.6 notes.md --view draw # opens on Draw: sketch and paint, the document behind it
21
- npx -- rapier-html@1.2.6 notes.md --view notes # opens the Notes library
22
- npx -- rapier-html@1.2.6 notes.md --drawing sketch.svg # carries a drawing, opened on Draw over the document
23
- npx -- rapier-html@1.2.6 revised.md --compare original.md # opens showing what changed
24
- npx -- rapier-html@1.2.6 notes.md --return "$RETURN_URL" --return-expires-at "$RETURN_EXPIRES_AT" # Send back
25
- npx -- rapier-html@1.2.6 notes.md out.html # a named output
26
- npm install rapier-html@1.2.6 # as a library: wrap, unwrap
20
+ npx -- rapier-html@1.2.8 notes.md # the editor, notes.md inside it, written beside the file
21
+ npx -- rapier-html@1.2.8 notes.md --view draw # opens on Draw: sketch and paint, the document behind it
22
+ npx -- rapier-html@1.2.8 notes.md --include draw,math # carries Draw and Math (default: what the document needs)
23
+ npx -- rapier-html@1.2.8 notes.md --drawing sketch.svg # carries a drawing, opened on Draw over the document
24
+ npx -- rapier-html@1.2.8 revised.md --compare original.md # opens showing what changed
25
+ npx -- rapier-html@1.2.8 notes.md --return "$RETURN_URL" --return-expires-at "$RETURN_EXPIRES_AT" # Send back
26
+ npx -- rapier-html@1.2.8 notes.md out.html # a named output
27
+ npm install rapier-html@1.2.8 # as a library: writePage, unwrap
27
28
  ```
28
29
 
29
30
  The first `--` is for npm, so `--help` reaches the command. It never overwrites a file.
@@ -59,20 +60,21 @@ current document. After expiry or a refusal, Share offers Save instead; bring th
59
60
  Save this as `example.mjs` in the folder you installed into, then run `node example.mjs`:
60
61
 
61
62
  ```js
62
- import {readFile, writeFile} from 'node:fs/promises';
63
- import {wrap, unwrap} from 'rapier-html';
63
+ import {writeFile} from 'node:fs/promises';
64
+ import {writePage, unwrap} from 'rapier-html';
64
65
 
65
- const rapier = await readFile(new URL('./rapier.html', import.meta.resolve('rapier-html')), 'utf8');
66
66
  const words = '# Hello\r\n\r\nA note about </script> and C:\\Users\\me.\n';
67
- const page = wrap(rapier, words, 'hello.md', {view: 'draw'}); // opens on Draw, the note behind it
67
+ const page = await writePage(words, 'hello.md', {view: 'draw'}); // opens on Draw, the note behind it
68
68
  console.log('words back exactly:', unwrap(page).text === words);
69
69
  await writeFile('hello.rapier.html', page, {flag: 'wx'}); // 'wx': never over an existing file
70
70
  ```
71
71
 
72
- - `wrap(rapierHtml, text, name, {view, drawing, drawingName, base, baseName, by, at, return: returnURL, return_expires_at})`
72
+ - `writePage(text, name, {include, view, drawing, drawingName, base, baseName, by, at, return: returnURL, return_expires_at})`
73
+ carries the editor with what the document displays with (`include` names the parts: `drawing`, `math`, `mermaid`).
74
+ - `wrap(rapierHtml, text, name, options)` does the same into a page you supply; `carry(rapierHtml, parts)` cuts one.
73
75
  - `unwrap(pageHtml)` returns the same fields, plus the validated `comparisonBase` record, with `null` for anything the
74
76
  page doesn't carry.
75
- - Also exported: `encodeCarried`, `decodeCarried` and `main`.
77
+ - Also exported: `portableNeeds`, `encodeCarried`, `decodeCarried` and `main`. TypeScript declarations ship in `dist/page.d.mts`.
76
78
 
77
79
  ## How the page carries the document
78
80
 
package/dist/cli.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ // SPDX-License-Identifier: MIT
2
3
  import {dirname} from 'node:path';
3
4
  import {fileURLToPath} from 'node:url';
4
5
  import {main} from './page.mjs';
@@ -0,0 +1,59 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // rapier-html: Markdown to one offline HTML file that carries its exact source, and back.
3
+ export type Part = 'drawing' | 'math' | 'mermaid';
4
+ export type DocKind = 'markdown' | 'text' | 'code';
5
+ export interface WrapOptions {
6
+ kind?: DocKind;
7
+ /** The view the page opens on, with the document behind it. */
8
+ view?: 'draw' | 'notes';
9
+ /** An SVG drawing carried beside the document, opened on Draw. */
10
+ drawing?: string;
11
+ drawingName?: string;
12
+ /** The original text (or a page carrying it); the page opens showing the diff. */
13
+ base?: string;
14
+ baseName?: string;
15
+ /** With base: the name and time shown on the diff. */
16
+ by?: string;
17
+ at?: string;
18
+ /** A one-use return URL and its expiry, both from the door's show {target: "return"}. */
19
+ return?: string;
20
+ return_expires_at?: string;
21
+ /** A rapier-ledger/2 history and its authorship projection, verified against the text. */
22
+ ledger?: unknown;
23
+ authorship?: unknown;
24
+ }
25
+ export interface Unwrapped {
26
+ /** The exact carried source, or null for a page without one. */
27
+ text: string | null;
28
+ name: string | null;
29
+ kind: DocKind | null;
30
+ view: 'draw' | 'notes' | null;
31
+ drawing: string | null;
32
+ drawingName: string | null;
33
+ base: string | null;
34
+ baseName: string | null;
35
+ baseSha256: string | null;
36
+ baseRevision: string | null;
37
+ by: string | null;
38
+ at: string | null;
39
+ return: string | null;
40
+ return_expires_at: string | null;
41
+ ledger: unknown;
42
+ authorship: unknown;
43
+ comparisonBase: unknown;
44
+ html: string;
45
+ }
46
+ /** Markdown to a page in one call: the editor this package carries, cut to what the document displays with. */
47
+ export function writePage(text: string, name?: string, options?: WrapOptions & {include?: Part[]}): Promise<string>;
48
+ /** Puts the document into a Rapier page you supply (for example a carry() of the packaged page). */
49
+ export function wrap(pageHtml: string, text: string, name?: string, options?: WrapOptions): string;
50
+ /** Reads the exact document back out of a page. */
51
+ export function unwrap(pageHtml: string): Unwrapped;
52
+ /** The page with only the named parts inline. */
53
+ export function carry(pageHtml: string, include?: Part[]): string;
54
+ /** The parts a document displays with: math, mermaid. */
55
+ export function portableNeeds(text: string, options?: {base?: string; flowchart?: (source: string) => boolean}): Part[];
56
+ export function encodeCarried(text: string): string;
57
+ export function decodeCarried(text: string): string;
58
+ /** The command line: rapier-html <document.md> [out.html] [options]. Resolves the written path, or null for --help. */
59
+ export function main(argv: string[], pagesDir: string, options?: {log?: (line: string) => void}): Promise<string | null>;
package/dist/page.mjs CHANGED
@@ -1,14 +1,26 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  import {readFile, writeFile} from 'node:fs/promises';
3
3
  import {basename, dirname, join} from 'node:path';
4
- import {wrap} from './wrap.mjs';
4
+ import {wrap, carry, portableNeeds} from './wrap.mjs';
5
5
  import {returnAddress, returnExpiresAt} from './return-address.mjs';
6
- export {wrap, unwrap, encodeCarried, decodeCarried} from './wrap.mjs';
6
+ export {wrap, unwrap, carry, portableNeeds, encodeCarried, decodeCarried} from './wrap.mjs';
7
+
8
+ // The page this package carries, read once on first use.
9
+ let carried = null;
10
+ const carriedPage = () => carried ??= readFile(new URL('./rapier.html', import.meta.url), 'utf8');
11
+ // One call from Markdown to a page: the carried editor, cut to what the document displays with (and Draw for
12
+ // view 'draw' or a drawing), with the document inside. `include` names the parts instead: drawing, math, mermaid.
13
+ export async function writePage(text, name = 'document.md', {include, ...options} = {}) {
14
+ const carries = include ?? [...(options.view === 'draw' || options.drawing != null ? ['drawing'] : []), ...portableNeeds(String(text), {base: options.base})];
15
+ return wrap(carry(await carriedPage(), carries), text, name, options);
16
+ }
7
17
  // Unknown options, a bare --drawing or --compare and a third name are refused.
8
- const USAGE = 'usage: rapier-html <document.md> [out.html] [--view draw|notes] [--drawing sketch.svg] [--compare original.md [--by <your name>]] [--return <url> --return-expires-at <timestamp>]\n' +
18
+ const USAGE = 'usage: rapier-html <document.md> [out.html] [--include draw,math,mermaid] [--view draw] [--drawing sketch.svg] [--compare original.md [--by <your name>]] [--return <url> --return-expires-at <timestamp>]\n' +
9
19
  ' writes <document>.rapier.html beside the file: Rapier with the document inside it, one file, offline.\n' +
10
20
  ' It never overwrites: an output that already exists, the document itself included, is refused.\n' +
11
- ' --view opens the page on Draw (sketch and paint, the document behind it) or on Notes\n' +
21
+ ' --include what the file carries beyond the base editor: draw (drawing and painting), math, mermaid, or none;\n' +
22
+ ' by default, the plug-ins the document displays with, and Draw for --view draw or --drawing\n' +
23
+ ' --view draw: opens the page on Draw (sketch and paint, the document behind it)\n' +
12
24
  ' --drawing carries an SVG drawing alongside the document, opened on Draw as the page boots\n' +
13
25
  ' --compare carries the original text; the page opens showing its diff from the current document\n' +
14
26
  ' --by with --compare: the name shown on the diff with the time the page was made\n' +
@@ -21,16 +33,22 @@ const text = async path => { try { return new TextDecoder('utf-8', {fatal: true,
21
33
 
22
34
  export async function main(argv, pagesDir, {log = console.log} = {}) {
23
35
  const names = [];
24
- let drawingPath = null, basePath = null, by = null, view = null, address = null, expiry = null, onlyNames = false;
36
+ let drawingPath = null, basePath = null, by = null, view = null, address = null, expiry = null, include = null, onlyNames = false;
25
37
  for (let i = 0; i < argv.length; i++) {
26
38
  const arg = argv[i];
27
39
  if (onlyNames || !arg.startsWith('-')) names.push(arg);
28
40
  else if (arg === '--') onlyNames = true;
29
41
  else if (arg === '--help') { log(USAGE); return null; }
30
42
  else if (arg === '--view') {
31
- if (view !== null || !['draw', 'notes'].includes(argv[i + 1])) throw new Error('--view takes draw or notes');
43
+ if (view !== null || argv[i + 1] !== 'draw') throw new Error('--view takes draw');
32
44
  view = argv[++i];
33
45
  }
46
+ else if (arg === '--include') {
47
+ const listed = argv[i + 1] === 'none' ? [] : String(argv[i + 1] || '').split(',');
48
+ if (include !== null || listed.some(item => !['draw', 'math', 'mermaid'].includes(item))) throw new Error('--include takes draw, math and mermaid, comma-separated, or none');
49
+ include = listed.map(item => item === 'draw' ? 'drawing' : item);
50
+ i++;
51
+ }
34
52
  else if (arg === '--compare') {
35
53
  if (basePath !== null || !argv[i + 1] || argv[i + 1].startsWith('-')) throw new Error('--compare takes one text file (write a name that starts with a dash as ./-original.md)');
36
54
  basePath = argv[++i];
@@ -66,9 +84,12 @@ export async function main(argv, pagesDir, {log = console.log} = {}) {
66
84
  if (address) wrapOptions.return = address;
67
85
  if (expiry) wrapOptions.return_expires_at = expiry;
68
86
  // Always a new file; 'wx' refuses any existing path, links included.
69
- try { await writeFile(out, wrap(page, source, name, wrapOptions), {flag: 'wx'}); }
87
+ const carries = include || [...(view === 'draw' || drawingPath ? ['drawing'] : []), ...portableNeeds(source, {base: wrapOptions.base})];
88
+ const html = wrap(carry(page, carries), source, name, wrapOptions);
89
+ try { await writeFile(out, html, {flag: 'wx'}); }
70
90
  catch (error) { throw error.code === 'EEXIST' ? new Error(out + ' already exists, and rapier-html never overwrites a file: name a new one') : error; }
71
- log(out + ' (' + name + ', ' + Buffer.byteLength(source) + ' bytes of document' +
72
- (view ? ', opens on ' + (view === 'draw' ? 'Draw' : 'Notes') : '') + (drawingPath ? ', ' + basename(drawingPath) + ' drawing' : '') + (basePath ? ', its diff from ' + basename(basePath) : '') + ')');
91
+ const labels = {drawing: 'Draw', math: 'Math', mermaid: 'Mermaid'};
92
+ log(out + ' (' + name + ', ' + Buffer.byteLength(source) + ' bytes of document, ' + Buffer.byteLength(html) + ' bytes in all, the base editor' +
93
+ [...new Set(carries)].map(id => ' + ' + labels[id]).join('') + (view ? ', opens on Draw' : '') + (drawingPath ? ', ' + basename(drawingPath) + ' drawing' : '') + (basePath ? ', its diff from ' + basename(basePath) : '') + ')');
73
94
  return out;
74
95
  }