diff --git a/SDK-ARCHITECTURE.md b/SDK-ARCHITECTURE.md new file mode 100644 index 0000000..b2b9fd5 --- /dev/null +++ b/SDK-ARCHITECTURE.md @@ -0,0 +1,478 @@ +# Originmain SDK Architecture +### From Proxy to SDK — System Design & Implementation Progress + +> **Living document.** Updated every time a piece of this architecture is implemented. +> Supersedes `RENDERING-ARCHITECTURE.md` (proxy-era, now deprecated). +> +> Last updated: 2026-05-13 + +--- + +## Table of Contents + +1. [Why We Moved Away From the Proxy](#1-why-we-moved-away-from-the-proxy) +2. [Target Architecture](#2-target-architecture) +3. [System Components](#3-system-components) +4. [Wire Protocol](#4-wire-protocol) +5. [Implementation Progress](#5-implementation-progress) +6. [Package Map](#6-package-map) +7. [Data Flow — Step by Step](#7-data-flow--step-by-step) +8. [Local Dev Problem & Tunnel Strategy](#8-local-dev-problem--tunnel-strategy) +9. [Edge Cases](#9-edge-cases) +10. [What Remains To Be Built](#10-what-remains-to-be-built) + +--- + +## 1. Why We Moved Away From the Proxy + +The original approach (`@originmain/cli`) ran a local HTTP reverse proxy that injected a +`` content | ✅ Yes | +| Hook installed too late | `__REACT_DEVTOOLS_GLOBAL_HOOK__` must exist **before** React's module body evaluates. Injected scripts run after HTML parses — after React is already loaded | ✅ Yes | + +**The only reliable fix**: the fiber hook must be installed by the app itself, not by an external injector. That means it ships as an npm package the developer imports **before React** in their app entry point. + +--- + +## 2. Target Architecture + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ ORIGINMAIN CLOUD (originmain.com) │ +│ │ +│ ┌─────────────────────────────┐ ┌──────────────────────────────────┐ │ +│ │ Canvas (Next.js app) │◄───►│ WebSocket Bridge │ │ +│ │ • Artboards / iframes │ │ /api/sdk/[projectId] │ │ +│ │ • Inspector / Editor │ │ • auth via SDK token │ │ +│ │ • File diff viewer │ │ • routes messages to user │ │ +│ └─────────────────────────────┘ └──────────────────────────────────┘ │ +│ ▲ │ +└────────────────────────────────────────────────────────│───────────────────┘ + │ WSS + │ (wss://originmain.com/api/sdk/[projectId]) +┌────────────────────────────────────────────────────────│───────────────────┐ +│ USER MACHINE (localhost / staging) │ │ +│ ▼ │ +│ ┌──────────────────────────┐ ┌────────────────────────────────────┐ │ +│ │ Next.js dev server │◄───►│ @originmain/dev (SDK) │ │ +│ │ (next dev / Vercel) │ │ • client runtime in browser │ │ +│ │ │ │ • server runtime in Node │ │ +│ │ │ │ • direct React fiber access │ │ +│ │ Components.tsx ◄────────┼─────┤ • file-write capability │ │ +│ │ │ │ • opens WSS to cloud canvas │ │ +│ └──────────────────────────┘ └────────────────────────────────────┘ │ +│ │ +│ next.config.js — wrapped with @originmain/next plugin │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +**Key invariant**: the fiber hook lives *inside* the user's app bundle. +No proxy, no injection, no external script — the user's `import '@originmain/live'` +is what instruments React. + +--- + +## 3. System Components + +### 3.1 `@originmain/live` (client runtime) — `packages/live-sdk` + +The browser-side SDK. A side-effect import that: + +- Installs `__REACT_DEVTOOLS_GLOBAL_HOOK__` **before React evaluates** (module-load time) +- Resolves the artboard ID from three sources in priority order: + 1. URL fragment: `location.hash` contains `#__om_artboard=` ← primary, cross-origin safe + 2. `window.name`: starts with `om:` (same-origin iframes only) + 3. postMessage handshake: sends `{ __om_init_request: true }` to parent, awaits reply +- Runs the full postMessage protocol (see §4) once the artboard ID is known +- Is a **complete no-op** outside an Originmain artboard iframe (zero runtime cost in production) + +### 3.2 `@originmain/next` (build plugin) — `packages/next` + +A `withOriginmain(nextConfig)` wrapper for `next.config.ts` that: + +- Prepends `@originmain/live` to every client-side webpack entry point +- Ensures the fiber hook import runs **before any other module** in the bundle +- Skips the server-side bundle (fiber hook is browser-only) +- Is idempotent (safe to wrap twice) +- Delegates to any existing `webpack` customisation in the user's config + +### 3.3 `@originmain/dev` (full SDK) — `packages/dev` ❌ NOT BUILT YET + +The full SDK intended for local development. Will combine: + +- Everything in `@originmain/live` (client runtime, fiber hook) +- A **server runtime** that runs inside the Next.js dev server process +- A **WebSocket client** that connects outbound to the cloud canvas bridge +- **File-write capability**: receives design panel edits from the canvas and applies them to source files (`.tsx`, `.ts`, CSS modules) + +### 3.4 WebSocket Bridge — `packages/app/src/app/api/sdk/[projectId]/` ❌ NOT BUILT YET + +A Next.js API route on the cloud canvas that: + +- Accepts an inbound WSS connection from `@originmain/dev` +- Authenticates via a project-scoped SDK token (issued in project settings) +- Routes messages bidirectionally: + - SDK → Canvas: `FIBER_TREE_UPDATE`, `ELEMENT_STYLES`, `ROUTES_DISCOVERED`, etc. + - Canvas → SDK: `PATCH_ELEMENT_STYLE`, `REQUEST_ELEMENT_STYLES`, `CAPTURE_SNAPSHOT`, etc. +- Maintains one WebSocket connection per active project session + +### 3.5 Canvas (Next.js app) — `packages/app` + +Originmain's cloud editor. Current transport: **postMessage via iframe**. +Future transport: **WebSocket via bridge** (for `@originmain/dev` local dev). + +Key components: +- `LiveArtboard.tsx` — manages the `