Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
# `pem/pem` — RFC 7468 PEM framing
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Decodes PEM-encoded blobs per RFC 7468 paragraph 5 and re-encodes byte content into the canonical `-----BEGIN <LABEL>-----` / `-----END <LABEL>-----` framed form with 64-column-wrapped base64. Used by `parseCertificate` (accepts DER or PEM) and `TrustAnchorStore` (PEM-bundle constructor). Multi-cert bundles are returned in declaration order so a single PEM file holding root + intermediate(s) preserves the chain shape callers expect.
## Features
- Multi-block decode — every `BEGIN/END` pair in a single text input produces a `PemBlock` entry.
- `\r\n` and `\n` line-ending tolerance.
- Strict base64 alphabet check (`A-Za-z0-9+/=`) plus length-multiple-of-4 check.
- 64-column line wrapping on encode (RFC 7468 paragraph 4 default).
- Label whitelist on encode (`[A-Z0-9 ]+`).
- Empty input and missing END marker throw `X509Error(PEM_MALFORMED)`.
## Usage: Basic Example
```ts
import { decodePem, encodePem } from "@suaveplan/x509/pem";
const blocks = decodePem(`-----BEGIN CERTIFICATE-----
MIIBxjCCAW2gAwIBAgIQ...
-----END CERTIFICATE-----`);
// blocks[0].label === "CERTIFICATE"; blocks[0].bytes is a Uint8Array
const text = encodePem("CERTIFICATE", blocks[0].bytes);
```
## Usage: Advanced Example
```ts
import { decodePem } from "@suaveplan/x509/pem";
// Trust-anchor bundle with three roots concatenated:
const bundle = `${rootA}\n${rootB}\n${rootC}`;
const blocks = decodePem(bundle);
// blocks.length === 3, ordering preserved.
// Windows line endings tolerated:
const win = bundle.replace(/\n/g, "\r\n");
const sameBlocks = decodePem(win);
```
## API Reference
- `decodePem(text: string): PemBlock[]` — returns the array of blocks in declaration order. Throws `X509Error(PEM_MALFORMED)` on empty input, missing END marker, bad base64, or label/body mismatch.
- `encodePem(label: string, bytes: Uint8Array): string` — wraps the body at 64 columns, terminates with `\n`. Throws `X509Error(PEM_MALFORMED)` on labels outside the `[A-Z0-9 ]+` alphabet.
- `PemBlock { label: string; bytes: Uint8Array }`.
## Implementation Notes
- The decoder normalises `\r\n` to `\n` once at entry, then operates on the normalised text. This is simpler and faster than matching `\r?\n` in every position.
- `BEGIN`-pattern matching uses a non-greedy capture so labels with embedded spaces work (`X509 CRL`, `RSA PRIVATE KEY`).
- The label-on-encode whitelist is intentionally narrow — RFC 7468 paragraph 2 allows hyphens but every real-world usage stays inside `[A-Z0-9 ]+`. Callers needing exotic labels should escape upstream.
- `atob`/`btoa` are used when present (every modern browser and Node 16+); the package falls back to `Buffer.from` on legacy Node builds without `atob`.