diff --git a/CLAUDE.md b/CLAUDE.md index 23be95a..355c64b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,7 +22,6 @@ apps/ meeting-notes/ # meeting-notes clients trace-explorer/ web-react/ # Trace Explorer — execution timeline debugger - react-demo/ # Expedition React browser demo (adopted from Traverse) browser-consumer/ # Browser consumer façade android-demo/ # Expedition Android demo youaskm3-starter-kit/ # Downstream browser starter kit diff --git a/README.md b/README.md index 2b300a6..2c5acf7 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ UI examples for [Traverse](https://github.com/traverse-framework/Traverse). | Demo | Path | |---|---| -| React browser demo | [`apps/react-demo/`](apps/react-demo/) | | Browser consumer façade | [`apps/browser-consumer/`](apps/browser-consumer/) | | youaskm3 starter kit | [`apps/youaskm3-starter-kit/`](apps/youaskm3-starter-kit/) | @@ -35,6 +34,7 @@ UI examples for [Traverse](https://github.com/traverse-framework/Traverse). | Path | Retired | Notes | |---|---|---| +| `apps/react-demo` | 2026-08-12 | Spec 004 retire ([#255](https://github.com/traverse-framework/reference-apps/pull/255)); use primary Web shells / browser-consumer | | `apps/android-demo` | 2026-08-12 | Spec 004 retire ([#251](https://github.com/traverse-framework/reference-apps/pull/251)); use primary Android Compose shells | | `apps/macos-demo` | 2026-08-12 | Spec 004 retire ([#252](https://github.com/traverse-framework/reference-apps/pull/252)); use primary SwiftUI shells | diff --git a/apps/react-demo/README.md b/apps/react-demo/README.md deleted file mode 100644 index 8a0a654..0000000 --- a/apps/react-demo/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Traverse React Demo - -Checked-in React browser demo for Traverse expedition planning. - -Canonical home: **`traverse-framework/reference-apps`** (`apps/react-demo/`). - -What it does: - -- renders one approved expedition flow -- allows one approved request submission path -- shows ordered runtime state updates from the live local browser adapter -- shows the final trace snapshot and output panel after the stream completes - -## Local live run - -Requires a Traverse checkout with `traverse-cli`: - -```bash -export TRAVERSE_REPO=/path/to/Traverse -(cd "$TRAVERSE_REPO" && cargo run -p traverse-cli -- browser-adapter serve --bind 127.0.0.1:4174) -node apps/react-demo/server.mjs --adapter http://127.0.0.1:4174 --port 4173 -``` - -Open `http://127.0.0.1:4173`. - -## Fallback preview - -```bash -python3 -m http.server 4173 --directory apps/react-demo -``` - -## Validation - -```bash -bash scripts/ci/react_demo_smoke.sh -# optional live path: -export TRAVERSE_REPO=/path/to/Traverse -bash scripts/ci/react_demo_live_adapter_smoke.sh -``` - -Runtime docs: [browser-adapter.md](https://github.com/traverse-framework/Traverse/blob/main/docs/browser-adapter.md), [quickstart](https://github.com/traverse-framework/Traverse/blob/main/quickstart.md). diff --git a/apps/react-demo/index.html b/apps/react-demo/index.html deleted file mode 100644 index 6a7e124..0000000 --- a/apps/react-demo/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - Traverse React Demo - - - -
- - - - - - diff --git a/apps/react-demo/public/expedition-runtime-session.json b/apps/react-demo/public/expedition-runtime-session.json deleted file mode 100644 index 174391a..0000000 --- a/apps/react-demo/public/expedition-runtime-session.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "demo_id": "expedition.plan.v1", - "title": "Plan Expedition", - "request_id": "req-expedition-001", - "execution_id": "exec_req-expedition-001", - "trace_id": "trace_exec_req-expedition-001", - "status": "completed", - "summary": "Traverse evaluates the governed expedition workflow and assembles a final expedition plan.", - "request": { - "goal": "Plan a two-day alpine expedition for a four-person team.", - "requested_target": "local", - "caller": "browser_demo" - }, - "state_updates": [ - { - "state": "discovering", - "title": "Discovering capability", - "timestamp": "2026-03-30T10:00:00Z", - "detail": "Looking up expedition.planning.plan-expedition@1.0.0 in the private-first registry." - }, - { - "state": "evaluating_constraints", - "title": "Evaluating constraints", - "timestamp": "2026-03-30T10:00:01Z", - "detail": "Confirmed local execution is allowed for the approved expedition capability." - }, - { - "state": "selecting", - "title": "Selecting workflow-backed capability", - "timestamp": "2026-03-30T10:00:02Z", - "detail": "Selected expedition.planning.plan-expedition@1.0.0." - }, - { - "state": "executing", - "title": "Executing workflow", - "timestamp": "2026-03-30T10:00:03Z", - "detail": "Running the approved workflow steps to capture intent, assess conditions, validate readiness, and assemble the plan." - }, - { - "state": "emitting_events", - "title": "Publishing governed events", - "timestamp": "2026-03-30T10:00:04Z", - "detail": "Emitting expedition objective, interpreted intent, conditions summary, readiness, and assembled plan events." - }, - { - "state": "completed", - "title": "Completed", - "timestamp": "2026-03-30T10:00:05Z", - "detail": "The final expedition plan is ready for review." - } - ], - "trace": { - "selected_capability_id": "expedition.planning.plan-expedition", - "selected_capability_version": "1.0.0", - "placement": { - "requested_target": "local", - "selected_target": "local", - "status": "selected", - "reason": "requested_target_selected" - }, - "emitted_events": [ - "expedition.planning.expedition-objective-captured@1.0.0", - "expedition.planning.expedition-intent-interpreted@1.0.0", - "expedition.planning.conditions-summary-assessed@1.0.0", - "expedition.planning.team-readiness-validated@1.0.0", - "expedition.planning.expedition-plan-assembled@1.0.0" - ], - "output": { - "plan_id": "plan-001", - "route": "North Glacier approach with base-camp ascent", - "weather_summary": "Cold start with stable winds and acceptable avalanche risk by midday.", - "team_status": "ready_with_layering_adjustments", - "next_action": "Review equipment checklist and confirm departure window." - } - } -} diff --git a/apps/react-demo/server.mjs b/apps/react-demo/server.mjs deleted file mode 100644 index b76710d..0000000 --- a/apps/react-demo/server.mjs +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env node - -import { createServer } from "node:http"; -import { readFile } from "node:fs/promises"; -import { extname, join, normalize } from "node:path"; -import { fileURLToPath } from "node:url"; - -const rootDir = fileURLToPath(new URL(".", import.meta.url)); -const defaultPort = 4173; -const defaultAdapterBaseUrl = "http://127.0.0.1:4174"; - -const { port, adapterBaseUrl } = parseArgs(process.argv.slice(2)); -const adapterOrigin = new URL(adapterBaseUrl); - -const server = createServer(async (request, response) => { - try { - if (request.url?.startsWith("/local/browser-subscriptions")) { - await proxyBrowserAdapter(request, response, adapterOrigin); - return; - } - - await serveStaticAsset(request, response); - } catch (error) { - response.statusCode = 500; - response.setHeader("Content-Type", "text/plain; charset=utf-8"); - response.end(String(error)); - } -}); - -server.listen(port, "127.0.0.1", () => { - console.log(`Traverse React demo serving on http://127.0.0.1:${port}`); - console.log(`Proxying browser adapter requests to ${adapterOrigin.origin}`); -}); - -function parseArgs(args) { - let port = defaultPort; - let adapterBaseUrl = defaultAdapterBaseUrl; - - for (let index = 0; index < args.length; index += 1) { - const current = args[index]; - if (current === "--port" && args[index + 1]) { - port = Number(args[index + 1]); - index += 1; - } else if (current === "--adapter" && args[index + 1]) { - adapterBaseUrl = args[index + 1]; - index += 1; - } - } - - if (!Number.isInteger(port) || port <= 0) { - throw new Error(`invalid port: ${port}`); - } - - return { port, adapterBaseUrl }; -} - -async function proxyBrowserAdapter(request, response, adapterOrigin) { - const targetUrl = new URL(request.url, adapterOrigin); - const headers = new Headers(); - - for (const [name, value] of Object.entries(request.headers)) { - if (value === undefined) { - continue; - } - if (["host", "connection", "content-length"].includes(name.toLowerCase())) { - continue; - } - headers.set(name, Array.isArray(value) ? value.join(", ") : value); - } - - let body = undefined; - if (!["GET", "HEAD"].includes(request.method || "")) { - body = await readRequestBody(request); - } - - const upstreamResponse = await fetch(targetUrl, { - method: request.method, - headers, - body, - }); - - response.statusCode = upstreamResponse.status; - response.statusMessage = upstreamResponse.statusText; - - upstreamResponse.headers.forEach((value, name) => { - if (name.toLowerCase() === "content-length") { - return; - } - response.setHeader(name, value); - }); - - if (!upstreamResponse.body) { - response.end(); - return; - } - - const reader = upstreamResponse.body.getReader(); - while (true) { - const { done, value } = await reader.read(); - if (done) { - break; - } - response.write(Buffer.from(value)); - } - - response.end(); -} - -async function serveStaticAsset(request, response) { - const requestPath = request.url?.split("?")[0] ?? "/"; - const normalizedPath = normalize(requestPath).replace(/^([.][.][/\\])+/, ""); - const filePath = normalizedPath === "/" ? "index.html" : normalizedPath.replace(/^\//, ""); - const resolvedPath = join(rootDir, filePath); - - try { - const contents = await readFile(resolvedPath); - response.statusCode = 200; - response.setHeader("Content-Type", contentTypeFor(resolvedPath)); - response.end(contents); - } catch { - if (requestPath !== "/") { - const indexPath = join(rootDir, "index.html"); - const contents = await readFile(indexPath); - response.statusCode = 200; - response.setHeader("Content-Type", "text/html; charset=utf-8"); - response.end(contents); - return; - } - - response.statusCode = 404; - response.setHeader("Content-Type", "text/plain; charset=utf-8"); - response.end("Not found"); - } -} - -function contentTypeFor(filePath) { - switch (extname(filePath)) { - case ".html": - return "text/html; charset=utf-8"; - case ".js": - return "text/javascript; charset=utf-8"; - case ".css": - return "text/css; charset=utf-8"; - case ".json": - return "application/json; charset=utf-8"; - default: - return "application/octet-stream"; - } -} - -async function readRequestBody(request) { - const chunks = []; - for await (const chunk of request) { - chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); - } - return Buffer.concat(chunks); -} diff --git a/apps/react-demo/src/browser-adapter-client.js b/apps/react-demo/src/browser-adapter-client.js deleted file mode 100644 index f59d113..0000000 --- a/apps/react-demo/src/browser-adapter-client.js +++ /dev/null @@ -1,330 +0,0 @@ -(function (root, factory) { - const client = factory(); - - if (typeof module === "object" && module.exports) { - module.exports = client; - } - - if (root) { - root.TraverseReactDemoClient = client; - } -})(typeof globalThis !== "undefined" ? globalThis : this, function () { - const APPROVED_BROWSER_DEMO_SESSION = { - title: "Plan Expedition", - summary: - "Traverse evaluates the governed expedition workflow and assembles a final expedition plan.", - request: { - goal: "Plan a two-day alpine expedition for a four-person team.", - requested_target: "local", - caller: "browser_demo", - }, - request_id: "expedition-plan-request-001", - execution_id: "exec_expedition-plan-request-001", - trace_id: "trace_exec_expedition-plan-request-001", - }; - - function createLiveDemoState() { - return { - phase: "idle", - statusLabel: "ready", - streamBanner: "No subscription active yet. Submit the approved request to begin.", - requestId: null, - executionId: null, - stateUpdates: [], - liveTrace: null, - liveResult: null, - error: "", - }; - } - - function buildApprovedSubscriptionRequest() { - return { - subscription_request: { - kind: "browser_runtime_subscription_request", - schema_version: "1.0.0", - governing_spec: "013-browser-runtime-subscription", - request_id: APPROVED_BROWSER_DEMO_SESSION.request_id, - }, - }; - } - - function humanizeName(value) { - return value - .toString() - .split("_") - .filter(Boolean) - .map((part) => part.slice(0, 1).toUpperCase() + part.slice(1)) - .join(" "); - } - - function formatDetailValue(value) { - if (value === null || value === undefined) { - return ""; - } - if (typeof value === "string") { - return value; - } - if (typeof value === "number" || typeof value === "boolean") { - return String(value); - } - return JSON.stringify(value); - } - - function describeStateEvent(stateEvent) { - const details = stateEvent.details || {}; - const parts = []; - - if (details.transition_reason) { - parts.push(humanizeName(details.transition_reason)); - } - - for (const [key, value] of Object.entries(details)) { - if (key === "transition_reason") { - continue; - } - parts.push(`${humanizeName(key)}: ${formatDetailValue(value)}`); - } - - return parts.length > 0 ? parts.join(" · ") : "State update received."; - } - - function formatStateUpdate(stateEvent) { - return { - state: stateEvent.state, - title: humanizeName(stateEvent.state), - timestamp: stateEvent.entered_at, - detail: describeStateEvent(stateEvent), - }; - } - - function normalizeSubscriptionMessage(message) { - const variant = Object.keys(message || {})[0]; - if (!variant) { - return null; - } - return { - variant, - payload: message[variant], - }; - } - - function parseSubscriptionFrame(frame) { - let eventName = ""; - let data = ""; - - for (const line of frame.split(/\r?\n/)) { - if (line.startsWith("event: ")) { - eventName = line.slice("event: ".length); - } else if (line.startsWith("data: ")) { - data += line.slice("data: ".length); - } - } - - if (!eventName || !data) { - return null; - } - - return { - event: eventName, - data: JSON.parse(data), - }; - } - - function parseSubscriptionFrames(text) { - return text - .split(/\r?\n\r?\n/) - .map((frame) => frame.trim()) - .filter(Boolean) - .map(parseSubscriptionFrame) - .filter(Boolean); - } - - async function runLiveBrowserSubscription({ - baseUrl = "", - fetchImpl = globalThis.fetch, - onMessage, - } = {}) { - const adapterPrefix = baseUrl.replace(/\/$/, ""); - const createResponse = await fetchImpl(`${adapterPrefix}/local/browser-subscriptions`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(buildApprovedSubscriptionRequest()), - }); - - const createdPayload = await createResponse.text(); - if (!createResponse.ok) { - throw new Error(`local browser adapter setup failed: ${createdPayload}`); - } - - const created = JSON.parse(createdPayload); - const streamResponse = await fetchImpl(`${adapterPrefix}${created.stream_url}`, { - headers: { - Accept: "text/event-stream", - }, - }); - - if (!streamResponse.ok) { - const errorPayload = await streamResponse.text(); - throw new Error(`local browser adapter stream failed: ${errorPayload}`); - } - - if (!streamResponse.body || typeof streamResponse.body.getReader !== "function") { - throw new Error("local browser adapter stream did not expose a readable body"); - } - - const reader = streamResponse.body.getReader(); - const decoder = new TextDecoder(); - let buffer = ""; - const messages = []; - - while (true) { - const { done, value } = await reader.read(); - if (done) { - break; - } - - buffer += decoder.decode(value, { stream: true }); - const frames = buffer.split(/\r?\n\r?\n/); - buffer = frames.pop() || ""; - - for (const frame of frames) { - const parsed = parseSubscriptionFrame(frame.trim()); - if (!parsed) { - continue; - } - - const normalized = normalizeSubscriptionMessage(parsed.data); - if (!normalized) { - continue; - } - - messages.push(normalized); - if (typeof onMessage === "function") { - onMessage(normalized, created); - } - } - } - - const tail = buffer.trim(); - if (tail) { - const parsed = parseSubscriptionFrame(tail); - if (parsed) { - const normalized = normalizeSubscriptionMessage(parsed.data); - if (normalized) { - messages.push(normalized); - if (typeof onMessage === "function") { - onMessage(normalized, created); - } - } - } - } - - return { - created, - messages, - }; - } - - function applyBrowserSubscriptionMessage(state, message, created) { - const nextState = { - ...state, - error: "", - }; - - switch (message.variant) { - case "Lifecycle": { - const lifecycle = message.payload; - nextState.requestId = lifecycle.request_id; - nextState.executionId = lifecycle.execution_id; - nextState.statusLabel = - lifecycle.status === "subscription_established" - ? "streaming" - : lifecycle.status === "stream_completed" - ? "completed" - : lifecycle.status; - nextState.streamBanner = - lifecycle.status === "subscription_established" - ? "Subscription established. Streaming ordered runtime updates." - : "Stream completed. Final trace artifact is now visible."; - nextState.phase = - lifecycle.status === "subscription_established" - ? "streaming" - : lifecycle.status === "stream_completed" - ? "completed" - : nextState.phase; - if (created) { - nextState.subscriptionId = created.subscription_id; - } - return nextState; - } - case "State": { - nextState.phase = "streaming"; - nextState.statusLabel = "streaming"; - nextState.streamBanner = "Subscription established. Streaming ordered runtime updates."; - nextState.stateUpdates = nextState.stateUpdates.concat(formatStateUpdate(message.payload.state_event)); - return nextState; - } - case "TraceArtifact": { - nextState.liveTrace = message.payload.trace; - return nextState; - } - case "StreamTerminal": { - nextState.liveResult = message.payload.result; - nextState.phase = "completed"; - nextState.statusLabel = "completed"; - nextState.streamBanner = "Stream completed. Final trace artifact is now visible."; - return nextState; - } - case "Error": { - nextState.phase = "error"; - nextState.statusLabel = "error"; - nextState.error = message.payload.message; - nextState.streamBanner = message.payload.message; - return nextState; - } - default: - return nextState; - } - } - - function traceSummary(trace, terminalResult) { - if (!trace || !trace.selection || !trace.execution) { - return null; - } - - const output = (terminalResult && terminalResult.output) || (trace.result && trace.result.output) || null; - return { - selection: { - capability: trace.selection.selected_capability_id, - version: trace.selection.selected_capability_version, - placementTarget: trace.execution.placement.selected_target, - placementReason: trace.execution.placement.reason, - }, - emittedEvents: trace.emitted_events || [], - output: output - ? { - planId: output.plan_id, - route: output.route, - weatherSummary: output.weather_summary, - teamStatus: output.team_status, - nextAction: output.next_action, - } - : null, - }; - } - - return { - APPROVED_BROWSER_DEMO_SESSION, - applyBrowserSubscriptionMessage, - buildApprovedSubscriptionRequest, - createLiveDemoState, - humanizeName, - normalizeSubscriptionMessage, - parseSubscriptionFrames, - parseSubscriptionFrame, - runLiveBrowserSubscription, - traceSummary, - }; -}); diff --git a/apps/react-demo/src/main.js b/apps/react-demo/src/main.js deleted file mode 100644 index ca24e2b..0000000 --- a/apps/react-demo/src/main.js +++ /dev/null @@ -1,234 +0,0 @@ -const { createElement: h, useState } = React; - -const DemoClient = window.TraverseReactDemoClient; -const APPROVED_SESSION = DemoClient.APPROVED_BROWSER_DEMO_SESSION; - -function labeledCard(label, value) { - return h( - "div", - null, - h("dt", null, label), - h("dd", null, value), - ); -} - -function timelineItem(update) { - return h( - "li", - { - key: `${update.timestamp}-${update.state}`, - className: "timeline-item", - }, - h("div", { className: "timeline-marker" }, update.state.slice(0, 1).toUpperCase()), - h( - "div", - { className: "timeline-body" }, - h( - "div", - { className: "timeline-topline" }, - h("strong", null, update.title), - h("span", null, update.timestamp), - ), - h("p", null, update.detail), - ), - ); -} - -function liveTraceSection(trace, terminalResult) { - const summary = DemoClient.traceSummary(trace, terminalResult); - - if (!summary) { - return h( - "div", - { className: "trace-placeholder" }, - "Terminal trace is withheld until the ordered state stream reaches completion.", - ); - } - - return [ - h( - "div", - { className: "trace-block", key: "selection" }, - h("h3", null, "Selection"), - h( - "dl", - { className: "trace-list" }, - labeledCard("Capability", summary.selection.capability), - labeledCard("Version", summary.selection.version), - labeledCard( - "Placement", - `${summary.selection.placementTarget} · ${summary.selection.placementReason}`, - ), - ), - ), - h( - "div", - { className: "trace-block", key: "events" }, - h("h3", null, "Emitted Events"), - h( - "ul", - { className: "event-list" }, - summary.emittedEvents.map((eventId) => h("li", { key: eventId }, eventId)), - ), - ), - h( - "div", - { className: "trace-block", key: "output" }, - h("h3", null, "Output"), - h( - "dl", - { className: "trace-list" }, - labeledCard("Plan", summary.output.planId), - labeledCard("Route", summary.output.route), - labeledCard("Weather", summary.output.weatherSummary), - labeledCard("Team Status", summary.output.teamStatus), - labeledCard("Next Action", summary.output.nextAction), - ), - ), - ]; -} - -function DemoApp() { - const [sessionState, setSessionState] = useState(() => DemoClient.createLiveDemoState()); - const [error, setError] = useState(""); - - async function handleSubmitRequest() { - if (sessionState.phase === "streaming") { - return; - } - - setError(""); - setSessionState(DemoClient.createLiveDemoState()); - - try { - await DemoClient.runLiveBrowserSubscription({ - onMessage: (message, created) => { - setSessionState((current) => DemoClient.applyBrowserSubscriptionMessage(current, message, created)); - }, - }); - } catch (reason) { - const message = String(reason); - setError(message); - setSessionState((current) => ({ - ...current, - phase: "error", - statusLabel: "error", - streamBanner: message, - error: message, - })); - } - } - - const statusLabel = sessionState.statusLabel; - const hasTerminalTrace = sessionState.phase === "completed" && sessionState.liveTrace; - const isStreaming = sessionState.phase === "streaming"; - const visibleUpdates = sessionState.stateUpdates; - - if (error) { - return h( - "main", - { className: "page" }, - h( - "section", - { className: "hero" }, - h( - "div", - { className: "hero-copy" }, - h("p", { className: "eyebrow" }, "Traverse Browser Runtime"), - h("h1", null, "Live adapter connection failed."), - h("p", { className: "lede" }, error), - h( - "p", - { className: "lede" }, - "Run the local browser adapter proxy again, or use the documented fixture preview fallback.", - ), - ), - ), - ); - } - - return h( - "main", - { className: "page" }, - h( - "section", - { className: "hero" }, - h( - "div", - { className: "hero-copy" }, - h("p", { className: "eyebrow" }, "Traverse Browser Runtime"), - h("h1", null, APPROVED_SESSION.title), - h("p", { className: "lede" }, APPROVED_SESSION.summary), - h( - "dl", - { className: "request-meta" }, - labeledCard("Goal", APPROVED_SESSION.request.goal), - labeledCard("Target", APPROVED_SESSION.request.requested_target), - labeledCard("Trace", APPROVED_SESSION.trace_id), - labeledCard("Request", APPROVED_SESSION.request_id), - ), - ), - h("div", { className: "status-pill" }, statusLabel), - ), - h( - "section", - { className: "grid" }, - h( - "article", - { className: "panel" }, - h( - "div", - { className: "panel-header" }, - h("h2", null, "Request And Stream"), - h( - "p", - null, - "Submit the approved expedition request, then watch the governed browser subscription stream unfold in order.", - ), - ), - h( - "div", - { className: "request-card" }, - h( - "div", - null, - h("p", { className: "request-label" }, "Approved request"), - h("h3", null, APPROVED_SESSION.title), - h("p", null, APPROVED_SESSION.request.goal), - ), - h( - "button", - { - className: "request-button", - type: "button", - onClick: handleSubmitRequest, - disabled: isStreaming, - }, - isStreaming ? "Streaming approved request..." : "Submit approved request", - ), - ), - h("div", { className: "stream-banner" }, sessionState.streamBanner), - h("ol", { className: "timeline" }, visibleUpdates.map(timelineItem)), - ), - h( - "article", - { className: "panel trace-panel" }, - h( - "div", - { className: "panel-header" }, - h("h2", null, "Terminal Trace"), - h("p", null, "The final governed selection, placement, and output snapshot."), - ), - hasTerminalTrace - ? liveTraceSection(sessionState.liveTrace, sessionState.liveResult) - : h( - "div", - { className: "trace-placeholder" }, - "Terminal trace is withheld until the ordered state stream reaches completion.", - ), - ), - ), - ); -} - -ReactDOM.createRoot(document.getElementById("root")).render(h(DemoApp)); diff --git a/apps/react-demo/src/styles.css b/apps/react-demo/src/styles.css deleted file mode 100644 index c130473..0000000 --- a/apps/react-demo/src/styles.css +++ /dev/null @@ -1,296 +0,0 @@ -:root { - color-scheme: light; - --bg: #f7f0e6; - --paper: rgba(255, 250, 243, 0.82); - --ink: #1f1a17; - --muted: #6d625a; - --accent: #145b73; - --accent-soft: #d8eef4; - --line: rgba(31, 26, 23, 0.12); - --shadow: 0 30px 60px rgba(39, 28, 20, 0.12); -} - -* { - box-sizing: border-box; -} - -body { - margin: 0; - min-height: 100vh; - font-family: "Avenir Next", "Segoe UI", sans-serif; - color: var(--ink); - background: - radial-gradient(circle at top left, rgba(20, 91, 115, 0.18), transparent 30%), - radial-gradient(circle at top right, rgba(193, 119, 61, 0.14), transparent 28%), - linear-gradient(180deg, #fffaf4 0%, var(--bg) 100%); -} - -.page { - max-width: 1180px; - margin: 0 auto; - padding: 48px 20px 64px; -} - -.hero { - display: flex; - justify-content: space-between; - gap: 24px; - align-items: flex-start; - margin-bottom: 28px; - padding: 32px; - border: 1px solid var(--line); - border-radius: 28px; - background: var(--paper); - backdrop-filter: blur(14px); - box-shadow: var(--shadow); -} - -.hero h1 { - margin: 8px 0 12px; - font-size: clamp(2.4rem, 6vw, 4.8rem); - line-height: 0.98; - letter-spacing: -0.05em; -} - -.eyebrow { - margin: 0; - font-size: 0.82rem; - letter-spacing: 0.2em; - text-transform: uppercase; - color: var(--accent); - font-weight: 700; -} - -.lede { - max-width: 60ch; - margin: 0; - color: var(--muted); - font-size: 1.05rem; - line-height: 1.55; -} - -.status-pill { - flex-shrink: 0; - padding: 10px 14px; - border-radius: 999px; - background: var(--accent-soft); - color: var(--accent); - text-transform: uppercase; - letter-spacing: 0.12em; - font-size: 0.76rem; - font-weight: 700; -} - -.request-meta, -.trace-list { - display: grid; - gap: 12px; - margin: 20px 0 0; -} - -.request-meta { - grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); -} - -.request-meta div, -.trace-list div { - padding: 12px 14px; - border-radius: 18px; - background: rgba(255, 255, 255, 0.72); - border: 1px solid var(--line); -} - -dt { - margin-bottom: 6px; - color: var(--muted); - font-size: 0.8rem; - text-transform: uppercase; - letter-spacing: 0.08em; -} - -dd { - margin: 0; - line-height: 1.45; -} - -.grid { - display: grid; - grid-template-columns: 1.2fr 0.8fr; - gap: 22px; -} - -.panel { - padding: 24px; - border-radius: 28px; - border: 1px solid var(--line); - background: rgba(255, 253, 249, 0.9); - box-shadow: var(--shadow); -} - -.panel-header h2, -.trace-block h3 { - margin: 0 0 8px; -} - -.panel-header p { - margin: 0 0 18px; - color: var(--muted); -} - -.request-card, -.stream-banner, -.trace-placeholder { - border: 1px solid var(--line); - background: white; -} - -.request-card { - display: flex; - justify-content: space-between; - gap: 18px; - align-items: center; - margin-bottom: 18px; - padding: 18px 20px; - border-radius: 22px; -} - -.request-label { - margin: 0 0 8px; - color: var(--accent); - font-size: 0.8rem; - letter-spacing: 0.12em; - text-transform: uppercase; - font-weight: 700; -} - -.request-card h3, -.request-card p { - margin: 0; -} - -.request-card p:last-child { - margin-top: 8px; - color: var(--muted); - line-height: 1.45; -} - -.request-button { - border: 0; - border-radius: 999px; - padding: 14px 20px; - background: var(--accent); - color: white; - font: inherit; - font-weight: 700; - cursor: pointer; - box-shadow: 0 14px 28px rgba(20, 91, 115, 0.18); -} - -.request-button:disabled { - cursor: wait; - opacity: 0.72; -} - -.stream-banner, -.trace-placeholder { - margin-bottom: 18px; - padding: 14px 16px; - border-radius: 18px; - color: var(--muted); - line-height: 1.45; -} - -.timeline { - list-style: none; - padding: 0; - margin: 0; - display: grid; - gap: 14px; -} - -.timeline-item { - display: grid; - grid-template-columns: 44px 1fr; - gap: 14px; - align-items: flex-start; -} - -.timeline-marker { - display: grid; - place-items: center; - width: 44px; - height: 44px; - border-radius: 14px; - background: var(--accent); - color: white; - font-weight: 700; -} - -.timeline-body { - padding: 14px 16px; - border-radius: 18px; - background: white; - border: 1px solid var(--line); -} - -.timeline-topline { - display: flex; - justify-content: space-between; - gap: 12px; - align-items: baseline; -} - -.timeline-topline span { - color: var(--muted); - font-size: 0.84rem; -} - -.timeline-body p { - margin: 10px 0 0; - color: var(--muted); - line-height: 1.45; -} - -.trace-panel { - display: grid; - gap: 18px; -} - -.trace-block { - padding: 16px 18px; - border-radius: 20px; - background: white; - border: 1px solid var(--line); -} - -.event-list { - margin: 0; - padding-left: 18px; - display: grid; - gap: 8px; -} - -.event-list li { - color: var(--muted); - line-height: 1.45; -} - -@media (max-width: 900px) { - .hero, - .grid { - grid-template-columns: 1fr; - } - - .hero { - flex-direction: column; - } - - .timeline-topline { - flex-direction: column; - } - - .request-card { - flex-direction: column; - align-items: flex-start; - } -} diff --git a/apps/react-demo/vendor/react-dom.development.js b/apps/react-demo/vendor/react-dom.development.js deleted file mode 100644 index 57a309c..0000000 --- a/apps/react-demo/vendor/react-dom.development.js +++ /dev/null @@ -1,29924 +0,0 @@ -/** - * @license React - * react-dom.development.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : - typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : - (global = global || self, factory(global.ReactDOM = {}, global.React)); -}(this, (function (exports, React) { 'use strict'; - - var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - - var suppressWarning = false; - function setSuppressWarning(newSuppressWarning) { - { - suppressWarning = newSuppressWarning; - } - } // In DEV, calls to console.warn and console.error get replaced - // by calls to these methods by a Babel plugin. - // - // In PROD (or in packages without access to React internals), - // they are left as they are instead. - - function warn(format) { - { - if (!suppressWarning) { - for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; - } - - printWarning('warn', format, args); - } - } - } - function error(format) { - { - if (!suppressWarning) { - for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { - args[_key2 - 1] = arguments[_key2]; - } - - printWarning('error', format, args); - } - } - } - - function printWarning(level, format, args) { - // When changing this logic, you might want to also - // update consoleWithStackDev.www.js as well. - { - var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; - var stack = ReactDebugCurrentFrame.getStackAddendum(); - - if (stack !== '') { - format += '%s'; - args = args.concat([stack]); - } // eslint-disable-next-line react-internal/safe-string-coercion - - - var argsWithFormat = args.map(function (item) { - return String(item); - }); // Careful: RN currently depends on this prefix - - argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it - // breaks IE9: https://github.com/facebook/react/issues/13610 - // eslint-disable-next-line react-internal/no-production-logging - - Function.prototype.apply.call(console[level], console, argsWithFormat); - } - } - - var FunctionComponent = 0; - var ClassComponent = 1; - var IndeterminateComponent = 2; // Before we know whether it is function or class - - var HostRoot = 3; // Root of a host tree. Could be nested inside another node. - - var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. - - var HostComponent = 5; - var HostText = 6; - var Fragment = 7; - var Mode = 8; - var ContextConsumer = 9; - var ContextProvider = 10; - var ForwardRef = 11; - var Profiler = 12; - var SuspenseComponent = 13; - var MemoComponent = 14; - var SimpleMemoComponent = 15; - var LazyComponent = 16; - var IncompleteClassComponent = 17; - var DehydratedFragment = 18; - var SuspenseListComponent = 19; - var ScopeComponent = 21; - var OffscreenComponent = 22; - var LegacyHiddenComponent = 23; - var CacheComponent = 24; - var TracingMarkerComponent = 25; - - // ----------------------------------------------------------------------------- - - var enableClientRenderFallbackOnTextMismatch = true; // TODO: Need to review this code one more time before landing - // the react-reconciler package. - - var enableNewReconciler = false; // Support legacy Primer support on internal FB www - - var enableLazyContextPropagation = false; // FB-only usage. The new API has different semantics. - - var enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber - - var enableSuspenseAvoidThisFallback = false; // Enables unstable_avoidThisFallback feature in Fizz - // React DOM Chopping Block - // - // Similar to main Chopping Block but only flags related to React DOM. These are - // grouped because we will likely batch all of them into a single major release. - // ----------------------------------------------------------------------------- - // Disable support for comment nodes as React DOM containers. Already disabled - // in open source, but www codebase still relies on it. Need to remove. - - var disableCommentsAsDOMContainers = true; // Disable javascript: URL strings in href for XSS protection. - // and client rendering, mostly to allow JSX attributes to apply to the custom - // element's object properties instead of only HTML attributes. - // https://github.com/facebook/react/issues/11347 - - var enableCustomElementPropertySupport = false; // Disables children for