Files
kandev/docs/plans/native-html-preview/task-05-script-capable-preview-runtime.md
2026-09-07 13:45:28 +01:00

4.2 KiB

id, title, status, wave, depends_on, plan, requirements, acceptance_criteria, system_design
id title status wave depends_on plan requirements acceptance_criteria system_design
05-script-capable-preview-runtime Build the capability-free preview runtime cancelled 1
plan.md
REQ-UI-NATIVE-HTML-PREVIEW-001
AC-UI-NATIVE-HTML-PREVIEW-001.3
AC-UI-NATIVE-HTML-PREVIEW-001.4
AC-UI-NATIVE-HTML-PREVIEW-001.5
AC-UI-NATIVE-HTML-PREVIEW-001.9
AC-UI-NATIVE-HTML-PREVIEW-001.10
../../specs/ui/system-design/native-html-preview.md

Task 05: Build the capability-free preview runtime

Summary

Implement the isolated script execution boundary selected by the revised HTML preview design. Inline source JavaScript runs in a dedicated worker-hosted ECMAScript VM with a virtual DOM and no host imports. The worker emits only data-only snapshots and diagnostics through a structured-clone protocol.

In scope

  • Select, pin, and license-check the ECMAScript engine and virtual-DOM support needed for the first supported capability set.
  • Implement worker lifecycle, load, event-dispatch, snapshot, diagnostics, and disposal messages.
  • Implement virtual DOM mutation, inline script order, virtual event handlers, bounded timers, console diagnostics, and runtime-owned blob tokens.
  • Deny browser globals, Kandev data, credentials, storage, filesystem, network, navigation, downloads, and window-opening APIs.
  • Enforce instruction, wall-clock, virtual-heap, timer, event-queue, and snapshot limits with fail-closed termination.
  • Add unit tests for capability absence, script execution, event dispatch, dynamic resource filtering, navigation no-ops, and budget failure.

Out of scope

  • File-tab state or toolbar changes.
  • Responsive surface composition and localization.
  • Public documentation.
  • Full browser API compatibility, remote resources, or multi-file sites.

Acceptance

  • A representative inline script mutates the virtual document and responds to a sanitized user event without executing in the native browser context.
  • Attempts to use fetch, XHR, WebSocket, EventSource, location, history, parent/top, forms, downloads, or window APIs fail closed and cannot produce a browser request or navigation.
  • Infinite loops, oversized output, unsupported APIs, malformed messages, and runtime exceptions terminate or reject the generation without falling back to native script execution.

Verification

cd apps/web
pnpm exec vitest run lib/html-preview/preview-runtime.test.ts lib/html-preview/preview-resource-policy.test.ts
pnpm run typecheck

Files likely touched

  • apps/web/lib/html-preview/preview-runtime.ts
  • apps/web/lib/html-preview/preview-runtime.worker.ts
  • apps/web/lib/html-preview/preview-runtime-types.ts
  • apps/web/lib/html-preview/preview-resource-policy.ts
  • apps/web/lib/html-preview/preview-runtime.test.ts
  • apps/web/lib/html-preview/preview-resource-policy.test.ts
  • apps/web/package.json
  • apps/pnpm-lock.yaml

Dependencies

None. This boundary must exist before UI integration can claim script support.

Risks

  • The engine may not support the required ECMAScript or virtual-DOM behavior in all supported browsers and WebViews.
  • A host import, native function escape, or unbounded callback can invalidate the security boundary.
  • Runtime limits that are too strict can break ordinary interactive documents.

Parallelism

sequential

Inputs

  • REQ-UI-NATIVE-HTML-PREVIEW-001.3 through .6 and .9.
  • The runtime boundary, message contract, execution limits, and security invariants in the system design.
  • The capability-free preview isolation design that this cancelled work order originally implemented.

Results

Implemented the worker-hosted QuickJS runtime with a virtual document, bounded event and timer execution, deny-by-default resource policy, runtime-owned blob tokens, structured-clone snapshots, and fail-closed lifecycle errors. Load and interaction execution each receive an independent wall-clock and interrupt budget, so an idle preview cannot consume the next user interaction's runtime allowance.

Verification completed:

pnpm exec vitest run lib/html-preview/preview-runtime.test.ts lib/html-preview/preview-runtime-client.test.ts lib/html-preview/preview-resource-policy.test.ts
pnpm exec tsc --noEmit --pretty false