typewright 0.2.1

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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +168 -0
  3. package/SPEC.md +327 -0
  4. package/dist/chunk-CZQO7TTL.js +1533 -0
  5. package/dist/chunk-CZQO7TTL.js.map +1 -0
  6. package/dist/chunk-KNEKNZXK.js +286 -0
  7. package/dist/chunk-KNEKNZXK.js.map +1 -0
  8. package/dist/chunk-M6IVEMXO.js +1398 -0
  9. package/dist/chunk-M6IVEMXO.js.map +1 -0
  10. package/dist/chunk-NJ7PJKHN.js +652 -0
  11. package/dist/chunk-NJ7PJKHN.js.map +1 -0
  12. package/dist/commands-Z3ndUSza.d.cts +221 -0
  13. package/dist/commands-Z3ndUSza.d.ts +221 -0
  14. package/dist/core/index.cjs +2952 -0
  15. package/dist/core/index.cjs.map +1 -0
  16. package/dist/core/index.d.cts +410 -0
  17. package/dist/core/index.d.ts +410 -0
  18. package/dist/core/index.js +4 -0
  19. package/dist/core/index.js.map +1 -0
  20. package/dist/mdx/index.cjs +662 -0
  21. package/dist/mdx/index.cjs.map +1 -0
  22. package/dist/mdx/index.d.cts +252 -0
  23. package/dist/mdx/index.d.ts +252 -0
  24. package/dist/mdx/index.js +3 -0
  25. package/dist/mdx/index.js.map +1 -0
  26. package/dist/react/index.cjs +7439 -0
  27. package/dist/react/index.cjs.map +1 -0
  28. package/dist/react/index.d.cts +140 -0
  29. package/dist/react/index.d.ts +140 -0
  30. package/dist/react/index.js +3644 -0
  31. package/dist/react/index.js.map +1 -0
  32. package/dist/streaming/index.cjs +1494 -0
  33. package/dist/streaming/index.cjs.map +1 -0
  34. package/dist/streaming/index.d.cts +64 -0
  35. package/dist/streaming/index.d.ts +64 -0
  36. package/dist/streaming/index.js +4 -0
  37. package/dist/streaming/index.js.map +1 -0
  38. package/dist/types-CX1GOx0Y.d.cts +319 -0
  39. package/dist/types-CX1GOx0Y.d.ts +319 -0
  40. package/package.json +128 -0
@@ -0,0 +1,252 @@
1
+ import { S as SandboxOptions, k as MdxTransform } from '../types-CX1GOx0Y.js';
2
+ export { e as ComponentMap, M as MathOptions, j as MdxOptions, l as MermaidOptions } from '../types-CX1GOx0Y.js';
3
+
4
+ /**
5
+ * `src/sandbox/host.ts` — the opaque-origin execution sandbox (SPEC.md §7, §11).
6
+ *
7
+ * Anything executable (compiled MDX, Mermaid diagrams) runs here, never in the
8
+ * host document. The sandbox is a hidden `<iframe srcdoc sandbox="allow-scripts">`
9
+ * with an **opaque origin** — `allow-same-origin` is NEVER granted, so a payload
10
+ * cannot reach `parent.document`, storage, cookies, or the network beyond what
11
+ * the CSP permits. This closes the XSS→RCE escalation and is Electron-safe.
12
+ *
13
+ * Security model (why this is safe without origin checks)
14
+ * ------------------------------------------------------
15
+ * - The iframe is opaque-origin, so every message it posts arrives at the host
16
+ * with `event.origin === "null"`. Origin therefore cannot authenticate the
17
+ * channel. Instead we validate:
18
+ * 1. `event.source === iframe.contentWindow` — the message really came from
19
+ * *our* frame (not a sibling frame or another window), and
20
+ * 2. `message.token === <per-instance random token>` — the message carries
21
+ * the secret channel token baked into this frame's `srcdoc`.
22
+ * Both must hold; mismatches are silently ignored. The same token+source gate
23
+ * is applied *inside* the frame (it only accepts messages whose source is its
24
+ * `parent` and whose token matches).
25
+ * - The CSP baked into the srcdoc is `default-src 'none'` with only
26
+ * `'unsafe-inline'` scripts/styles (extendable via {@link SandboxOptions.csp}).
27
+ * Compiled modules run as DOM-inserted **inline** `<script>` elements — which
28
+ * `'unsafe-inline'` permits — so we never need `'unsafe-eval'`/`new Function`.
29
+ * - Compiled output renders **inside** the iframe (the iframe *is* the widget).
30
+ * The host never `innerHTML`s compiled output into its own tree. `evaluate`
31
+ * resolves with the produced `html` for informational/read-mode use only; the
32
+ * host must treat it as untrusted.
33
+ * - A component's legitimate host/network needs are brokered: code inside the
34
+ * frame calls `host(payload)` → `postMessage({type:'host', payload})` → the
35
+ * host's {@link SandboxOptions.onHostMessage}, which proxies the request.
36
+ *
37
+ * The message-validation and dispatch logic is factored into pure functions
38
+ * ({@link shouldAcceptMessage}, {@link dispatchInbound}, {@link buildSandboxCsp},
39
+ * {@link buildSandboxSrcdoc}) so the protocol is unit-testable without a real
40
+ * cross-origin frame (end-to-end iframe evaluation is covered by the e2e suite).
41
+ */
42
+
43
+ /** Result of evaluating a compiled module inside the sandbox. */
44
+ interface EvaluateResult {
45
+ /**
46
+ * Serialized HTML the module produced (already rendered inside the iframe).
47
+ * Informational only — the host MUST NOT inject this into its own DOM.
48
+ */
49
+ html?: string;
50
+ /** Measured content height of the iframe, for sizing the widget. */
51
+ height?: number;
52
+ /** Present when evaluation threw; the module never crashes the host. */
53
+ error?: string;
54
+ }
55
+ /** Result of rendering a Mermaid diagram inside the sandbox. */
56
+ interface MermaidResult {
57
+ /** The diagram SVG (already rendered inside the iframe). */
58
+ svg?: string;
59
+ height?: number;
60
+ error?: string;
61
+ }
62
+ /** Controller returned by {@link createSandbox}. */
63
+ interface SandboxController {
64
+ /**
65
+ * Evaluate a compiled module body inside the sandbox. `code` is a statement
66
+ * list that closes over the injected `h`, `components`, `props`, `host`, and
67
+ * `root`, and returns the rendered result (an HTML string, a DOM node, or
68
+ * nothing if it mounts into `root` itself). See the transform adapters in
69
+ * `src/mdx/transform.ts` for the code shape.
70
+ */
71
+ evaluate(code: string, props?: Record<string, unknown>): Promise<EvaluateResult>;
72
+ /** Render a Mermaid diagram source using the injected engine (if any). */
73
+ renderMermaid(src: string): Promise<MermaidResult>;
74
+ /** Tear down: remove the iframe, drop listeners, settle pending calls. */
75
+ destroy(): void;
76
+ }
77
+ /**
78
+ * Options for {@link createSandbox}. A superset of the public
79
+ * {@link SandboxOptions} with host-only injection points (an existing
80
+ * `SandboxOptions` is accepted as-is).
81
+ */
82
+ interface CreateSandboxOptions extends SandboxOptions {
83
+ /** Element to append the hidden iframe to (defaults to `document.body`). */
84
+ container?: HTMLElement;
85
+ /**
86
+ * Milliseconds before an `evaluate` / `renderMermaid` call resolves with a
87
+ * timeout error (never rejects). `0` disables the timeout. Defaults to 8000.
88
+ */
89
+ timeoutMs?: number;
90
+ /**
91
+ * JavaScript *source* of a Mermaid-compatible engine, inlined into the sandbox
92
+ * document (see {@link import('../types').MermaidOptions.getEngine}). Expected
93
+ * to define `self.__twMermaidRender(src)` or `self.mermaid`.
94
+ */
95
+ mermaidEngine?: string;
96
+ }
97
+ /** Normalized shape of an inbound result message from the frame. */
98
+ interface InboundResult {
99
+ html?: string;
100
+ svg?: string;
101
+ height?: number;
102
+ error?: string;
103
+ }
104
+ /**
105
+ * Decide whether an inbound `message` event should be trusted. Replaces the
106
+ * origin check (useless for an opaque-origin frame, where `event.origin` is
107
+ * always `"null"`) with a source-identity + secret-token check.
108
+ */
109
+ declare function shouldAcceptMessage(event: {
110
+ source?: unknown;
111
+ data?: unknown;
112
+ }, ctx: {
113
+ source: unknown;
114
+ token: string;
115
+ }): boolean;
116
+ /**
117
+ * Route a *trusted* inbound message to the right handler. `ready` unlocks the
118
+ * outbound queue, `host` is brokered to {@link SandboxOptions.onHostMessage},
119
+ * anything carrying a numeric `id` settles the matching pending call.
120
+ */
121
+ declare function dispatchInbound(data: Record<string, unknown>, handlers: {
122
+ onReady?: () => void;
123
+ onHost?: (payload: unknown) => void;
124
+ onResult?: (id: number, result: InboundResult) => void;
125
+ }): void;
126
+ /** The strict base CSP for the sandbox document; `extra` is appended. */
127
+ declare function buildSandboxCsp(extra?: string): string;
128
+ /** A per-instance random channel token. Prefers crypto; falls back gracefully. */
129
+ declare function createChannelToken(): string;
130
+ /**
131
+ * Build the sandbox document. Only trusted, fixed content is inlined here (the
132
+ * bootstrap and the optional engine source); per-evaluate module code is NEVER
133
+ * inlined into this string — it is injected at runtime via a script element's
134
+ * `textContent` (see the bootstrap), which is immune to `</script>` breakout.
135
+ */
136
+ declare function buildSandboxSrcdoc(params: {
137
+ token: string;
138
+ csp: string;
139
+ engineSource?: string;
140
+ }): string;
141
+ /**
142
+ * Create a hidden opaque-origin sandbox and return a controller for evaluating
143
+ * compiled modules and rendering Mermaid inside it. Requires a DOM (browser or
144
+ * jsdom). Debouncing is the caller's responsibility.
145
+ */
146
+ declare function createSandbox(opts?: CreateSandboxOptions): SandboxController;
147
+
148
+ /**
149
+ * `src/mdx/transform.ts` — MDX transform adapters (SPEC.md §7, step 2).
150
+ *
151
+ * Turning JSX/TS into runnable plain JS is the one conceded boundary. This
152
+ * module resolves an {@link MdxTransform} into a uniform async compile function
153
+ * `(code, meta?) => Promise<string>`:
154
+ *
155
+ * - `'wasm-esbuild'` → dynamically imports the OPTIONAL peer `esbuild-wasm`.
156
+ * - `'wasm-swc'` → dynamically imports the OPTIONAL peer `@swc/wasm-web`.
157
+ * Both peers are never bundled and never hard-imported; if absent, a clear
158
+ * Error naming the missing peer is thrown. The host is responsible for
159
+ * initializing the wasm engine (its `wasmURL` is environment-specific).
160
+ * - `'constrained'` → a built-in, ZERO-DEPENDENCY transform for a restricted
161
+ * MDX-JS subset (see grammar below). No external parser.
162
+ * - a function → returned as-is (host-supplied), wrapped to a Promise.
163
+ * - `undefined` → a transform that throws "no MDX transform configured"
164
+ * (the editor treats this as "render escaped source").
165
+ *
166
+ * ── Constrained subset (exact, compiled to `h(tag, props, ...children)`) ──────
167
+ * The constrained transform is a small hand-written recursive-descent parser for
168
+ * a bounded surface — deliberately NOT a general JS parser. It accepts:
169
+ *
170
+ * Module := (Line)* lines beginning with `import`/`export`
171
+ * (at column 0) are stripped/hoisted out
172
+ * Body := (Text | Element | Interp)* the remaining top-level content
173
+ * Element := '<' Name Attr* '/>'
174
+ * | '<' Name Attr* '>' Children '</' Name '>'
175
+ * Name := [A-Za-z][A-Za-z0-9._-]* Capitalized → component; the root
176
+ * identifier is bound from the map
177
+ * (`const Chart = components["Chart"]`) and the
178
+ * tag is emitted bare (`h(Chart, …)`, `h(Foo.Bar, …)`);
179
+ * lowercase → HTML string tag. A capitalized name
180
+ * whose segments aren't identifiers is rejected.
181
+ * Attr := Name boolean shorthand → `true`
182
+ * | Name '=' '"' … '"' string literal
183
+ * | Name '=' "'" … "'" string literal
184
+ * | Name '=' '{' Expr '}' restricted expression
185
+ * Children := (Text | Element | Interp)*
186
+ * Interp := '{' Expr '}' interpolation child
187
+ * Expr := number | 'true' | 'false' | 'null'
188
+ * | Identifier e.g. `name`
189
+ * | Identifier ('.' Identifier)+ simple member, e.g. `user.name`
190
+ * Text := run of chars that are not '<' or '{' (JSX entities untouched)
191
+ *
192
+ * Anything outside this subset (arrow functions, calls, operators, object/array
193
+ * literals, template strings, JSX fragments `<>…</>`, spread `{...x}`, mismatched
194
+ * tags, unterminated constructs) throws a clear Error — it never silently
195
+ * miscompiles. Hosts needing the full surface use `wasm-esbuild`/`wasm-swc`.
196
+ *
197
+ * Output shape: the compiled module is a statement list ending in a `return`,
198
+ * closing over the sandbox-injected `h`, `components`, and `props`. Example:
199
+ * `<Callout type="info">Hi {name}</Callout>` →
200
+ * const Callout = components["Callout"];
201
+ * return h(Callout, {"type": "info"}, "Hi ", name);
202
+ */
203
+
204
+ interface TransformMeta {
205
+ filename?: string;
206
+ }
207
+ type CompileFn = (code: string, meta?: TransformMeta) => Promise<string>;
208
+ /** Resolve an {@link MdxTransform} into a uniform async compile function. */
209
+ declare function resolveTransform(t: MdxTransform | undefined): CompileFn;
210
+ /** Compile the restricted MDX subset to a sandbox module string. */
211
+ declare function compileConstrained(source: string): string;
212
+
213
+ /**
214
+ * `typewright/mdx` — the sandboxed MDX/Mermaid execution boundary.
215
+ *
216
+ * Two pieces, kept separate on purpose (SPEC.md §7):
217
+ * - {@link resolveTransform} turns JSX/TS into plain JS (the one conceded
218
+ * dependency boundary — wasm peers or a zero-dep constrained subset).
219
+ * - {@link createSandbox} runs that plain JS inside an opaque-origin sandboxed
220
+ * iframe that cannot reach the host DOM, storage, or session.
221
+ *
222
+ * {@link compileAndRun} is the convenience that wires them together for a
223
+ * one-shot compile-and-render.
224
+ */
225
+
226
+ /** Options for {@link compileAndRun}. */
227
+ interface CompileAndRunOptions {
228
+ /** MDX/JSX source to compile. */
229
+ code: string;
230
+ /** How to transform it (defaults to `undefined` → throws "no transform"). */
231
+ transform?: MdxTransform;
232
+ /** Transform metadata (e.g. a filename to pick the tsx/jsx loader). */
233
+ meta?: TransformMeta;
234
+ /** Props passed to the evaluated module. */
235
+ props?: Record<string, unknown>;
236
+ /**
237
+ * Sandbox options for a freshly-created sandbox. Ignored when `controller`
238
+ * is supplied.
239
+ */
240
+ sandbox?: CreateSandboxOptions;
241
+ /** Reuse an existing sandbox instead of creating (and destroying) one. */
242
+ controller?: ReturnType<typeof createSandbox>;
243
+ }
244
+ /**
245
+ * Compile `code` with the resolved transform and evaluate it in a sandbox. When
246
+ * no `controller` is supplied a temporary sandbox is created and destroyed
247
+ * around the call. The compiled output renders inside the sandbox; the returned
248
+ * `html` is informational — never inject it into the host tree (SPEC.md §11).
249
+ */
250
+ declare function compileAndRun(opts: CompileAndRunOptions): Promise<EvaluateResult>;
251
+
252
+ export { type CompileAndRunOptions, type CompileFn, type CreateSandboxOptions, type EvaluateResult, type InboundResult, MdxTransform, type MermaidResult, type SandboxController, SandboxOptions, type TransformMeta, buildSandboxCsp, buildSandboxSrcdoc, compileAndRun, compileConstrained, createChannelToken, createSandbox, dispatchInbound, resolveTransform, shouldAcceptMessage };
@@ -0,0 +1,3 @@
1
+ export { buildSandboxCsp, buildSandboxSrcdoc, compileAndRun, compileConstrained, createChannelToken, createSandbox, dispatchInbound, resolveTransform, shouldAcceptMessage } from '../chunk-NJ7PJKHN.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}