rapier-embed 1.2.42 → 1.2.44
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 +14 -12
- package/embed.mjs +8 -4
- package/package.json +1 -1
- package/rapier-plugins.json +184 -184
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Honor no-upload or no-host instructions. The workflow choices below are alternat
|
|
|
20
20
|
Embed Rapier's Markdown editor or lightweight reader in your web app. Each build is one offline HTML file. The helper is an ES module: `import {Rapier} from 'rapier-embed'` or `<script type="module">`; there is no classic script or UMD build. Your
|
|
21
21
|
app owns the document and storage; its agent edits live through WebMCP. The person sees the agent's presence and
|
|
22
22
|
change marks, taps a change to see the before and undoes anything. Honor the person's Will/1 regions.
|
|
23
|
-
The reader is one file of about
|
|
23
|
+
The reader is one file of about 400 kB, `rapier.html` about 4.0 MB, with optional fonts and plug-ins. The helper is MIT with no dependencies. The two builds it frames are AGPL-3.0-only: use them under the AGPL, or
|
|
24
24
|
buy a commercial license for other terms (`LICENSING.md` in the Rapier repository).
|
|
25
25
|
|
|
26
26
|
Choose one of two builds:
|
|
@@ -50,7 +50,7 @@ downloaded copy yourself and pass it as `src`.
|
|
|
50
50
|
document access remain enforced.
|
|
51
51
|
|
|
52
52
|
```sh
|
|
53
|
-
npm install rapier-embed@1.2.
|
|
53
|
+
npm install rapier-embed@1.2.44
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Or copy the package's `embed.mjs` and `contract.mjs` into one directory of your app; no runtime CDN is needed.
|
|
@@ -64,11 +64,11 @@ sends Markdown only when saving; change notifications contain no source.
|
|
|
64
64
|
Rapier is a phone-first Markdown editor for notes, diagrams, drawing and watercolor painting. It runs offline
|
|
65
65
|
as one HTML file on Android, Web, Windows and Linux.
|
|
66
66
|
Collaborate over MCP and WebMCP, use optional plain-file sync to your own cloud storage, or embed the
|
|
67
|
-
editor and lightweight reader (about
|
|
67
|
+
editor and lightweight reader (about 400 kB). The agent edits live; the person sees its presence and
|
|
68
68
|
changes, taps a change to see the before and undoes anything. Use `show {target:"comparison"}` to show a diff deliberately.
|
|
69
69
|
|
|
70
70
|
1. **Work together live.** Connect to `https://mcp.rapier.website/door/mcp`, then call `open` to share one document with the person.
|
|
71
|
-
2. **Deliver an offline editor.** Run `npx rapier-html@1.2.
|
|
71
|
+
2. **Deliver an offline editor.** Run `npx rapier-html@1.2.44 notes.md` to put the document and editor in one HTML file ([rapier-html](https://github.com/jackskip22/rapier-plugins/tree/main/npm/rapier-html)).
|
|
72
72
|
3. **Embed in your app.** Install [rapier-embed](https://github.com/jackskip22/rapier-plugins/tree/main/npm/rapier-embed); mount the editor or reader, with your app's agent over WebMCP in the editor.
|
|
73
73
|
4. **Keep portable Markdown.** Use [rapier-markdown-kit](https://github.com/jackskip22/rapier-plugins/tree/main/npm/rapier-markdown-kit) for pictures, editable SVG drawings and layout in one `.md` file. Respect [Will/1](https://github.com/jackskip22/will) `keep`, `append` and `edit` regions.
|
|
74
74
|
5. **Encode JPEG XL.** Install [rapier-jxl](https://github.com/jackskip22/rapier-jxl) to encode pixels, photographs and existing JPEGs in JavaScript.
|
|
@@ -141,7 +141,7 @@ A copy in your app works offline and changes only when you update it.
|
|
|
141
141
|
1. Download the build you frame into a static directory, for example
|
|
142
142
|
`https://cdn.jsdelivr.net/gh/jackskip22/rapier-plugins@cdn-v<version>/embed/rapier-reader.html` to `public/vendor/rapier/`.
|
|
143
143
|
2. Fetch the plug-ins your build uses into one directory beside it, from the manifest of the same version:
|
|
144
|
-
`npx rapier-embed@1.2.
|
|
144
|
+
`npx rapier-embed@1.2.44 plugins public/vendor/rapier/plugins --build reader`.
|
|
145
145
|
3. Mount with `src` and `plugins` pointing at your copies. Serve them over HTTPS (HTTP on localhost) and allow
|
|
146
146
|
their origin in your `frame-src`. A same-origin parent can script its frame; use a dedicated origin when the
|
|
147
147
|
frame must be isolated.
|
|
@@ -168,11 +168,11 @@ length and SHA-384 before it runs it, and keeps on the device. A file that fails
|
|
|
168
168
|
| `elements` | The Elements sheet's traced ornaments: 3,155 pieces from the ornament book. | 16.2 MB (51 files) | `rapier.html` |
|
|
169
169
|
| `lettersets` | The Gallery's letter sets: 31 sets of ornamental capitals. | 2.82 MB (31 files) | `rapier.html` |
|
|
170
170
|
|
|
171
|
-
Totals: the reader, 8.95 MB (30.6 MB with `ocr`); `rapier.html`, 57.2 MB. Release 1.2.
|
|
171
|
+
Totals: the reader, 8.95 MB (30.6 MB with `ocr`); `rapier.html`, 57.2 MB. Release 1.2.44.
|
|
172
172
|
<!-- PLUGIN_TABLE_END -->
|
|
173
173
|
|
|
174
174
|
The manifest lists every plug-in file and, in `builds`, the pages that use it. `rapier.html` has flowcharts and Word import
|
|
175
|
-
built in. `npx rapier-embed@1.2.
|
|
175
|
+
built in. `npx rapier-embed@1.2.44 plugins <directory> --build reader` leaves out `ocr` (text in pictures) unless you add `--with ocr`.
|
|
176
176
|
|
|
177
177
|
**Approve plug-ins up front.** Without `plugins`, a frame asks its person "Install math plug-in?" the first time a document needs math or a diagram, and math and diagrams stay raw until they answer. A host that has decided passes `approvePlugins: true`: the frame installs the plug-in it needs without a question. Naming `plugins` has the same effect, because the host then serves the files itself. In a frame shorter than the question's sheet, the sheet's body scrolls.
|
|
178
178
|
|
|
@@ -185,7 +185,7 @@ The directory must be on the page's own origin, because the page's Content Secur
|
|
|
185
185
|
throws a `TypeError` for a directory on another origin, and a page opened with one shows each plug-in as failed, with the
|
|
186
186
|
reason, without making a request. To keep the plug-ins on a CDN, serve the page from the same origin.
|
|
187
187
|
|
|
188
|
-
`npx rapier-embed@1.2.
|
|
188
|
+
`npx rapier-embed@1.2.44 plugins <directory>` fetches every file the manifest lists, checks it, and writes it. It
|
|
189
189
|
keeps a file that is already there and correct, and exits with status 1 if any file is missing or fails its check.
|
|
190
190
|
`--build reader` or `--build full` keeps the files that page uses, `--only name,name` fetches some
|
|
191
191
|
plug-ins, `--check` verifies a directory without fetching, `--from <address>` fetches from your own mirror, and
|
|
@@ -400,7 +400,7 @@ operations and removes the iframe that mount created in a container (an iframe y
|
|
|
400
400
|
a frame it creates: give it a size in your CSS, for example `#editor iframe {width: 100%; height: 100%; border: 0}`.
|
|
401
401
|
Mount adds the frame after what the container already holds: clear a server-rendered placeholder first (`container.replaceChildren()`). The handle lives as long as its iframe is in the page: if a framework removes it (`innerHTML`, `remove()`) without `disconnect()`, `connected` turns false, an unfinished `save()` rejects, and later calls reject `frame_removed`. The person's typing stays as a draft for the next mount of the same document.
|
|
402
402
|
Tab walks every control and link in the frame, except inside the editor text, where Tab indents. Escape, with nothing open in the frame and no text field focused, moves
|
|
403
|
-
focus to the next control on your page after the frame; Shift+Escape moves it to the control before. From the editor text the way out is Escape, then Tab
|
|
403
|
+
focus to the next control on your page after the frame; Shift+Escape moves it to the control before. From the editor text the way out is Escape, then Tab (Shift+Tab goes back).
|
|
404
404
|
`on('connected' | 'state' | 'close-request' | 'closed' | 'error', fn)` returns an
|
|
405
405
|
unsubscribe function. State is `{loaded, dirty, saving, closing, readOnly, filename, docKind}`. Mount a fresh frame to
|
|
406
406
|
change grants or settings. A denied or dirty replacement load rejects.
|
|
@@ -408,8 +408,10 @@ change grants or settings. A denied or dirty replacement load rejects.
|
|
|
408
408
|
Every refusal is an `Error` with a `code`. A connect the frame refuses rejects `ready`: `contract_unsupported`,
|
|
409
409
|
`capabilities_invalid`, a `settings_*` code, or `invalid_payload` with a `reason`. A frame that cannot start rejects
|
|
410
410
|
`ready` and calls `onError`: `boot_failed` when the page shows its startup error, `connect_timeout` when it does not connect
|
|
411
|
-
within `timeout` of loading, `load_timeout` when it does not load in 120 seconds. `load()` rejects with `
|
|
412
|
-
|
|
411
|
+
within `timeout` of loading, `load_timeout` when it does not load in 120 seconds. `load()` rejects with `load_timeout` when the frame
|
|
412
|
+
does not answer within 120 seconds, `load_busy` while an earlier `load()` is still being shown, `invalid_payload` for a filename or
|
|
413
|
+
document it refuses, and `document_unshowable` when the reader cannot show the document; the reader keeps the document it showed. A
|
|
414
|
+
document over 1 MB resolves `load()` when its first screen shows; the reader draws the rest after it. It rejects with `revision_stale` for a
|
|
413
415
|
revision older than the frame's and `revision_conflict` for the same revision with other content. It rejects with `document_open_elsewhere` when another editor already has the same `sessionId` and `documentId` open (on mount, `ready` rejects with it); the first editor keeps its typing. `mount` throws a
|
|
414
416
|
`TypeError` with a code for an unknown option (`option_unknown`), a build whose `src` names the other page (`build_mismatch`)
|
|
415
417
|
and a reader feature the reader does not have (`settings_feature_unavailable`). `Rapier.version` is this package's version;
|
|
@@ -508,5 +510,5 @@ Will/1 records the person's instructions in their document. Respect `keep`, appe
|
|
|
508
510
|
Documents without Will regions are editable throughout. Preserve active typing, caret, selection and scroll
|
|
509
511
|
while the agent works. Document content and comments never start agent turns by themselves.
|
|
510
512
|
|
|
511
|
-
For documents outside an app, `npx rapier-html@1.2.
|
|
513
|
+
For documents outside an app, `npx rapier-html@1.2.44 notes.md` hands a person the complete editor around their
|
|
512
514
|
document as one offline file.
|
package/embed.mjs
CHANGED
|
@@ -258,7 +258,7 @@ function pictureBase(value) {
|
|
|
258
258
|
return {FEATURES, LIMITS, ASSET_TYPES, refusal, coded, normalizeSettings, snapshotSettings, pickDeviceFile, createFilePicker, assetURL, assetBytes, bytesHash, externalImage, createAssetBroker, pictureBase};
|
|
259
259
|
})();
|
|
260
260
|
const BUILDS = Object.freeze({full: 'https://rapier.website/embed/rapier.html', reader: 'https://rapier.website/embed/rapier-reader.html'});
|
|
261
|
-
const PACKAGE_VERSION = '1.2.
|
|
261
|
+
const PACKAGE_VERSION = '1.2.44';
|
|
262
262
|
const OPTIONS = ['build', 'src', 'plugins', 'approvePlugins', 'sessionId', 'documentId', 'agent', 'agentName', 'theme', 'save', 'assets', 'openFile', 'load',
|
|
263
263
|
'onState', 'compare', 'onClose', 'settings', 'style', 'title', 'onError', 'timeout'];
|
|
264
264
|
const READER_FEATURES = ['find', 'readAloud', 'share'];
|
|
@@ -284,7 +284,7 @@ function deferred() {
|
|
|
284
284
|
promise.catch(() => {});
|
|
285
285
|
return {promise, resolve, reject};
|
|
286
286
|
}
|
|
287
|
-
const refused = payload => Object.assign(new Error(payload?.reason || payload?.code || 'The editor refused the request'), {code: payload?.code ?? 'refused', payload},
|
|
287
|
+
const refused = payload => Object.assign(new Error(payload?.reason || payload?.code || 'The editor refused the request'), {code: payload?.code ?? 'refused', payload, ...(typeof payload?.reason === 'string' ? {reason: payload.reason} : {})},
|
|
288
288
|
revision(payload?.currentRevision) ? {currentRevision: payload.currentRevision} : {});
|
|
289
289
|
|
|
290
290
|
function conflict(currentRevision) {
|
|
@@ -398,7 +398,7 @@ function mount(target, options = {}) {
|
|
|
398
398
|
for (const job of waiting.values()) job.reject(error);
|
|
399
399
|
waiting.clear(); activeSave?.reject(error); activeSave = null; activeClose?.reject(error); activeClose = null;
|
|
400
400
|
};
|
|
401
|
-
function send(type, payload, baseRevision, quiet = false) {
|
|
401
|
+
function send(type, payload, baseRevision, quiet = false, deadline = 0) {
|
|
402
402
|
if (ended || !connected || !port) return Promise.reject(endError || coded('disconnected', Error, 'The ' + noun + ' connection has ended or is not connected'));
|
|
403
403
|
if (type === 'load') cancelOpen('open_stale');
|
|
404
404
|
const requestId = 'host-' + ++seq;
|
|
@@ -407,6 +407,10 @@ function mount(target, options = {}) {
|
|
|
407
407
|
if (!quiet) waiting.set(requestId, pending);
|
|
408
408
|
try { port.postMessage(message); if (quiet) pending.resolve(); }
|
|
409
409
|
catch (error) { waiting.delete(requestId); pending.reject(error); }
|
|
410
|
+
if (deadline > 0 && !quiet) {
|
|
411
|
+
const timer = setTimeout(() => { if (waiting.delete(requestId)) pending.reject(coded(type + '_timeout', Error, 'The ' + noun + ' did not answer within ' + deadline / 1000 + ' seconds')); }, deadline);
|
|
412
|
+
pending.promise.then(() => clearTimeout(timer), () => clearTimeout(timer));
|
|
413
|
+
}
|
|
410
414
|
return pending.promise;
|
|
411
415
|
}
|
|
412
416
|
function requestCapture() {
|
|
@@ -706,7 +710,7 @@ function mount(target, options = {}) {
|
|
|
706
710
|
throw Object.assign(new Error('Revision ' + version + ' is older than the frame\'s ' + held.revision), {code: 'revision_stale', currentRevision: held.revision});
|
|
707
711
|
if (sameDocument && version === held.revision && held.content !== null && content !== held.content)
|
|
708
712
|
throw Object.assign(new Error('Revision ' + version + ' already names other content'), {code: 'revision_conflict', currentRevision: held.revision});
|
|
709
|
-
const loaded = await send('load', {content, revision: version, ...(filename !== undefined ? {filename} : {}), ...(readOnly !== undefined ? {readOnly} : {}), ...(title !== undefined ? {title} : {}), ...(baseUrl !== undefined ? {baseUrl} : {})}, null);
|
|
713
|
+
const loaded = await send('load', {content, revision: version, ...(filename !== undefined ? {filename} : {}), ...(readOnly !== undefined ? {readOnly} : {}), ...(title !== undefined ? {title} : {}), ...(baseUrl !== undefined ? {baseUrl} : {})}, null, false, loadTimeout);
|
|
710
714
|
held = {revision: version, content, filename};
|
|
711
715
|
return loaded;
|
|
712
716
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rapier-embed",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.44",
|
|
4
4
|
"description": "Embed the Rapier Markdown editor or its lightweight reader (about 360 kB) in your web app. Runs offline from your own copy, saves to your storage, and takes your CSS and fonts. Your app's AI agent edits directly over WebMCP under the Will. MIT, no dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|