diff --git a/biome.json b/biome.json index 9bff3d75..00326ba8 100644 --- a/biome.json +++ b/biome.json @@ -9,7 +9,8 @@ "recommended": true, "style": { "noParameterAssign": "off", - "useConst": "off" + "useConst": "off", + "noUselessElse": "off" }, "correctness": { "useYield": "off" diff --git a/inspector/CONTRIBUTING.md b/inspector/CONTRIBUTING.md new file mode 100644 index 00000000..33532111 --- /dev/null +++ b/inspector/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing To The Inspector 🎯 + +Welcome! This document explains how to get started working on the Inspector. + +## Quick start 🚀 + +### Install deps (from repo root): + +```shell +pnpm install +``` + +### Run the inspector locally: + +```shell +cd inspector +pnpm start +``` + +This runs Vite and serves the Crank-based inspector UI. Open http://localhost:5173 (or whatever Vite prints). + +- Run tests & checks (from repo root): + - Run tests: `pnpm test` + - Run type checks: `pnpm run check` + - Run linter: `pnpm run lint` + - Format: `pnpm run fmt` + +Note: Some checks (lint/format/test) are run at the monorepo root and cover all workspaces. + +## Notes And What Is Where 👀 + +- Crank generator components are the UI building blocks. Many components are written as generators for render loops. They can own Effection scopes. +- Use shoelace web-components for pre-built "blocks". +- Use CSS Modules per component (`*.module.css`). Avoid placing `class` attributes directly on Shoelace (`sl-*`) elements. +- D3 owns its SVG subtree: components render an `` that D3 manages directly — avoid mixing Crank DOM updates inside D3-managed nodes. +- If working purely on the UI, the `/demo` page pulls in a static file which is useful for components feature and functionality testing. It shares components with the `/live` and `/recording` pages. diff --git a/inspector/README.md b/inspector/README.md new file mode 100644 index 00000000..4902153e --- /dev/null +++ b/inspector/README.md @@ -0,0 +1,49 @@ +# inspector + +Helpers to inspect an effection tree. + +## Running + +### Live + +Start your application with the inspector loader so it runs alongside your app. + +Node: + +```bash +node --import @effectionx/inspector ./your-app.js --suspend +``` + +Deno: + +```bash +deno run --preload npm:@effectionx/inspector ./your-app.ts --suspend +``` + +When started this way the inspector will launch a small SSE server (default port: 41000) and serve the UI at `http://localhost:41000`. + +### Recording ✅ + +The UI supports loading saved recordings useful for review and sharing. From the Home screen click **Load Recording → Browse files** and choose a `.json` or `.effection` file. A recording is a JSON array of NodeMap snapshots. The inspector accepts `.json` and `.effection` files. + +#### Creating a recording from a live session: + +You can capture the SSE stream from a running inspector and save the emitted data. Start by using [the instructions for running the process live](#live). + +```bash +# Start capturing and it will close once your effection process closes +curl -sN -X POST http://localhost:41000/watchScopes \ + -H "Accept: text/event-stream" -d '[]' \ + | jq -R -s 'split("\n") | map(select(startswith("data: "))) | map(.[6:] | fromjson)' \ + > recording.json +``` + +If you started the inspected process with `--suspend`, click the red Play button in the inspector header (next to the `live` badge) to resume execution — the UI issues the appropriate POST for you. + +If you prefer the command line, the same request can be made manually: + +```bash +curl -s -X POST http://localhost:41000/play -H 'Content-Type: application/json' -d '[]' +``` + +You can also monitor player state with `/watchPlayerState`. diff --git a/inspector/combine.test.ts b/inspector/combine.test.ts new file mode 100644 index 00000000..ffe24c7e --- /dev/null +++ b/inspector/combine.test.ts @@ -0,0 +1,92 @@ +import { describe, it } from "@effectionx/bdd"; +import { expect } from "expect"; +import { combine, createImplementation, createProtocol } from "../lib/mod.ts"; +import { scope } from "arktype"; +import type { Stream } from "effection"; +import type { Method } from "../lib/types.ts"; + +describe("combine", () => { + it("combines protocols methods", function* () { + type AMethods = { a: Method }; + type BMethods = { b: Method }; + + const schema = scope({ + NoneArr: "never[]", + None: "never", + Str: "string", + }).export(); + + const aMethods: AMethods = { + a: { args: schema.NoneArr, progress: schema.None, returns: schema.Str }, + }; + const bMethods: BMethods = { + b: { args: schema.NoneArr, progress: schema.None, returns: schema.Str }, + }; + + const a = createProtocol(aMethods); + const b = createProtocol(bMethods); + + const combined = combine.protocols(a, b); + expect(Object.keys(combined.methods).sort()).toEqual(["a", "b"]); + }); + + it("combines inspectors and their attach results", function* () { + type AMethods = { a: Method }; + type BMethods = { b: Method }; + + const schema = scope({ + NoneArr: "never[]", + None: "never", + Str: "string", + }).export(); + + const aProtoMethods: AMethods = { + a: { args: schema.NoneArr, progress: schema.None, returns: schema.Str }, + }; + const bProtoMethods: BMethods = { + b: { args: schema.NoneArr, progress: schema.None, returns: schema.Str }, + }; + + const aProto = createProtocol(aProtoMethods); + const bProto = createProtocol(bProtoMethods); + + const aIns = createImplementation(aProto, function* () { + return { + *a(): Stream { + return { + *next() { + return { done: true, value: "A" }; + }, + }; + }, + }; + }); + + const bIns = createImplementation(bProto, function* () { + return { + *b(): Stream { + return { + *next() { + return { done: true, value: "B" }; + }, + }; + }, + }; + }); + + const combined = combine.inspectors(aIns, bIns); + const handle = yield* combined.attach(); + + expect(Object.keys(handle.protocol.methods).sort()).toEqual(["a", "b"]); + + const aStream = handle.invoke({ name: "a", args: [] }); + const aSub = yield* aStream; + const aNext = yield* aSub.next(); + expect(aNext).toEqual({ done: true, value: "A" }); + + const bStream = handle.invoke({ name: "b", args: [] }); + const bSub = yield* bStream; + const bNext = yield* bSub.next(); + expect(bNext).toEqual({ done: true, value: "B" }); + }); +}); diff --git a/inspector/crank/.gitignore b/inspector/crank/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/inspector/crank/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/inspector/crank/app/app.tsx b/inspector/crank/app/app.tsx new file mode 100644 index 00000000..368bea94 --- /dev/null +++ b/inspector/crank/app/app.tsx @@ -0,0 +1,43 @@ +import type { Context } from "@b9g/crank"; +import { router } from "../src/router.ts"; +import { Layout } from "./layout.tsx"; +import { Home } from "./home.tsx"; +import { Live } from "./live.tsx"; +import { Demo } from "./demo.tsx"; +import { Recording } from "./recording.tsx"; + +export async function* App(this: Context): AsyncGenerator { + let route = router.route; + router.listen(() => + this.refresh(() => { + route = router.route; + }), + ); + + for ({} of this) { + switch (route) { + case "home": + yield ; + break; + case "live": + yield ( + + + + ); + break; + case "demo": + yield ; + break; + case "recording": + yield ; + break; + default: + yield ( + +

404 Not found

+ + ); + } + } +} diff --git a/inspector/crank/app/components/card.module.css b/inspector/crank/app/components/card.module.css new file mode 100644 index 00000000..7c9025b2 --- /dev/null +++ b/inspector/crank/app/components/card.module.css @@ -0,0 +1,9 @@ +.cardText { + color: inherit; +} +.cardHead { + display: flex; + gap: 12px; + align-items: flex-start; + padding: 12px; +} diff --git a/inspector/crank/app/components/graphic.tsx b/inspector/crank/app/components/graphic.tsx new file mode 100644 index 00000000..ccb188fe --- /dev/null +++ b/inspector/crank/app/components/graphic.tsx @@ -0,0 +1,381 @@ +import * as d3 from "d3"; +import type { Context } from "@b9g/crank"; +import type { Hierarchy } from "../data/types.ts"; + +type GraphicViewOptions = { + orientation: "vertical" | "horizontal"; +}; + +// using an async function generator so we can call `scheduleRender` after yielding +// the SVG element to ensure it's in the DOM and has dimensions before +// we attempt to render the chart. Other methods lead to infinite render loops. +export async function* Graphic( + this: Context, + { hierarchy, selection }: { hierarchy: Hierarchy; selection: Hierarchy }, +) { + let svgEl: SVGSVGElement | null = null; + // orientation state (vertical by default as requested) + let orientation = "vertical" as GraphicViewOptions["orientation"]; + // track the currently selected id so scheduleRender can pass it into renderChart + let currentSelectionId: string | undefined = selection?.id; + + function resetZoom() { + if (!svgEl) return; + const svg = d3.select(svgEl); + const zoomNode = svg.node(); + if (zoomNode && "__zoomBehavior" in zoomNode) { + svg + .transition() + .duration(350) + .call((zoomNode as any).__zoomBehavior.transform, d3.zoomIdentity); + } + } + + function scheduleRender() { + if (!hierarchy) return; + const svg = svgEl; + if (!svg) return; + const root = svg.closest && (svg.closest("html") as Element | null); + if (!root) return; + const graphicWrapper = + svg.closest && (svg.closest("#graphic-wrapper") as Element | null); + if (!graphicWrapper) return; + + const svgRect = svg.getBoundingClientRect(); + const rootRect = root.getBoundingClientRect(); + const wrapperRect = graphicWrapper.getBoundingClientRect(); + + const box = { + width: wrapperRect.width, + // height is total available from svg top to window bottom + height: Math.max(0, rootRect.height - svgRect.top), + }; + + // ensure the latest selection id is passed to the chart renderer + currentSelectionId = selection?.id; + + // console.log("Container box for Graphic render:", box); + if (!box.width || !box.height) { + // console.warn("Graphic render skipped due to zero width or height:", box); + return; + } + + try { + // there is padding in the tab-panel so if we set it too large, it shifts outside + // and triggers a resize loop. We can leave a small gap to avoid this. + renderChart(svg, box, hierarchy, orientation, currentSelectionId); + } catch (err) { + console.error("renderChart error (Graphic):", err); + } + } + + // listen to sl-resize events bubbled from + this.addEventListener("sl-resize", () => { + this.refresh(); + }); + + for await ({ hierarchy, selection } of this) { + // keep a live copy of the selected id (loop-scoped selection gets updated) + currentSelectionId = selection?.id; + + yield ( +
+
+ { + if (orientation !== "vertical") { + orientation = "vertical"; + resetZoom(); + this.refresh(); + } + scheduleRender(); + }} + > + Vertical + + { + if (orientation !== "horizontal") { + orientation = "horizontal"; + resetZoom(); + this.refresh(); + } + scheduleRender(); + }} + > + Horizontal + +
+ +
+ + { + svgEl = el; + }} + > + Process graph + + + + +
+
+ ); + // schedule a render after yielding the SVG element to ensure it's in the DOM and has dimensions + scheduleRender(); + } +} + +function textValue(node: d3.HierarchyNode) { + const labelName = (node.data.data["@effection/attributes"] as any)?.name; + return `${node.data.id} [${labelName}]`; +} + +function themeBasedFill(dark: string, light: string) { + // Prefer explicit app theme class, then fall back to system preference + if (typeof window === "undefined") return light; + if (document.documentElement.classList.contains("sl-theme-dark")) return dark; + if ( + window.matchMedia && + window.matchMedia("(prefers-color-scheme: dark)").matches + ) + return dark; + return light; +} + +export function renderChart( + ref: SVGSVGElement, + container: { width: number; height: number }, + data: Hierarchy, + orientation: "vertical" | "horizontal" = "vertical", + selectedId?: string, +) { + const root = d3.hierarchy(data); + // Scale the vertical spacing based on the panel height so the tree fills + // the available vertical space rather than always using a tiny fixed value. + const descendantCount = root.descendants().length; + const dx = Math.max(20, (container.height || 0) / (descendantCount + 1)); + const dy = container.width / (root.height + 1); + + // Create a tree layout with computed spacing. + const tree = d3.tree().nodeSize([dx, dy]); + + // Sort the tree and apply the layout. + root.sort((a, b) => d3.ascending(a.data.id, b.data.id)); + tree(root as unknown as d3.HierarchyNode); + + // Compute the extent of the tree (extent is along the "x" value used by the layout) + let x0 = Number.POSITIVE_INFINITY; + let x1 = -x0; + root.each((d) => { + if (typeof d.x === "number") { + if (d.x > x1) x1 = d.x; + if (d.x < x0) x0 = d.x; + } + }); + + // Compute the adjusted span along the x axis used by the layout. + const spanX = x1 - x0 + dx * 2; + + const svg = d3.select(ref); + + // Ensure a viewport group exists: we apply zoom/pan transforms to this group. + if (svg.select("g[data-viewport]").empty()) { + svg.append("g").attr("data-viewport", ""); + } + const viewport = svg.select("g[data-viewport]"); + + // Ensure groups exist within the viewport for stable selection (links / nodes) + if (viewport.select("g[data-links]").empty()) { + viewport.append("g").attr("data-links", ""); + } + if (viewport.select("g[data-nodes]").empty()) { + viewport.append("g").attr("data-nodes", ""); + } + + // Preserve any user-applied transform (zoom/pan) across re-renders. + const currentTransform = viewport.attr("transform"); + + // Compute viewBox depending on orientation. For vertical we place the x span + // horizontally (viewBox x origin = x0 - dx) and let the vertical dimension be the + // container height. For horizontal we place the x span vertically as before. + if (orientation === "vertical") { + svg + .attr("width", container.width) + .attr("height", container.height) + .attr("viewBox", [x0 - dx, -dy / 3, spanX, container.height]) + .attr("preserveAspectRatio", "xMinYMin meet"); + } else { + // horizontal (existing behavior) + svg + .attr("width", container.width) + .attr("height", container.height) + .attr("viewBox", [-dy / 3, x0 - dx, container.width, spanX]) + .attr("preserveAspectRatio", "xMinYMin meet"); + } + + // Install zoom behavior once. + const nodeZoom = svg.node(); + if (nodeZoom && !("__zoomInitialized" in nodeZoom)) { + const zoomBehavior = d3 + .zoom() + .scaleExtent([0.2, 6]) + .on("zoom", (event) => { + viewport.attr("transform", event.transform); + }); + + // Apply the zoom behavior to the svg. Casts added for TS safety. + svg.call( + zoomBehavior as unknown as d3.ZoomBehavior, + ); + + // dblclick to reset zoom + svg.on("dblclick.zoom", () => { + svg + .transition() + .duration(350) + .call((sel) => + sel.call(zoomBehavior.transform as any, d3.zoomIdentity), + ); + }); + + // @ts-expect-error Mark the node as having the zoom behavior initialized + // so we don't re-apply it on every render. + nodeZoom.__zoomInitialized = true; + // store the behavior so callers can reset programmatically + // @ts-expect-error + nodeZoom.__zoomBehavior = zoomBehavior; + } + + // Restore preserved transform (if any) + if (currentTransform) { + viewport.attr("transform", currentTransform); + } + + const linksGroup = viewport + .select("g[data-links]") + .attr("fill", "none") + .attr("stroke", "#555") + .attr("stroke-opacity", 0.4) + .attr("stroke-width", 1.5); + + linksGroup + .selectAll("path") + .data(root.links()) + .join( + (enter) => enter.append("path"), + (update) => update, + (exit) => exit.remove(), + ) + .attr("d", (link) => { + const s = link.source; + const t = link.target; + if ( + typeof s.y !== "number" || + typeof s.x !== "number" || + typeof t.y !== "number" || + typeof t.x !== "number" + ) { + return ""; + } + if (orientation === "vertical") { + // for vertical layout: coordinates are (x,y) -> translate(x,y) + return `M${s.x},${s.y}C${s.x},${(s.y + t.y) / 2} ${t.x},${(s.y + t.y) / 2} ${t.x},${t.y}`; + } + // horizontal layout: existing behavior (translate(y,x)) + return `M${s.y},${s.x}C${(s.y + t.y) / 2},${s.x} ${(s.y + t.y) / 2},${t.x} ${t.y},${t.x}`; + }); + + const node = viewport + .select("g[data-nodes]") + .selectAll("g") + .data(root.descendants()) + .join( + (enter) => enter.append("g"), + (update) => update, + (exit) => exit.remove(), + ) + .attr("id", (d) => `g-${d.data.id}`) + .attr("stroke-linejoin", "round") + .attr("stroke-width", 3) + .attr("transform", (d) => { + if (orientation === "vertical") return `translate(${d.x},${d.y})`; + return `translate(${d.y},${d.x})`; + }) + .style("cursor", "pointer") + .on("click", function (event: any, d: any) { + event.stopPropagation(); + const id = d && d.data && d.data.id; + if (id) { + (ref as Element).dispatchEvent( + new CustomEvent("sl-selection-change", { + detail: { selection: [{ dataset: { id } }] }, + bubbles: true, + composed: true, + }), + ); + } + }) + .attr("data-selected", (d) => (selectedId === d.data.id ? "true" : null)); + + node + .selectAll("circle") + .data((d) => [d]) + .join( + (enter) => enter.append("circle").attr("r", 0), + (update) => update, + (exit) => exit.remove().attr("fill", "red"), + ) + .attr("fill", (d: any) => + selectedId === d.data.id ? "#ff9800" : d.children ? "#555" : "#999", + ) + .transition() + .duration(500) + .ease(d3.easeLinear) + .attr("stroke", (d: any) => (selectedId === d.data.id ? "#000" : "none")) + .attr("stroke-width", (d: any) => (selectedId === d.data.id ? 1.5 : 0)) + .attr("r", Math.max(2.5, Math.min(8, dx * 0.5))); + + node + .selectAll("text") + .data((d) => [d]) + .join( + (enter) => enter.append("text").attr("opacity", 0), + (update) => update, + (exit) => exit.remove().attr("opacity", 0), + ) + + .transition() + .duration(500) + .ease(d3.easeLinear) + .attr("dy", "0.31em") + .attr("x", (d: any) => { + if (orientation === "vertical") return 8; + return d.children ? -8 : 8; + }) + .attr("text-anchor", (d: any) => { + if (orientation === "vertical") return "start"; + return d.children ? "end" : "start"; + }) + .text((d: any) => textValue(d)) + .style("font-size", `${Math.max(5, Math.min(dx * 0.6, 10))}px`) + .attr("opacity", 1) + .attr("fill", themeBasedFill("white", "black")) + .attr("paint-order", "fill"); +} diff --git a/inspector/crank/app/components/header.tsx b/inspector/crank/app/components/header.tsx new file mode 100644 index 00000000..cba5b7b5 --- /dev/null +++ b/inspector/crank/app/components/header.tsx @@ -0,0 +1,44 @@ +import layoutStyles from "../layout.module.css"; + +export function Header({ toggleTheme }: { toggleTheme: () => void }): Element { + return ( +
+
+
+ + Effection logo + Effection logo dark + +
+ +
+ toggleTheme()} + > + + + + + + + +
+
+
+ ); +} diff --git a/inspector/crank/app/components/hierarchy-details.module.css b/inspector/crank/app/components/hierarchy-details.module.css new file mode 100644 index 00000000..aea67edc --- /dev/null +++ b/inspector/crank/app/components/hierarchy-details.module.css @@ -0,0 +1,85 @@ +.detailsContainer { + padding: 12px; + display: flex; + flex-direction: column; + gap: 12px; +} +.tabControls { + display: flex; + gap: 8px; +} + +.tabPanel { + border-top: 1px solid var(--sl-color-neutral-200, #e5e7eb); + padding-top: 12px; +} +.headerRow { + display: flex; + gap: 12px; + align-items: center; + justify-content: space-between; +} +.parentSection { + margin-top: 12px; +} +.copyAll { + padding: 6px 10px; + background: transparent; + border: 1px solid var(--sl-color-neutral-200, #e5e7eb); + border-radius: 6px; +} +.propertiesSection { + margin-top: 8px; +} +.propertiesHeader { + display: flex; + align-items: center; + justify-content: space-between; +} +.kvList { + margin-top: 8px; +} +.kvRow { + display: flex; + gap: 12px; + padding: 6px 0; + border-bottom: 1px dashed rgba(0, 0, 0, 0.03); +} +.propertyKey { + font-weight: 600; + min-width: 140px; +} +.propertyValue { + flex: 1; + white-space: pre-wrap; +} +.parentSection .detailsHeading { + margin-bottom: 6px; +} +.childRow { + display: flex; + justify-content: space-between; + padding: 8px; + border: 1px solid var(--sl-color-neutral-200, #e5e7eb); + border-radius: 6px; + margin: 6px 0; +} +.clickable { + cursor: pointer; +} +.mutedText { + color: var(--sl-color-neutral-600, #6b7280); +} +.detailsHeading { + font-weight: 700; +} +.statusText { + margin-left: 8px; +} +.childrenList { + margin-top: 8px; +} +.childType { + color: var(--sl-color-neutral-600, #6b7280); + font-size: 13px; +} diff --git a/inspector/crank/app/components/hierarchy-details.tsx b/inspector/crank/app/components/hierarchy-details.tsx new file mode 100644 index 00000000..a2796faa --- /dev/null +++ b/inspector/crank/app/components/hierarchy-details.tsx @@ -0,0 +1,120 @@ +import { getNodeLabel } from "../data/labels.ts"; +import type { Hierarchy } from "../data/types.ts"; + +import detailsStyles from "./hierarchy-details.module.css"; + +function valueToString(v: unknown): string { + if (v === null || v === undefined) return ""; + if (typeof v === "object") { + try { + return JSON.stringify(v); + } catch (_err) { + return String(v); + } + } + return String(v); +} + +function flattenNodeData( + data: Record | undefined, +): Array<{ k: string; v: string }> { + const top = data ?? {}; + const topLevelKeys = Object.keys(top); + + return Object.entries(top).flatMap(([k, v]) => { + if (v && typeof v === "object" && !Array.isArray(v)) { + const entries = Object.entries(v as Record); + if (topLevelKeys.length === 1) { + return entries.map(([subk, subv]) => ({ + k: subk, + v: valueToString(subv), + })); + } + return entries.map(([subk, subv]) => ({ + k: `${k}.${subk}`, + v: valueToString(subv), + })); + } + return [{ k, v: valueToString(v) }]; + }); +} + +export function Details({ slot, node }: { slot?: string; node: Hierarchy }) { + function copyAllProperties() { + if (!node) return; + const txt = JSON.stringify(node.data ?? {}, null, 2); + if ( + navigator.clipboard && + typeof navigator.clipboard.writeText === "function" + ) { + navigator.clipboard.writeText(txt).catch(() => {}); + } + } + + const properties = flattenNodeData(node.data); + + return ( +
+ + + Attributes + + + JSON{" "} + + + +
{JSON.stringify(node, null, 2)}
+
+ + +
+
+
+
+ {node ? getNodeLabel(node) : "Attributes"} +
+
+ {node ? String(node.data.type ?? "") : ""} +
+
+
+ ● {String(node.data.status ?? "")} +
+
+ +
+
+
Properties
+
+ +
+
+ +
+ {properties.length === 0 ? ( +
No properties
+ ) : ( + properties.map((p) => ( +
+
{p.k}
+
+ {String(p.v)} +
+
+ )) + )} +
+
+
+
+
+
+ ); +} diff --git a/inspector/crank/app/components/hierarchy-view.tsx b/inspector/crank/app/components/hierarchy-view.tsx new file mode 100644 index 00000000..c747492c --- /dev/null +++ b/inspector/crank/app/components/hierarchy-view.tsx @@ -0,0 +1,38 @@ +import type { Hierarchy } from "../data/types.ts"; +import { getNodeLabel } from "../data/labels.ts"; + +export function TreeView({ + hierarchy, + selection, + slot, +}: { + hierarchy: Hierarchy; + selection: Hierarchy; + slot?: string; +}) { + return ( + + + + ); +} + +export function TreeNode({ + hierarchy, + selection, +}: { hierarchy: Hierarchy; selection: Hierarchy }): Element { + let selected = hierarchy.id === selection.id; + return ( + + {getNodeLabel(hierarchy)} + {hierarchy.children.map((h) => ( + + ))} + + ); +} diff --git a/inspector/crank/app/components/playback-controls.module.css b/inspector/crank/app/components/playback-controls.module.css new file mode 100644 index 00000000..f38040ed --- /dev/null +++ b/inspector/crank/app/components/playback-controls.module.css @@ -0,0 +1,73 @@ +.wrapper { + /* Reduced top padding to sit closer to the nav and added right padding to + provide a comfortable gap before the page edge. We use a negative top + margin to remove the extra space so the gap above the controls matches + the space below (divider spacing is 8px). */ + padding: 4px 20px 12px 12px; + margin-top: -1px; +} + +.controls { + display: flex; + gap: 12px; + align-items: center; +} +.controls label { + display: inline-flex; + gap: 8px; + align-items: center; +} + +/* Make the range take the remaining available space */ +.controls sl-range { + flex: 1 1 auto; + min-width: 0; /* allow shrinking in tight spaces */ + width: 100%; + /* custom track colors (can be overridden by theme) */ + --track-color-active: var(--accent-color, #0ea5ff); + --track-color-inactive: rgba(255, 255, 255, 0.06); + --track-height: 6px; +} + +/* Ensure buttons and labels don't shrink and keep their intrinsic size */ +.controls sl-button, +.controls #offset-label { + flex: 0 0 auto; +} + +/* Display the current and max value to the right of the track */ +.valueDisplay { + flex: 0 0 auto; + margin-left: 8px; + color: var(--sl-color-neutral-500, rgba(255, 255, 255, 0.7)); + font-size: 13px; + align-self: center; +} + +/* Dark theme tweaks */ +:global(.sl-theme-dark) .controls sl-range { + --track-color-inactive: rgba(255, 255, 255, 0.06); +} +:global(:not(.sl-theme-dark)) .controls sl-range { + --track-color-inactive: rgba(0, 0, 0, 0.08); + --track-color-active: var(--sl-color-primary-500, #0ea5ff); +} +.divider { + /* Use Shoelace custom properties so the divider can control spacing/color/width */ + --color: rgba(255, 255, 255, 0.04); + --width: 1px; + --spacing: 0px; /* reduce spacing so the split panel reaches the divider */ + + /* Fallback styling for older browsers or if the custom properties aren't picked up */ + margin-top: 8px; + border-color: var(--color); + border-top-width: var(--width); +} + +/* Dark and light theme adjustments */ +:global(.sl-theme-dark) .divider { + --color: rgba(255, 255, 255, 0.06); +} +:global(:not(.sl-theme-dark)) .divider { + --color: rgba(0, 0, 0, 0.06); +} diff --git a/inspector/crank/app/components/playback-controls.tsx b/inspector/crank/app/components/playback-controls.tsx new file mode 100644 index 00000000..33568ee3 --- /dev/null +++ b/inspector/crank/app/components/playback-controls.tsx @@ -0,0 +1,100 @@ +import type { Context } from "@b9g/crank"; +import { + createScope, + Ok, + sleep, + withResolvers, + type Operation, +} from "effection"; +import type { Recording } from "../data/recording.ts"; +import playbackStyles from "./playback-controls.module.css"; + +export async function* PlaybackControls( + { + recording, + tickIntervalMs = 600, + }: { + recording: Recording; + tickIntervalMs?: number; + }, + ctx: Context, +) { + let [scope, destroy] = createScope(); + let offset = 0; + let playing = false; + let refresh = ctx.refresh.bind(ctx); + + let playLoop = withResolvers(); + scope.run(function* (): Operation { + while (true) { + playLoop = withResolvers(); + while (playing) { + console.log("looping", { playing, offset }); + if (playing) { + const nextOffset = offset + 1 > recording.length - 1 ? 0 : offset + 1; + console.log(nextOffset, recording.length); + recording.setOffset(nextOffset); + + refresh(() => (offset = nextOffset)); + yield* sleep(tickIntervalMs); + } + } + yield* playLoop.operation; + } + }); + + ctx.addEventListener("sl-input", (event) => { + if (playing) { + playing = false; + } + + const v = Number( + event?.target && "value" in event?.target ? event.target.value : 0, + ); + recording.setOffset(v); + refresh(() => (offset = v)); + }); + + try { + for ({} of ctx) { + yield ( + <> +
+
+ { + console.log("play/pause clicked"); + refresh(() => { + playing = !playing; + playLoop.resolve(Ok()); + }); + }} + > + {playing ? "Pause" : "Play"} + + +
Offset:
+ + +
+ {offset} / {recording ? (recording as Recording).length - 1 : 0} +
+
+
+ + + + ); + } + } finally { + await destroy(); + } +} diff --git a/inspector/crank/app/components/render-recording.tsx b/inspector/crank/app/components/render-recording.tsx new file mode 100644 index 00000000..4aac8415 --- /dev/null +++ b/inspector/crank/app/components/render-recording.tsx @@ -0,0 +1,51 @@ +import { Fragment, type Context } from "@b9g/crank"; + +import { + resource, + type Subscription, +} from "effection"; +import { pipe } from "remeda"; +import { arrayLoader, useRecording } from "../data/recording.ts"; +import type { Recording } from "../data/recording.ts"; +import { raf, sample } from "../data/sample.ts"; +import { stratify } from "../data/stratify.ts"; +import type { NodeMap } from "../data/types.ts"; +import { PlaybackControls } from "../components/playback-controls.tsx"; +import type { Stratification } from "../data/stratify.ts"; +import { StructureInspector } from "./structure-inspector.tsx"; +import { createCrankScope } from "../lib/crank-scope.ts"; + +export async function* RenderRecording( + { nodeMap }: { nodeMap: NodeMap[] }, + ctx: Context, +): AsyncGenerator { + let scope = createCrankScope(ctx); + let $recording = Promise.withResolvers(); + + let structure = scope.bind( + resource>(function* (provide) { + let recording = yield* useRecording(arrayLoader(nodeMap)); + $recording.resolve(recording); + + const hierarchies = pipe( + recording.replayStream(), + sample(raf()), + stratify(), + ); + + yield* provide(yield* hierarchies); + }), + { root: { id: "Global", children: [], data: {} }, hierarchies: {} }, + ); + + let recording = await $recording.promise; + + for ({} of ctx) { + yield ( + + + + + ); + } +} diff --git a/inspector/crank/app/components/structure-inspector.tsx b/inspector/crank/app/components/structure-inspector.tsx new file mode 100644 index 00000000..592a7fff --- /dev/null +++ b/inspector/crank/app/components/structure-inspector.tsx @@ -0,0 +1,139 @@ +import type { Hierarchy } from "../data/types.ts"; +import { getNodeLabel } from "../data/labels.ts"; +import { Details } from "./hierarchy-details.tsx"; +import type { Stratification } from "../data/stratify.ts"; +import type { Context } from "@b9g/crank"; +import { Graphic } from "./graphic.tsx"; +import { createCrankScope } from "../lib/crank-scope.ts"; +import { settings } from "../data/settings.ts"; + +export interface StructureInspectorFilters { + showInspectorRuntime: boolean; + showAnonymousScopes: boolean; +} + +export interface StructureInspectorProps { + structure?: Stratification; +} + +export function* StructureInspector( + this: Context, + { structure = initialStructure() }: StructureInspectorProps, +): Generator { + let scope = createCrankScope(this); + + let selection: Hierarchy | undefined = undefined; + + let filters = scope.bind(settings, settings.value); + + this.addEventListener("sl-selection-change", (e) => { + let [item] = e.detail.selection; + let id = item.dataset.id!; + this.refresh(() => (selection = structure.hierarchies[id]!)); + }); + + for ({ structure = initialStructure() } of this) { + let root = applyFilters(filters.value, structure.root); + selection = selection ?? root; + + yield ( + + +
+ + ); + } +} + +export function TreeView({ + root, + selection, + slot, +}: { + root: Hierarchy; + selection: Hierarchy; + slot?: string; +}) { + return ( + + + Tree + + + Graphic + + + + + + + + + + + ); +} + +export function TreeNode({ + hierarchy, + selection, +}: { + hierarchy: Hierarchy; + selection: Hierarchy; +}): Element { + let selected = hierarchy.id === selection.id; + return ( + + {getNodeLabel(hierarchy)} + {hierarchy.children.map((h) => ( + + ))} + + ); +} + +export function initialStructure(): Stratification { + let root: Hierarchy = { + children: [], + id: "0", + data: { + "@effection/attributes": { name: "Global" }, + }, + }; + + return { + root, + hierarchies: { [root.id]: root }, + }; +} + +function applyFilters( + filters: Partial, + root: Hierarchy, +): Hierarchy { + let children = root.children.flatMap((child) => { + let attributes = (child.data["@effection/attributes"] ?? {}) as Record< + string, + unknown + >; + if (attributes.name === "Inspector" && !filters.showInspectorRuntime) { + return []; + } else if ( + attributes.name === "anonymous" && + !filters.showAnonymousScopes + ) { + return child.children; + } else { + return [applyFilters(filters, child)]; + } + }); + return { + ...root, + children, + }; +} diff --git a/inspector/crank/app/data/box.ts b/inspector/crank/app/data/box.ts new file mode 100644 index 00000000..a614d015 --- /dev/null +++ b/inspector/crank/app/data/box.ts @@ -0,0 +1,9 @@ +import { Err, Ok, type Operation, type Result } from "effection"; + +export function* box(op: () => Operation): Operation> { + try { + return Ok(yield* op()); + } catch (error) { + return Err(error as Error); + } +} diff --git a/inspector/crank/app/data/connection.ts b/inspector/crank/app/data/connection.ts new file mode 100644 index 00000000..d7594e10 --- /dev/null +++ b/inspector/crank/app/data/connection.ts @@ -0,0 +1,110 @@ +import { + createQueue, + resource, + scoped, + spawn, + Err, + type Result, + type Stream, + type Yielded, +} from "effection"; + +/** + * Trying to connect, but not sure yet. + */ +type Pending = { + type: "pending"; +}; + +/** + * The connection failed completely. Nothing was ever returned. + * There is no record that has been delivered + */ +type Failed = { + type: "failed"; + error: Error; +}; + +/** + * The connection is active and data is flowing. + */ +type Live = { + type: "live"; + latest: T; +}; + +/** + * The connection was closed by the remote end in an orderly fashion . + */ +type Closed = { + type: "closed"; + latest: T; + result: Result; +}; + +export type ConnectionState = + | Pending + | Failed + | Live + | Closed; + +export interface Connection + extends Stream, never> { + initial: ConnectionState; +} + +export function createConnection( + stream: Stream, +): Connection { + let initial: ConnectionState = { type: "pending" }; + let connection = resource>>( + function* (provide) { + let queue = createQueue, never>(); + + // queue.add(initial); + + let latest: IteratorYieldResult | undefined = undefined; + + yield* spawn(function* () { + try { + yield* scoped(function* () { + let subscription = yield* stream; + let next = yield* subscription.next(); + while (!next.done) { + latest = next; + queue.add({ type: "live", latest: latest.value }); + next = yield* subscription.next(); + } + if (!latest) { + queue.add({ + type: "failed", + error: new Error( + "connection closed before returning anything", + { cause: next.value }, + ), + }); + } + }); + } catch (cause) { + let error = + cause instanceof Error ? cause : new Error("unknown", { cause }); + if (latest) { + queue.add({ + type: "closed", + latest: latest.value, + result: Err(error), + }); + } else { + queue.add({ type: "failed", error }); + } + } + }); + + yield* provide(queue); + }, + ); + + return Object.assign(connection, { + initial, + }); +} diff --git a/inspector/crank/app/data/labels.ts b/inspector/crank/app/data/labels.ts new file mode 100644 index 00000000..fe91346f --- /dev/null +++ b/inspector/crank/app/data/labels.ts @@ -0,0 +1,11 @@ +import type { Hierarchy } from "./types.ts"; + +export const LABEL_ATTRIBUTE = "@effection/attributes"; + +export function getNodeLabel(node: Hierarchy): string { + const inspectorLabels = ( + node?.data && LABEL_ATTRIBUTE in node.data ? node.data[LABEL_ATTRIBUTE] : {} + ) as Record; + const label = String(inspectorLabels?.name ?? node.id); + return label === "anonymous" ? `${label} [${node.id}]` : label; +} diff --git a/inspector/crank/app/data/recording.ts b/inspector/crank/app/data/recording.ts new file mode 100644 index 00000000..1a683b3c --- /dev/null +++ b/inspector/crank/app/data/recording.ts @@ -0,0 +1,60 @@ +import { type Stream, type Operation, createSignal } from "effection"; +import type { NodeMap } from "./types.ts"; +import { createSubject } from "@effectionx/stream-helpers"; +import { pipe } from "remeda"; + +export interface Recording { + length: number; + replayStream(): Stream; + setOffset(offset: number): void; +} + +export interface Cassette { + length: number; + loadOffset(offset: number): Operation; +} + +export interface Tick { + nodemap: NodeMap; +} + +export function* useRecording( + load: () => Operation, +): Operation { + let { length, loadOffset } = yield* load(); + let stream = createSignal(); + + const offsets = pipe(stream, createSubject(0)); + + return { + length, + setOffset: stream.send, + *replayStream() { + let subscription = yield* offsets; + + return { + *next() { + let next = yield* subscription.next(); + let tick = yield* loadOffset(next.value); + return { + done: false, + value: tick.nodemap, + }; + }, + }; + }, + }; +} + +export function arrayLoader(array: NodeMap[]): () => Operation { + return function* () { + return { + length: array.length, + *loadOffset(offset) { + return { + nodemap: array[offset], + }; + }, + }; + }; +} diff --git a/inspector/crank/app/data/sample.ts b/inspector/crank/app/data/sample.ts new file mode 100644 index 00000000..31918670 --- /dev/null +++ b/inspector/crank/app/data/sample.ts @@ -0,0 +1,55 @@ +import { + action, + all, + scoped, + spawn, + withResolvers, + type Operation, + type Yielded, +} from "effection"; +import type { Transform } from "./types.ts"; + +/** + * Sample a stream at an interval specified by `interval` + */ +export function sample(interval: Operation): Transform { + return (stream) => { + return { + *[Symbol.iterator]() { + let subscription = yield* stream; + + return { + next() { + return scoped(function* () { + let next: Yielded>; + let hasNext = withResolvers(); + + // spawn a task that will consume and drop frames + yield* spawn(function* () { + next = yield* subscription.next(); + hasNext.resolve(); + while (!next.done) { + next = yield* subscription.next(); + console.log("drop", next); + } + }); + + // we needf to await the interval AND have a next + yield* all([interval, hasNext.operation]); + return next!; + }); + }, + }; + }, + }; + }; +} + +export function raf(): Operation { + return action((resolve) => { + let id = requestAnimationFrame(resolve); + return () => { + cancelAnimationFrame(id); + }; + }); +} diff --git a/inspector/crank/app/data/settings.ts b/inspector/crank/app/data/settings.ts new file mode 100644 index 00000000..53aa0eb2 --- /dev/null +++ b/inspector/crank/app/data/settings.ts @@ -0,0 +1,15 @@ +import { type } from "arktype"; +import { createLocalStorage } from "./storage"; + +export const SettingsSchema = type({ + "showInspectorRuntime?": "boolean", + "showAnonymousScopes?": "boolean", +}); + +export type Settings = typeof SettingsSchema.infer; + +export const settings = createLocalStorage( + "settings", + SettingsSchema, + {}, +); diff --git a/inspector/crank/app/data/storage.ts b/inspector/crank/app/data/storage.ts new file mode 100644 index 00000000..ee4e8ec8 --- /dev/null +++ b/inspector/crank/app/data/storage.ts @@ -0,0 +1,74 @@ +import { filter, map } from "@effectionx/stream-helpers"; +import type { StandardSchemaV1 } from "@standard-schema/spec"; +import { + createSignal, + each, + on, + resource, + spawn, + type Stream, +} from "effection"; +import { pipe } from "remeda"; +import { validateUnsafe } from "../../../lib/validate"; + +export interface LocalStorage extends Stream { + value: T; + update(fn: (current: T) => T): void; +} + +export function createLocalStorage( + key: string, + schema: StandardSchemaV1, + defaultValue: T, +): LocalStorage { + let value = decode(schema, localStorage.getItem(key), defaultValue); + let signal = createSignal(); + + let stream: Stream = resource(function* (provide) { + let events = pipe( + on(window, "storage"), + filter(function* (event) { + return event.key === key; + }), + map(function* (event) { + return decode(schema, event.newValue, defaultValue); + }), + ); + + yield* spawn(function* () { + for (value of yield* each(events)) { + signal.send(value); + yield* each.next(); + } + }); + + yield* provide(yield* signal); + }); + + return { + ...stream, + get value() { + return value; + }, + update(fn) { + let next = fn(value); + validateUnsafe(schema, next); + if (next !== value) { + value = next; + localStorage.setItem(key, JSON.stringify(value)); + signal.send(value); + } + }, + }; +} + +function decode( + schema: StandardSchemaV1, + item: string | null, + defaultValue: T, +): T { + if (item === null) { + return defaultValue; + } + return validateUnsafe(schema, JSON.parse(item)); +} diff --git a/inspector/crank/app/data/stratify.ts b/inspector/crank/app/data/stratify.ts new file mode 100644 index 00000000..1a091e1b --- /dev/null +++ b/inspector/crank/app/data/stratify.ts @@ -0,0 +1,63 @@ +import { map } from "@effectionx/stream-helpers"; +import type { Hierarchy, NodeMap, Transform } from "./types.ts"; + +export type HierarchyMap = Record; + +export interface Stratification { + root: Hierarchy; + hierarchies: HierarchyMap; +} + +export function stratify(): Transform { + return map(function* (nodes) { + let stratii = new Map(); + + let rootId: string | undefined = undefined; + + for (let [id, node] of Object.entries(nodes)) { + let stratum = stratii.get(id); + if (!stratum) { + const s: Hierarchy = { + id, + parentId: node.parentId, + data: node.data, + children: [], + }; + stratii.set(id, s); + stratum = s; + } else { + // ensure parentId/data are set if this record was created earlier + stratum.parentId = node.parentId; + stratum.data = node.data; + } + if (!node.parentId) { + if (typeof rootId === "string") { + let current = stratii.get(rootId); + throw new TypeError( + `duplicate roots: [${JSON.stringify(current)}, ${JSON.stringify(node)}]`, + ); + } + rootId = node.id; + } else { + let parent = stratii.get(node.parentId); + if (!parent) { + console.warn(`unknown parent id: ${node.parentId}`); + } else { + parent.children.push(stratum); + } + } + } + + if (!rootId) { + throw new TypeError("Hierarchy did not contain a root node"); + } + + const root = stratii.get(rootId as string); + if (!root) { + throw new TypeError("Hierarchy did not contain a root node"); + } + + let hierarchies = Object.fromEntries(stratii.entries()); + return { root, hierarchies }; + }); +} diff --git a/inspector/crank/app/data/types.ts b/inspector/crank/app/data/types.ts new file mode 100644 index 00000000..d4baf72d --- /dev/null +++ b/inspector/crank/app/data/types.ts @@ -0,0 +1,23 @@ +import type { Stream } from "effection"; + +export interface Node { + id: string; + parentId?: string; + data: Record; +} + +export type NodeMap = Record; + +export interface Hierarchy { + id: string; + parentId?: string; + data: Record; + children: Hierarchy[]; +} + +/** + * A function that transforms one stream into another + */ +export type Transform = ( + input: Stream, +) => Stream; diff --git a/inspector/crank/app/data/update-node-map.ts b/inspector/crank/app/data/update-node-map.ts new file mode 100644 index 00000000..7963b68b --- /dev/null +++ b/inspector/crank/app/data/update-node-map.ts @@ -0,0 +1,33 @@ +import type { ScopeEvent } from "../../../scope/protocol.ts"; +import type { NodeMap, Transform } from "./types.ts"; +import { reduce } from "../../../lib/reduce.ts"; + +export function updateNodeMap( + initial: NodeMap, +): Transform { + return reduce(function* (nodemap, item) { + if (item.type === "tree") { + for (let node of item.value) { + nodemap[node.id] = { + id: node.id, + parentId: node.parentId, + data: node.data, + }; + } + } + if (item.type === "created") { + nodemap[item.id] = { + id: item.id, + parentId: item.parentId, + data: {}, + }; + } + if (item.type === "destroyed") { + delete nodemap[item.id]; + } + if (item.type === "set") { + nodemap[item.id].data[item.contextName] = item.contextValue; + } + return nodemap; + }, initial); +} diff --git a/inspector/crank/app/demo.json b/inspector/crank/app/demo.json new file mode 100644 index 00000000..9374ad20 --- /dev/null +++ b/inspector/crank/app/demo.json @@ -0,0 +1,13661 @@ +[ + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": {} + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": {} + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": {} + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": {} + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": {} + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": {} + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": {} + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": {} + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "44": { + "id": "44", + "parentId": "43", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "46": { + "id": "46", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + }, + "58": { + "id": "58", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + }, + "58": { + "id": "58", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + }, + "58": { + "id": "58", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + }, + "58": { + "id": "58", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + }, + "58": { + "id": "58", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + }, + "58": { + "id": "58", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "45": { + "id": "45", + "parentId": "43", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + }, + "57": { + "id": "57", + "parentId": "43", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "43": { + "id": "43", + "parentId": "42", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "42": { + "id": "42", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/play", + "method": "GET" + } + } + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "47": { + "id": "47", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 1 + } + } + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "48": { + "id": "48", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 2 + } + } + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "54": { + "id": "54", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 8 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "52": { + "id": "52", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 6 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "49": { + "id": "49", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 3 + } + } + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "50": { + "id": "50", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 4 + } + } + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "53": { + "id": "53", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 7 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "55": { + "id": "55", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 9 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "51": { + "id": "51", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 5 + } + } + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + }, + "56": { + "id": "56", + "parentId": "3", + "data": { + "@effection/attributes": { + "name": "child", + "number": 10 + } + } + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "3": { + "id": "3", + "parentId": "2", + "data": { + "@effection/attributes": { + "name": "main", + "args": ["--break"] + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "2": { + "id": "2", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "anonymous" + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + } + }, + { + "0": { + "id": "0", + "data": { + "@effection/attributes": { + "name": "Global" + } + } + }, + "1": { + "id": "1", + "parentId": "0", + "data": { + "@effection/attributes": { + "name": "Inspector" + } + } + }, + "4": { + "id": "4", + "parentId": "1", + "data": { + "@effection/attributes": { + "name": "SSEServer", + "port": 41000 + } + } + }, + "31": { + "id": "31", + "parentId": "4", + "data": { + "@effection/attributes": { + "name": "RequestHandler", + "url": "/watchScopes", + "method": "POST" + } + } + }, + "32": { + "id": "32", + "parentId": "31", + "data": { + "@effection/attributes": { + "name": "Transport" + } + } + }, + "39": { + "id": "39", + "parentId": "32", + "data": { + "@effection/attributes": { + "name": "streamEvents" + } + } + }, + "40": { + "id": "40", + "parentId": "32", + "data": {} + }, + "41": { + "id": "41", + "parentId": "32", + "data": {} + } + } +] diff --git a/inspector/crank/app/demo.tsx b/inspector/crank/app/demo.tsx new file mode 100644 index 00000000..accea3d1 --- /dev/null +++ b/inspector/crank/app/demo.tsx @@ -0,0 +1,17 @@ +import type { Context, Element } from "@b9g/crank"; +import { Layout } from "./layout.tsx"; +import type { NodeMap } from "./data/types.ts"; +import { RenderRecording } from "./components/render-recording.tsx"; +import json from "./demo.json" with { type: "json" }; + +export function* Demo(this: Context): Generator { + const nodeMap = json as unknown as NodeMap[]; + + for ({} of this) { + yield ( + + + + ); + } +} diff --git a/inspector/crank/app/global.css b/inspector/crank/app/global.css new file mode 100644 index 00000000..740a3ebb --- /dev/null +++ b/inspector/crank/app/global.css @@ -0,0 +1,19 @@ +html, +body { + height: 100%; +} + +body { + display: flex; + flex-direction: column; +} + +main { + flex-grow: 1; + /* Ensure sticky top bar doesn't overlap content */ + padding-top: 16px; +} + +sl-split-panel { + height: 100%; +} diff --git a/inspector/crank/app/home.module.css b/inspector/crank/app/home.module.css new file mode 100644 index 00000000..b4cf79b3 --- /dev/null +++ b/inspector/crank/app/home.module.css @@ -0,0 +1,75 @@ +.recordingUpload { + display: flex; + gap: 12px; + align-items: center; +} +.hiddenFileInput { + display: none; +} +.meta { + color: var(--sl-color-neutral-600, #6b7280); + font-size: 13px; +} +.homePage { + padding: 48px 56px; + min-height: 100vh; + box-sizing: border-box; +} +.homeMain { + max-width: 1200px; + margin: 0 auto; +} +.recentSection { + margin-top: 48px; +} +.recentHeader { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 18px; +} +.recentList { + display: grid; + gap: 12px; +} +.sessionCard { + padding: 0; +} +.sessionRow { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + padding: 12px; +} +.sessionIcon { + width: 44px; + height: 44px; + display: flex; + align-items: center; + justify-content: center; +} +.clearIcon { + font-size: 14px; + vertical-align: middle; +} +.clearAction { + display: flex; + gap: 8px; + align-items: center; +} +.sessionInfo { + margin-left: 8px; +} +.sessionTitle { + font-weight: 700; +} +.sessionMeta { + margin-top: 6px; + color: var(--sl-color-neutral-600, #6b7280); + font-size: 13px; +} +.sessionAction { + margin-left: auto; +} diff --git a/inspector/crank/app/home.tsx b/inspector/crank/app/home.tsx new file mode 100644 index 00000000..aca44d63 --- /dev/null +++ b/inspector/crank/app/home.tsx @@ -0,0 +1,230 @@ +import type { Context } from "@b9g/crank"; +import { Layout } from "./layout.tsx"; +import { router } from "../src/router.ts"; +import layoutStyles from "./layout.module.css"; +import cardStyles from "./components/card.module.css"; +import homeStyles from "./home.module.css"; + +function FeatureCards({ uploadSlot }: { uploadSlot?: Element }) { + return ( +
+ +
+ +
+

Connect to Live Process

+
+ Inspect a running Effection process in real-time via WebSocket + connection +
+
+
+ +
+ + + Start Connection + + +
WebSocket URL required
+
+
+ + +
+ +
+

Load Recording

+
+ Analyze a previously recorded session with time-travel controls + and playback +
+
+
+ +
+ {uploadSlot} +
.json, .effection files
+
+
+ + +
+ +
+

Try Demo

+
+ Explore the inspector with a sample process—no setup or + configuration required +
+
+ + Recommended + +
+ +
+ + + Launch Demo + + +
Perfect for first-time users
+
+
+
+ ); +} + +function RecentSessions() { + return ( +
+
+

Recent Sessions

+
+ + Clear History +
+
+
+
+ +
+
+ +
+
+
+ ws://localhost:8080/inspector{" "} + + Live + +
+
+ Last accessed 2 hours ago +
+
+
+
+
+ +
+ +
+
+ +
+
+
+ api-server-session-2025-01-15.json{" "} + Recording +
+
+ Last accessed yesterday +
+
+
+ + Open + +
+
+
+
+ +
+ +
+
+ +
+
+
+ ws://staging.example.com:3000{" "} + + Live + +
+
+ Last accessed 3 days ago +
+
+
+
+
+ +
+ +
+
+ +
+
+
+ worker-pool-debug.effection{" "} + Recording +
+
+ Last accessed last week +
+
+
+
+
+
+
+ ); +} + +export async function* Home(this: Context): AsyncGenerator { + function RecordingUpload({ slot }: { slot?: string }) { + return ( +
+ + + (document.getElementById("file-input") as HTMLInputElement).click() + } + > + Browse files + +
+ ); + } + const handleFileSelect = (e: Event) => { + const input = e.currentTarget as HTMLInputElement; + const file = input.files?.[0]; + if (file) { + router.navigate({ route: "recording", state: { file } }); + } + }; + + for ({} of this) { + yield ( + +
+
+ } /> + + +
+
+
+ ); + } +} diff --git a/inspector/crank/app/layout.module.css b/inspector/crank/app/layout.module.css new file mode 100644 index 00000000..9c503cd0 --- /dev/null +++ b/inspector/crank/app/layout.module.css @@ -0,0 +1,192 @@ +.grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; + margin-top: 24px; +} + +.footer { + margin-top: 12px; + display: flex; + gap: 12px; + align-items: center; +} + +@media (max-width: 800px) { + .grid { + grid-template-columns: 1fr; + } +} + +/* Header / Top bar styles */ +.topBar { + position: sticky; + top: 0; + z-index: 50; + height: 52px; /* slightly shorter nav */ + display: flex; + align-items: center; + background: var(--topbar-bg, rgba(255, 255, 255, 0.02)); + border-bottom: 1px solid rgba(0, 0, 0, 0.06); + padding: 4px 6px; + -webkit-backdrop-filter: blur(6px); + backdrop-filter: blur(6px); +} + +.brand { + display: flex; + align-items: center; + gap: 12px; + width: 100%; +} + +.logo { + display: flex; + align-items: center; + height: 42px; /* slightly smaller to fit the shorter nav */ + padding: 0 6px; + margin-left: -6px; /* nudge more to the left edge */ + border-radius: 8px; + background: transparent; +} + +.logoButton { + padding: 0; + border: none; + background: transparent; + display: flex; + align-items: center; +} + +/* Logo image uses variables so we can tweak size; make it 2x and remove backgrounds */ +:root { + /* doubled size for logo */ + --logo-img-height: 36px; /* 1.5x */ + --logo-img-padding: 0; + --logo-img-bg: transparent; + --logo-img-border: none; + --logo-img-shadow: none; +} + +.logoImg { + height: var(--logo-img-height); + width: auto; + display: block; + /* keep the SVG unobstructed: no background, no padding, no border */ + background: transparent; + padding: 0; + border-radius: 0; + border: none; + box-shadow: none; +} + +.themeSwitcher { + margin-left: auto; + display: flex; + align-items: center; + height: 100%; + align-self: center; +} + +/* Ensure the theme toggle button itself is centered within the .themeSwitcher */ +.themeSwitcher sl-button { + align-self: center; +} + +.themeSwitcher sl-button::part(base) { + height: 32px; + display: flex; + align-items: center; + justify-content: center; + padding: 0 6px; + background: transparent; + border: none; + box-shadow: none; +} + +.iconSun { + display: inline-block; +} +.iconMoon { + display: none; +} + +/* Theme-aware tweaks */ +.themeLight { + --logo-bg: #1f2937; + --topbar-bg: #ffffff; +} + +.themeDark { + --logo-bg: rgba(255, 255, 255, 0.06); + --topbar-bg: #0b1220; +} + +.themeDark .iconSun { + display: none; +} +.themeDark .iconMoon { + display: inline-block; +} +.themeLight .iconSun { + display: inline-block; +} +.themeLight .iconMoon { + display: none; +} + +/* Swap which logo is visible depending on the theme (document-level class). + Default (light mode) shows the dark-logo asset, and dark mode shows the + white-logo asset so the text is always readable. */ +.lightLogo { + display: none; +} +.darkLogo { + display: block; +} + +/* When the document has the dark theme class, invert visible logos */ +:global(.sl-theme-dark) .lightLogo { + display: block; +} +:global(.sl-theme-dark) .darkLogo { + display: none; +} + +/* Ensure the sl-button wrapper doesn't add its own light background or + border that could make the logo or toggle text unreadable. Remove borders + for both the logo button and the theme-toggle button. */ +.logoButton::part(base), +.themeSwitcher sl-button::part(base) { + background: transparent; + box-shadow: none; + padding: 0; + border: none; + outline: none; +} + +.logoButton::part(base):hover, +.themeSwitcher sl-button::part(base):hover { + background: transparent; + border: none; +} + +.logoButton::part(base):focus, +.themeSwitcher sl-button::part(base):focus { + outline: none; + border: none; + box-shadow: none; +} + +/* removed theme-specific white backgrounds for the logo so it stays transparent */ +html:not(.sl-theme-dark) { + --logo-img-bg: transparent; + --logo-img-border: none; + --logo-img-shadow: none; +} + +.sl-theme-dark { + --logo-img-bg: transparent; + --logo-img-border: none; + --logo-img-shadow: none; +} diff --git a/inspector/crank/app/layout.tsx b/inspector/crank/app/layout.tsx new file mode 100644 index 00000000..90f0d740 --- /dev/null +++ b/inspector/crank/app/layout.tsx @@ -0,0 +1,136 @@ +import type { Children, Context } from "@b9g/crank"; +import layoutStyles from "./layout.module.css"; +import { settings } from "./data/settings.ts"; +import type { SlDrawer, SlLazyChangeEvent } from "@shoelace-style/shoelace"; +import { createScope, each, sleep } from "effection"; + +export async function* Layout( + this: Context, + { children }: { children: Children }, + cxt: Context, +): AsyncGenerator { + let [scope, destroy] = createScope(); + await using _ = { + [Symbol.asyncDispose]: destroy, + }; + + scope.run(function* () { + for ({} of yield* each(settings)) { + cxt.refresh(); + yield* each.next(); + } + }); + + // Initialize theme on client load using stored value or system preference + if (typeof window !== "undefined") { + const stored = localStorage.getItem("theme"); + const prefersDark = + typeof window.matchMedia === "function" && + window.matchMedia("(prefers-color-scheme: dark)").matches; + const theme = stored || (prefersDark ? "dark" : "light"); + + if (theme === "dark") { + document.documentElement.classList.add("sl-theme-dark"); + } else { + document.documentElement.classList.remove("sl-theme-dark"); + } + } + + function toggleTheme() { + const isDark = document.documentElement.classList.contains("sl-theme-dark"); + if (isDark) { + document.documentElement.classList.remove("sl-theme-dark"); + localStorage.setItem("theme", "light"); + } else { + document.documentElement.classList.add("sl-theme-dark"); + localStorage.setItem("theme", "dark"); + } + } + + let drawer: SlDrawer; + + this.addEventListener("sl-change", (event: SlLazyChangeEvent) => { + let { name, checked } = event.target as unknown as { + name: string; + checked: boolean; + }; + settings.update((current) => { + return { + ...current, + [name]: checked, + }; + }); + }); + + for ({} of this) { + yield ( +
+ (drawer = el)}> +

+ + Show Inspector Runtime + +

+

+ + Show Anonymous Scopes + +

+
+
+
+
+ + Effection logo + Effection logo dark + +
+ +
this.provide("toolbar", el)} + >
+ +
+ drawer.show()}> + + + toggleTheme()} + > + + + + + + + +
+
+
+
{children}
+
+ ); + } +} diff --git a/inspector/crank/app/lib/crank-scope.ts b/inspector/crank/app/lib/crank-scope.ts new file mode 100644 index 00000000..98c4697b --- /dev/null +++ b/inspector/crank/app/lib/crank-scope.ts @@ -0,0 +1,30 @@ +import type { Context as Crank } from "@b9g/crank"; +import { createScope, each, type Stream } from "effection"; + +export interface Ref { + value: T; +} + +export interface CrankScope { + bind(stream: Stream, initial: T): Ref; +} + +export function createCrankScope(crank: Crank): CrankScope { + let [scope, destroy] = createScope(); + + crank.cleanup(destroy); + + return { + bind(stream: Stream, initial: T): Ref { + let ref: { value: T } = { value: initial }; + scope.run(function* () { + for (let item of yield* each(stream)) { + ref.value = item; + crank.refresh(); + yield* each.next(); + } + }); + return ref; + }, + }; +} diff --git a/inspector/crank/app/live.module.css b/inspector/crank/app/live.module.css new file mode 100644 index 00000000..bdab9617 --- /dev/null +++ b/inspector/crank/app/live.module.css @@ -0,0 +1,11 @@ +.startButton { + font-size: x-large; + color: red; + display: inline-flex; + padding: 0px; + transform: translateY(8px); +} + +.startButton::part(base) { + padding: 0px; +} diff --git a/inspector/crank/app/live.tsx b/inspector/crank/app/live.tsx new file mode 100644 index 00000000..57f68e77 --- /dev/null +++ b/inspector/crank/app/live.tsx @@ -0,0 +1,174 @@ +import type { Context } from "@b9g/crank"; +import { pipe } from "remeda"; + +import { updateNodeMap } from "./data/update-node-map.ts"; +import { stratify } from "./data/stratify.ts"; +import { createSSEClient } from "../../lib/sse-client.ts"; +import { protocol as scope } from "../../scope/protocol.ts"; +import { protocol as player } from "../../player/protocol.ts"; +import { combine } from "../../lib/combine.ts"; +import { StructureInspector } from "./components/structure-inspector.tsx"; +import { createConnection, type ConnectionState } from "./data/connection.ts"; +import { Toolbar } from "./toolbar.tsx"; +import styles from "./live.module.css"; +import { createCrankScope } from "./lib/crank-scope.ts"; + +const protocol = combine.protocols(scope, player); + +const client = createSSEClient(protocol); + +const hierarchies = pipe( + client.methods.watchScopes(), + updateNodeMap({}), + stratify(), +); + +export async function* Live(this: Context): AsyncGenerator { + let scope = createCrankScope(this); + + let connection = scope.bind(createConnection(hierarchies), { + type: "pending", + }); + + let player = scope.bind(client.methods.watchPlayerState(), "paused"); + + for ({} of this) { + let state = connection.value; + let status = ; + switch (state.type) { + case "pending": + yield status; + break; + case "failed": + yield ( + <> + + + + {state.error} + + ); + break; + case "closed": + yield ( + <> + + + + + + ); + break; + case "live": + yield ( + <> + + + + + + + ); + break; + } + } +} + +type PlayerStatus = "playing" | "paused"; + +function PauseControls({ + status, + unpause = () => {}, +}: { status: PlayerStatus; unpause?: () => void }): Element { + unpause(); + return ( + + fetch("/play", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: "[]", + }) + .then((r) => { + if (!r.ok) { + console.error("play request failed", r.status, r.statusText); + } else { + console.log("play request succeeded", r); + } + }) + .catch((err) => console.error("play request failed", err)) + } + disabled={status === "playing"} + > + ); +} + +function Status({ state }: { state: ConnectionState }) { + if (state.type === "live") { + return ( + <> + connection + + live + + + ); + } else if (state.type === "closed") { + if (state.result.ok) { + return ( + <> + connection + + done + + + ); + } else { + let error = state.result.error; + if (error.message === "connection closed") { + return ( + <> + connection + + done + + + ); + } + return ( + <> + connection + + + error + + + + ); + } + } else if (state.type === "failed") { + return ( + <> + connection + + failed + + + ); + } else { + return ( + <> + connection + + connecting + + + ); + } +} diff --git a/inspector/crank/app/recording.tsx b/inspector/crank/app/recording.tsx new file mode 100644 index 00000000..9dda7186 --- /dev/null +++ b/inspector/crank/app/recording.tsx @@ -0,0 +1,66 @@ +import type { Context } from "@b9g/crank"; +import { Layout } from "./layout.tsx"; +import { router } from "../src/router.ts"; + +import { + createScope, + each, + createSignal, + until, + type Operation, +} from "effection"; +import type { NodeMap } from "./data/types.ts"; +import { RenderRecording } from "./components/render-recording.tsx"; + +export async function* Recording(this: Context): AsyncGenerator { + const { state } = router.location; + + let [scope, destroy] = createScope(); + + // signal for incoming files + const files = createSignal(); + let nodeMap: NodeMap[] = []; + // runs on first render if we navigated here with a file in the router state + if (state?.file) { + console.log("Received file from router state:", state.file); + nodeMap = JSON.parse(await state.file.text()) as NodeMap[]; + } + + let refresh = this.refresh.bind(this); + + // process incoming files + scope.run(function* (): Operation { + for (let file of yield* each(files)) { + try { + const text = yield* until(file.text()); + const json: NodeMap[] = JSON.parse(text); + + refresh(() => (nodeMap = json)); + } catch (e) { + console.error("Error processing recording file:", e); + } + } + }); + + // file input handler to support manual upload from the Recording page + // TODO add a file input element to the Recording page UI + const handleFileSelect = (e: Event) => { + const input = e.currentTarget as HTMLInputElement; + const file = input.files?.[0]; + if (file) { + files.send(file); + } + }; + + try { + for ({} of this) { + yield ( + + + + ); + } + } finally { + await destroy(); + } +} diff --git a/inspector/crank/app/toolbar.tsx b/inspector/crank/app/toolbar.tsx new file mode 100644 index 00000000..d8efbdee --- /dev/null +++ b/inspector/crank/app/toolbar.tsx @@ -0,0 +1,7 @@ +import type { Context, Children } from "@b9g/crank"; +import { Portal } from "@b9g/crank"; + +export function Toolbar(this: Context, { children }: { children: Children }) { + let toolbar: Element = this.consume("toolbar"); + return {children}; +} diff --git a/inspector/crank/index.html b/inspector/crank/index.html new file mode 100644 index 00000000..e202a3b4 --- /dev/null +++ b/inspector/crank/index.html @@ -0,0 +1,18 @@ + + + + + + + + Effection Inspector + + + + + diff --git a/inspector/crank/public/effection-logo-dark.svg b/inspector/crank/public/effection-logo-dark.svg new file mode 100644 index 00000000..b280e16b --- /dev/null +++ b/inspector/crank/public/effection-logo-dark.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inspector/crank/public/effection-logo.svg b/inspector/crank/public/effection-logo.svg new file mode 100644 index 00000000..2fb93d1a --- /dev/null +++ b/inspector/crank/public/effection-logo.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inspector/crank/src/main.tsx b/inspector/crank/src/main.tsx new file mode 100644 index 00000000..81a97a96 --- /dev/null +++ b/inspector/crank/src/main.tsx @@ -0,0 +1,6 @@ +import "./shoelace.ts"; +import "../app/global.css"; + +import { renderer } from "@b9g/crank/dom"; +import { App } from "../app/app.tsx"; +renderer.render(, document.body); diff --git a/inspector/crank/src/router.ts b/inspector/crank/src/router.ts new file mode 100644 index 00000000..b847225b --- /dev/null +++ b/inspector/crank/src/router.ts @@ -0,0 +1,14 @@ +import { createBrowserHistory } from "@nano-router/history"; + +const history = createBrowserHistory(); + +import { Routes, Route, Router } from "@nano-router/router"; + +const routes = new Routes( + new Route("home", "/"), + new Route("live", "/live"), + new Route("demo", "/demo"), + new Route("recording", "/recording"), +); + +export const router = new Router({ routes, history }); diff --git a/inspector/crank/src/shoelace.ts b/inspector/crank/src/shoelace.ts new file mode 100644 index 00000000..400938ff --- /dev/null +++ b/inspector/crank/src/shoelace.ts @@ -0,0 +1,14 @@ +import "@shoelace-style/shoelace/dist/themes/light.css"; +import "@shoelace-style/shoelace/dist/themes/dark.css"; +import { setBasePath } from "@shoelace-style/shoelace"; +import "@shoelace-style/shoelace/dist/components/button/button.js"; +import "@shoelace-style/shoelace/dist/components/icon/icon.js"; +import "@shoelace-style/shoelace/dist/components/tree/tree.js"; +import "@shoelace-style/shoelace/dist/components/tree-item/tree-item.js"; +import "@shoelace-style/shoelace/dist/components/split-panel/split-panel.js"; +import "@shoelace-style/shoelace/dist/components/card/card.js"; +import "@shoelace-style/shoelace/dist/components/badge/badge.js"; +import "@shoelace-style/shoelace/dist/components/tooltip/tooltip.js"; + +// Tell Shoelace where to find its assets +setBasePath("shoelace/"); diff --git a/inspector/crank/tsconfig.json b/inspector/crank/tsconfig.json new file mode 100644 index 00000000..3d4ae750 --- /dev/null +++ b/inspector/crank/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "esnext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["esnext", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + "jsx": "react-jsx", + "jsxImportSource": "@b9g/crank", + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src", "app"] +} diff --git a/inspector/crank/vite.config.ts b/inspector/crank/vite.config.ts new file mode 100644 index 00000000..6671d319 --- /dev/null +++ b/inspector/crank/vite.config.ts @@ -0,0 +1,34 @@ +import { defineConfig } from "vite"; +import { viteStaticCopy } from "vite-plugin-static-copy"; +import { join, dirname } from "node:path"; + +const shoelaceIcons = join( + dirname(import.meta.resolve("@shoelace-style/shoelace")), + "assets/icons/*.svg", +).replace(/^file:/, ""); + +export default defineConfig({ + plugins: [ + viteStaticCopy({ + targets: [ + { + src: shoelaceIcons, + dest: "shoelace/assets/icons", + }, + ], + }), + ], + server: { + proxy: { + "/watchScopes": "http://localhost:41000", + "/watchPlayerState": "http://localhost:41000", + "/play": "http://localhost:41000", + }, + }, + build: { + // relative to this config file, not the package root + outDir: "dist", + // Lightning CSS produces a much smaller CSS bundle than the default minifier. + cssMinify: "lightningcss", + }, +}); diff --git a/inspector/examples/example.ts b/inspector/examples/example.ts new file mode 100644 index 00000000..2a07f9f4 --- /dev/null +++ b/inspector/examples/example.ts @@ -0,0 +1,21 @@ +import { main, sleep, spawn, useAttributes, type Task } from "effection"; + +await main(function* () { + let tasks: Task[] = []; + for (let i = 1; i <= 10; i++) { + let task = yield* spawn(function* () { + yield* useAttributes({ name: "child", number: i }); + let delay = Math.random() * 1000; + yield* sleep(delay); + return `${i} is done`; + }); + tasks.push(task); + } + + for (let task of tasks) { + yield* sleep(Math.random() * 200); + yield* task.halt(); + } + + console.log("done"); +}); diff --git a/inspector/implementation.test.ts b/inspector/implementation.test.ts new file mode 100644 index 00000000..79c12cb5 --- /dev/null +++ b/inspector/implementation.test.ts @@ -0,0 +1,53 @@ +import { describe, it } from "@effectionx/bdd"; +import { expect } from "expect"; +import type { Stream } from "effection"; +import { scope } from "arktype"; +import type { Method } from "../lib/types.ts"; + +import { createImplementation, createProtocol } from "../lib/mod.ts"; + +describe("createImplementation()", () => { + it("attach yields a handle with protocol and methods and invoke calls the method", function* () { + type EchoMethod = { echo: Method }; + + const schema = scope({ + NoneArr: "never[]", + None: "never", + Str: "string", + }).export(); + + const protocolMethods: EchoMethod = { + echo: { + args: schema.NoneArr, + progress: schema.None, + returns: schema.Str, + }, + }; + + const protocol = createProtocol(protocolMethods); + + const inspector = createImplementation(protocol, function* () { + return { + *echo(): Stream { + return { + *next() { + return { done: true, value: "hello" }; + }, + }; + }, + }; + }); + + const handle = yield* inspector.attach(); + + // ensure protocol and methods exist + expect(handle.protocol).toBe(protocol); + expect(typeof handle.methods.echo).toBe("function"); + + // invoke the method and read the stream result + const stream = handle.invoke({ name: "echo", args: [] }); + const sub = yield* stream; + const next = yield* sub.next(); + expect(next).toEqual({ done: true, value: "hello" }); + }); +}); diff --git a/inspector/implementation.types.test.ts b/inspector/implementation.types.test.ts new file mode 100644 index 00000000..427f08d5 --- /dev/null +++ b/inspector/implementation.types.test.ts @@ -0,0 +1,29 @@ +import type { Implementation } from "../lib/types.ts"; +import { scope } from "arktype"; +import type { Method } from "../lib/types.ts"; + +// This file is a compile-time (type-level) test to ensure that +// `createImplementation` enforces the method signatures described by the +// protocol (i.e. the `Implementation` type). If the types below do not +// conform, the TypeScript type-check will fail. + +const _schema = scope({ + Args: "string[]", + Obj: { greeting: "string" }, +}).export(); + +type FooMethods = { greet: Method<[string], never, { greeting: string }> }; + +// This implementation must match `Implementation` exactly. If it +// doesn't, the type-check will fail and indicate a problem in the typings. +const _impl: Implementation = function* () { + return { + *greet(name: string) { + return { + *next() { + return { done: true, value: { greeting: `hello ${name}` } }; + }, + }; + }, + }; +}; diff --git a/inspector/lib/attach.ts b/inspector/lib/attach.ts new file mode 100644 index 00000000..bae224f0 --- /dev/null +++ b/inspector/lib/attach.ts @@ -0,0 +1,32 @@ +import { + type Operation, + type Scope, + suspend, + useAttributes, + withResolvers, +} from "effection"; +import type { Methods, Inspector, Handle } from "./types.ts"; + +export function* attach( + scope: Scope, + inspector: Inspector, + init: (handle: Handle) => Operation, +): Operation<() => Operation> { + let attached = withResolvers(); + + let task = scope.run(function* () { + yield* useAttributes({ name: "Inspector" }); + try { + let handle = yield* inspector.attach(scope); + yield* init(handle); + attached.resolve(); + yield* suspend(); + } catch (error) { + attached.reject(error as Error); + } + }); + + yield* attached.operation; + + return task.halt; +} diff --git a/inspector/lib/box.ts b/inspector/lib/box.ts new file mode 100644 index 00000000..d41344da --- /dev/null +++ b/inspector/lib/box.ts @@ -0,0 +1,8 @@ +import type { Result } from "effection"; + +export function unbox(result: Result): T { + if (result.ok) { + return result.value; + } + throw result.error; +} diff --git a/inspector/lib/combine.ts b/inspector/lib/combine.ts new file mode 100644 index 00000000..41893056 --- /dev/null +++ b/inspector/lib/combine.ts @@ -0,0 +1,66 @@ +import type { Operation, Scope } from "effection"; +import type { Handle, Inspector, Methods, Protocol } from "./types.ts"; + +export interface Combine { + protocols(...protocols: [Protocol]): Protocol; + protocols( + ...protocols: [Protocol, Protocol] + ): Protocol; + protocols( + ...protocols: [Protocol, Protocol, Protocol] + ): Protocol; + protocols< + A extends Methods, + B extends Methods, + C extends Methods, + D extends Methods, + >( + ...protocols: [Protocol, Protocol, Protocol, Protocol] + ): Protocol; + + inspectors(...inspectors: [Inspector]): Inspector; + inspectors( + ...inspectors: [Inspector, Inspector] + ): Inspector; + inspectors( + ...inspectors: [Inspector, Inspector, Inspector] + ): Inspector; + inspectors< + A extends Methods, + B extends Methods, + C extends Methods, + D extends Methods, + >( + ...inspectors: [Inspector, Inspector, Inspector, Inspector] + ): Inspector; +} + +export const combine: Combine = { + protocols: (...protocols: Protocol[]) => { + return protocols.reduce( + (acc, protocol) => { + Object.assign(acc.methods, protocol.methods); + return acc; + }, + { methods: {} } as Protocol, + ); + }, + inspectors: (...inspectors: Inspector[]) => { + return inspectors.reduce( + (acc: Inspector, inspector: Inspector) => { + let protocol = combine.protocols(acc.protocol, inspector.protocol); + let attach = function* (scope: Scope): Operation> { + let a = yield* acc.attach(scope); + let b = yield* inspector.attach(scope); + let methods = Object.assign({}, a.methods, b.methods); + return { + protocol, + methods, + invoke: ({ name, args }) => methods[name](...args), + }; + }; + return { protocol, attach }; + }, + ); + }, +}; diff --git a/inspector/lib/impl.ts b/inspector/lib/impl.ts new file mode 100644 index 00000000..8160d810 --- /dev/null +++ b/inspector/lib/impl.ts @@ -0,0 +1,26 @@ +import { lift, type Operation, type Stream } from "effection"; + +export function fn( + fn: (...args: TArgs) => TReturn, +): (...args: TArgs) => Stream { + return lift((...args) => ({ + *next() { + return { done: true, value: fn(...args) }; + }, + })); +} + +export function op( + fn: (...args: TArgs) => Operation, +): ( + ...args: TArgs +) => Stream { + return lift((...args) => ({ + *next() { + return { + done: true, + value: yield* fn(...args), + } as IteratorReturnResult; + }, + })); +} diff --git a/inspector/lib/implementation.ts b/inspector/lib/implementation.ts new file mode 100644 index 00000000..e3f586b7 --- /dev/null +++ b/inspector/lib/implementation.ts @@ -0,0 +1,25 @@ +import type { Operation, Scope } from "effection"; +import type { + Handle, + Implementation, + Inspector, + Methods, + Protocol, +} from "./types.ts"; + +export function createImplementation( + protocol: Protocol, + create: Implementation, +): Inspector { + return { + protocol, + *attach(scope: Scope): Operation> { + let methods = yield* create(scope); + return { + protocol, + methods, + invoke: ({ name, args }) => methods[name](...args), + }; + }, + }; +} diff --git a/inspector/lib/labels.ts b/inspector/lib/labels.ts new file mode 100644 index 00000000..d2c018ea --- /dev/null +++ b/inspector/lib/labels.ts @@ -0,0 +1,21 @@ +import { + createContext, + type Scope, + useScope, + type Operation, + type Attributes, +} from "effection"; + +export const AttributesContext = createContext( + "@effection/attributes", + { + name: "anonymous", + }, +); + +export function getLabels(scope: Scope) { + if (scope.hasOwn(AttributesContext)) { + return scope.expect(AttributesContext); + } + return AttributesContext.defaultValue!; +} diff --git a/inspector/lib/mod.ts b/inspector/lib/mod.ts new file mode 100644 index 00000000..ceb49dc4 --- /dev/null +++ b/inspector/lib/mod.ts @@ -0,0 +1,5 @@ +export * from "./types.ts"; +export * from "./protocol.ts"; +export * from "./implementation.ts"; +export * from "./combine.ts"; +export * from "./reader.ts"; diff --git a/inspector/lib/protocol.ts b/inspector/lib/protocol.ts new file mode 100644 index 00000000..56d01852 --- /dev/null +++ b/inspector/lib/protocol.ts @@ -0,0 +1,9 @@ +import type { Method, Protocol } from "./types.ts"; + +export function createProtocol< + M extends Record>, +>(methods: M): Protocol { + return { + methods, + }; +} diff --git a/inspector/lib/reader.ts b/inspector/lib/reader.ts new file mode 100644 index 00000000..f892f532 --- /dev/null +++ b/inspector/lib/reader.ts @@ -0,0 +1,7 @@ +export function toJson(value: unknown) { + try { + return JSON.parse(JSON.stringify(value)); + } catch (_error) { + return String(value); + } +} diff --git a/inspector/lib/reduce.ts b/inspector/lib/reduce.ts new file mode 100644 index 00000000..c2bba1e8 --- /dev/null +++ b/inspector/lib/reduce.ts @@ -0,0 +1,47 @@ +import type { Operation, Stream } from "effection"; + +/** + * Transforms a stream by taking each item and applying it to an + * accumulated value to produce a new accumulated value which is then + * passed downstream. + * + * @example + * ```ts + * import { reduce, streamOf } from "@effectionx/stream-helpers"; + * + * const sum = reduce(function*(total: number, item: number) { + * return sum + number; + * }, 0); + * + * sum(streamOf([1,2,3])) //=> yields 1, 3, 6 + * ``` + * + * @param fn - The operation to apply a single item to the accumulated value + * @param initial - The first accumulated value from which all others will descend + * @returns A stream transformer that applies the reduction over the lifetime of the stream + */ +export function reduce( + fn: (current: TSum, item: T) => Operation, + initial: TSum, +): (stream: Stream) => Stream { + return (upstream) => ({ + *[Symbol.iterator]() { + let current = initial; + let subscription = yield* upstream; + + return { + *next() { + let next = yield* subscription.next(); + if (next.done) { + return next; + } + let reduction = yield* fn(current, next.value); + + current = reduction; + + return { done: false, value: current } as const; + }, + }; + }, + }); +} diff --git a/inspector/lib/sse-client.ts b/inspector/lib/sse-client.ts new file mode 100644 index 00000000..eebcaa9a --- /dev/null +++ b/inspector/lib/sse-client.ts @@ -0,0 +1,123 @@ +import { + resource, + stream, + until, + useAbortSignal, + useAttributes, +} from "effection"; +import { + toJson, + type Handle, + type InvocationArgs, + type InvocationResult, + type Methods, + type Protocol, +} from "../mod.ts"; +import { validateUnsafe } from "../lib/validate.ts"; +import { parseServerSentEvents } from "parse-sse"; + +export interface SSEClientOptions { + url?: string; +} + +/** + * Implement a protocol by calling it over SSE. if the protocl has a method `.foo()`, it + * will use the SSE stream at `/foo` + * + * The arguments of the protocl are validated before they are sent, and the returned values are + * validated on the way back. + * + * @param protocol - the protocol to implement + * @returns a handle to a protocol implementation that will invoke its methods over the wire. + */ +export function createSSEClient( + protocol: Protocol, + options: SSEClientOptions = {}, +): Handle { + let handle: Handle = { + protocol, + invoke({ + name, + args, + }: InvocationArgs): InvocationResult { + let methodName = String(name); + + // validate the arguments against the protocol + validateUnsafe( + protocol.methods[name].args, + args, + `arguments ${methodName}()`, + ); + + return resource(function* (provide) { + yield* useAttributes({ name: `inspector.${methodName}()` }); + let signal = yield* useAbortSignal(); + + let pathname = `/${methodName}`; + + let url = options.url ? new URL(pathname, options.url) : pathname; + + let response = yield* until( + fetch(url, { + signal, + method: "POST", + headers: { + Accept: "text/event-stream", + }, + body: JSON.stringify(toJson(args)), + }), + ); + + if (!response.ok) { + throw new Error(`${response.status} ${response.statusText}`); + } + + let events = stream(parseServerSentEvents(response)); + + let subscription = yield* events; + + yield* provide({ + *next() { + let next = yield* subscription.next(); + if (next.done) { + throw new Error("connection closed"); + } + + let { type, data } = next.value; + let parsed = JSON.parse(data); + if (type === "yield") { + return { + done: false, + value: validateUnsafe( + protocol.methods[name].progress, + parsed, + `progress ${methodName}()`, + ), + }; + } else if (type === "return") { + return { + done: true, + value: validateUnsafe( + protocol.methods[methodName].returns, + parsed, + ), + }; + } else if (type === "throw") { + throw parsed; + } else { + throw new TypeError(`unrecognized event type: '${type}'`); + } + }, + }); + }); + }, + methods: Object.fromEntries( + Object.keys(protocol.methods).map((name) => [ + name, + (...args) => handle.invoke({ name, args }), + ]), + ) as Handle["methods"], + }; + + return handle; +} diff --git a/inspector/lib/sse-server.ts b/inspector/lib/sse-server.ts new file mode 100644 index 00000000..e6d6c486 --- /dev/null +++ b/inspector/lib/sse-server.ts @@ -0,0 +1,152 @@ +import { + once, + type Operation, + resource, + scoped, + spawn, + type Task, + until, + useAttributes, + useScope, +} from "effection"; +import type { Handle, Methods } from "./types.ts"; +import { validateUnsafe } from "./validate.ts"; + +import { + createEventStream, + defineEventHandler, + H3, + serve, + serveStatic, +} from "h3"; +import { readFile, stat } from "node:fs/promises"; +import { join } from "node:path"; + +export interface SSEServerOptions { + port: number; +} + +export function useSSEServer( + handle: Handle, + options: SSEServerOptions, +): Operation { + let { port } = options; + let { protocol } = handle; + let methodNames = Object.keys(protocol.methods) as Array; + + return resource(function* (provide) { + yield* useAttributes({ name: "SSEServer", port }); + let scope = yield* useScope(); + + let app = new H3(); + + let inflight = new Set>(); + + for (let name of methodNames) { + app.all(`/${String(name)}`, async (event) => { + let { req } = event; + let stream = createEventStream(event); + + let task = scope.run(function* () { + yield* useAttributes({ + name: "RequestHandler", + method: req.method, + pathname: event.url.pathname, + }); + try { + yield* spawn(() => + scoped(function* () { + yield* useAttributes({ name: "EventStream" }); + let post = req.method.toUpperCase() === "POST"; + let body: unknown = post ? yield* until(req.json()) : []; + let args = validateUnsafe(protocol.methods[name].args, body); + let subscription = yield* handle.invoke({ name, args }); + let next = yield* subscription.next(); + while (!next.done) { + yield* until( + stream.push({ + event: "yield", + data: JSON.stringify(next.value), + }), + ); + next = yield* subscription.next(); + } + let value = validateUnsafe( + protocol.methods[name].returns, + next.value, + ); + yield* until( + stream.push({ event: "return", data: JSON.stringify(value) }), + ); + }), + ); + yield* once(req.signal, "abort"); + } catch (cause) { + let error = + cause instanceof Error ? cause : new Error("unknown", { cause }); + let { name, message } = error; + yield* until( + stream.push({ + event: "throw", + data: JSON.stringify({ name, message }), + }), + ); + } finally { + inflight.delete(task); + yield* until(stream.close()); + } + }); + inflight.add(task); + + return await stream.send(); + }); + } + + const ROOT_DIR = join(import.meta.dirname, ".."); + const PUBLIC_DIR = join( + ...(ROOT_DIR === "dist" + ? [ROOT_DIR, "..", "crank", "dist"] + : [ROOT_DIR, "crank", "dist"]), + ); + + const frontendRoutes = ["/live", "/recording", "/demo"]; + // handle static assets from the crank dist directory (js, css, etc.) + app.use( + defineEventHandler(async (event) => { + return await serveStatic(event, { + getContents: (id) => { + const filename = frontendRoutes.includes(id) ? "index.html" : id; + return readFile(join(PUBLIC_DIR, filename)); + }, + getMeta: async (id) => { + const filename = frontendRoutes.includes(id) ? "index.html" : id; + const stats = await stat(join(PUBLIC_DIR, filename)).catch( + () => null, + ); + if (!stats || !stats.isFile()) return; + return { size: stats.size, mtime: stats.mtime }; + }, + fallthrough: true, + }); + }), + ); + + let server = serve(app, { + port, + silent: true, + }); + + yield* until(server.ready()); + + try { + yield* provide(`http://localhost:${port}`); + } finally { + while (inflight.size > 0) { + for (let task of inflight) { + yield* task.halt(); + } + } + yield* until(server.close()); + } + }); +} diff --git a/inspector/lib/types.ts b/inspector/lib/types.ts new file mode 100644 index 00000000..c54d4aab --- /dev/null +++ b/inspector/lib/types.ts @@ -0,0 +1,41 @@ +import type { Operation, Scope, Stream, Yielded } from "effection"; +import type { StandardSchemaV1 } from "@standard-schema/spec"; + +export interface Method { + args: StandardSchemaV1; + progress: StandardSchemaV1; + returns: StandardSchemaV1; +} + +export type Methods = Record>; + +export interface InvocationArgs { + name: N; + args: StandardSchemaV1.InferInput; +} + +export type InvocationResult = Stream< + StandardSchemaV1.InferInput, + StandardSchemaV1.InferInput +>; + +export interface Protocol { + methods: M; +} + +export type Implementation = (scope: Scope) => Operation<{ + [N in keyof M]: ( + ...args: InvocationArgs["args"] + ) => InvocationResult; +}>; + +export type Handle = { + protocol: Protocol; + invoke(args: InvocationArgs): InvocationResult; + methods: Yielded>>; +}; + +export interface Inspector { + protocol: Protocol; + attach(scope: Scope): Operation>; +} diff --git a/inspector/lib/validate.ts b/inspector/lib/validate.ts new file mode 100644 index 00000000..9d8baf54 --- /dev/null +++ b/inspector/lib/validate.ts @@ -0,0 +1,30 @@ +import type { StandardSchemaV1 } from "@standard-schema/spec"; +import { Err, Ok, type Result } from "effection"; +import { unbox } from "./box.ts"; + +export function validateUnsafe( + schema: StandardSchemaV1, + value: unknown, + description?: string, +): StandardSchemaV1.InferInput> { + return unbox(validate(schema, value, description)); +} + +export function validate( + schema: StandardSchemaV1, + value: unknown, + description?: string, +): Result>> { + let validation = schema["~standard"].validate(value); + if (validation instanceof Promise) { + return Err( + new TypeError("invalid protocol: async validations are not allowed"), + ); + } + if (validation.issues) { + let issues = validation.issues.join("\n"); + let message = description ? `${description} ${issues}` : issues; + return Err(new TypeError(message, { cause: value })); + } + return Ok(validation.value); +} diff --git a/inspector/loader.ts b/inspector/loader.ts new file mode 100644 index 00000000..b662dffa --- /dev/null +++ b/inspector/loader.ts @@ -0,0 +1,38 @@ +import { global, useAttributes } from "effection"; +import { api } from "effection/experimental"; +import { combine } from "./mod.ts"; +import { scope } from "./scope/implementation.ts"; +import { player } from "./player/implementation.ts"; +import { attach } from "./lib/attach.ts"; +import { useSSEServer } from "./lib/sse-server.ts"; +import { pause } from "./player/implementation.ts"; +import packageJSON from "./package.json" with { type: "json" }; + +const inspector = combine.inspectors(scope, player); + +global.around(api.Main, { + main([body], next) { + return next(function* (args) { + yield* useAttributes({ name: "Main", args: args.join(" ") }); + + let detach = yield* attach(global, inspector, function* (handle) { + let address = yield* useSSEServer(handle, { port: 41000 }); + + let { version } = packageJSON; + console.log( + `effection inspector@${version} running at ${address}/live`, + ); + }); + + try { + if (args.includes("--suspend")) { + yield* pause(); + } + + yield* body(args); + } finally { + yield* detach(); + } + }); + }, +}); diff --git a/inspector/mod.ts b/inspector/mod.ts new file mode 100644 index 00000000..945209dd --- /dev/null +++ b/inspector/mod.ts @@ -0,0 +1 @@ +export * from "./lib/mod.ts"; diff --git a/inspector/package.json b/inspector/package.json new file mode 100644 index 00000000..7a2c2d26 --- /dev/null +++ b/inspector/package.json @@ -0,0 +1,62 @@ +{ + "name": "@effectionx/inspector", + "version": "0.0.1", + "type": "module", + "license": "MIT", + "author": "engineering@frontside.com", + "repository": { + "type": "git", + "url": "git+https://github.com/thefrontside/effectionx.git" + }, + "bugs": { + "url": "https://github.com/thefrontside/effectionx/issues" + }, + "engines": { + "node": ">= 22" + }, + "sideEffects": true, + "files": ["dist", "crank/dist"], + "scripts": { + "start": "vite --host 0.0.0.0 crank", + "build:bundle": "vite build crank" + }, + "peerDependencies": { + "effection": "^4.1.0-alpha.3" + }, + "dependencies": { + "@ark/util": "^0.56.0", + "@b9g/crank": "^0.7.5", + "@effectionx/stream-helpers": "workspace:*", + "@standard-schema/spec": "^1.0.0", + "arktype": "^2.1.27", + "canvg": "^4.0.3", + "d3": "^7.9.0", + "h3": "2.0.1-rc.14", + "remeda": "^2", + "zod": "^4.1.13" + }, + "devDependencies": { + "@effectionx/bdd": "workspace:*", + "@nano-router/history": "^4.0.4", + "@nano-router/router": "^4.0.4", + "@shoelace-style/shoelace": "^2.20.1", + "@types/d3": "^7.4.3", + "d3": "^7.9.0", + "effection": "4.1.0-alpha.3", + "lightningcss": "^1.31.1", + "parse-sse": "^0.1.0", + "vite": "^7.3.1", + "vite-plugin-static-copy": "^3.2.0" + }, + "exports": { + ".": { + "development": "./loader.ts", + "default": "./dist/loader.js" + }, + "./lib": { + "development": "./mod.ts", + "default": "./dist/mod.js" + }, + "./package.json": "./package.json" + } +} diff --git a/inspector/player/implementation.ts b/inspector/player/implementation.ts new file mode 100644 index 00000000..0a4f1e41 --- /dev/null +++ b/inspector/player/implementation.ts @@ -0,0 +1,82 @@ +import { + createChannel, + createContext, + lift, + resource, + type Subscription, + withResolvers, + type Operation, +} from "effection"; +import { createImplementation } from "../lib/implementation.ts"; +import { protocol } from "./protocol.ts"; +import { op } from "../lib/impl.ts"; + +export type PlayerStatus = "playing" | "paused"; + +export type PlayerContext = + | { + status: "playing"; + } + | { + status: "paused"; + resume: () => Operation; + }; + +const PlayerContext = createContext<{ ref: PlayerContext }>( + "@effectionx/inspector.player", +); + +const state = createChannel(); + +export const player = createImplementation(protocol, function* (root) { + root.set(PlayerContext, { ref: { status: "playing" } }); + return { + play: op(function* () { + let cxt = yield* getContext(); + if (cxt && cxt.status === "paused") { + yield* setContext({ status: "playing" }); + yield* cxt.resume(); + } + }), + + watchPlayerState: () => + resource(function* (provide) { + let context = yield* getContext(); + let current: IteratorYieldResult = { + done: false, + value: context ? context.status : "playing", + }; + let states = yield* state; + let subscription: Subscription = { + *next() { + subscription.next = states.next; + return current; + }, + }; + yield* provide(subscription); + }), + }; +}); + +export function* pause() { + let resumed = withResolvers(); + yield* setContext({ + status: "paused", + resume: lift(resumed.resolve), + }); + + yield* resumed.operation; +} + +function* setContext(value: PlayerContext): Operation { + let context = yield* PlayerContext.expect(); + + context.ref = value; + + yield* state.send(value.status); +} + +function* getContext(): Operation { + let context = yield* PlayerContext.expect(); + return context.ref; +} diff --git a/inspector/player/mod.ts b/inspector/player/mod.ts new file mode 100644 index 00000000..e69de29b diff --git a/inspector/player/protocol.ts b/inspector/player/protocol.ts new file mode 100644 index 00000000..6476d09d --- /dev/null +++ b/inspector/player/protocol.ts @@ -0,0 +1,15 @@ +import { type } from "arktype"; +import { createProtocol } from "../lib/protocol.ts"; + +export const protocol = createProtocol({ + watchPlayerState: { + args: type("never[]"), + progress: type("'playing' | 'paused'"), + returns: type("never"), + }, + play: { + args: type("never[]"), + progress: type("never"), + returns: type("undefined"), + }, +}); diff --git a/inspector/protocol.test.ts b/inspector/protocol.test.ts new file mode 100644 index 00000000..b32d1445 --- /dev/null +++ b/inspector/protocol.test.ts @@ -0,0 +1,19 @@ +import { describe, it } from "@effectionx/bdd"; +import { expect } from "expect"; +import type { Methods } from "../lib/types.ts"; +import { scope } from "arktype"; + +import { createProtocol } from "../lib/mod.ts"; + +describe("createProtocol()", () => { + it("returns a protocol object containing the provided methods", function* () { + const schema = scope({ None: "never[]" }).export(); + + const methods: Methods = { + foo: { args: schema.None, progress: schema.None, returns: schema.None }, + }; + const protocol = createProtocol(methods); + + expect(protocol.methods).toBe(methods); + }); +}); diff --git a/inspector/scope/implementation.ts b/inspector/scope/implementation.ts new file mode 100644 index 00000000..8e0466c8 --- /dev/null +++ b/inspector/scope/implementation.ts @@ -0,0 +1,138 @@ +import type { Inspector } from "../lib/mod.ts"; +import { createImplementation, toJson } from "../lib/mod.ts"; +import { op } from "../lib/impl.ts"; +import { createContext, createSignal, type Scope } from "effection"; +import { api } from "effection/experimental"; +import { + protocol, + type ScopeNode, + type ScopeEvent, + type ScopeTree, +} from "./protocol.ts"; +import { pipe } from "remeda"; +import { createSubject } from "@effectionx/stream-helpers"; +import { AttributesContext, getLabels } from "../lib/labels.ts"; + +const Id = createContext("@effectionx/inspector.id", "global"); +const Children = createContext>( + "@effection/scope.children", + new Set(), +); + +export const scope = createImplementation(protocol, function* (root) { + let ids = 0; + let { send, ...stream } = createSignal(); + + root.set(AttributesContext, { name: "Global" }); + + // give every node an id that does not have it. + visit( + root, + (_, { scope }) => { + scope.set(Id, String(ids++)); + }, + null, + ); + + root.around(api.Scope, { + create([parent], next) { + let parentId = parent.expect(Id); + let [scope, destroy] = next(parent); + + let id = scope.set(Id, String(ids++)); + + send({ + type: "created", + id, + parentId, + }); + return [scope, destroy]; + }, + *destroy([scope], next) { + let id = scope.expect(Id); + send({ type: "destroying", id }); + try { + yield* next(scope); + send({ + type: "destroyed", + id, + result: { ok: true }, + }); + } catch (error) { + let { name, message, stack } = error as Error; + send({ + type: "destroyed", + id, + result: { ok: false, error: { name, message, stack } }, + }); + throw error; + } + }, + + set([scope, context, value], next) { + if (context.name === AttributesContext.name) { + send({ + type: "set", + id: scope.expect(Id), + contextName: context.name, + contextValue: toJson(value), + }); + } + return next(scope, context, value); + }, + }); + + return { + watchScopes: () => + pipe( + stream, + createSubject({ type: "tree", value: readTree(root) }), + ), + getScopes: op(function* () { + return readTree(root); + }), + }; +}) as Inspector; + +function readTree(root: Scope): ScopeTree { + return visit( + root, + (nodes, { scope, parentId }) => { + nodes.push({ + id: scope.expect(Id), + parentId, + data: { [AttributesContext.name]: getLabels(scope) }, + }); + }, + [] as ScopeNode[], + ); +} + +function visit( + scope: Scope, + visitor: (current: T, node: { parentId?: string; scope: Scope }) => void, + initial: T, +): T { + let sum = initial; + let visit: Array<{ + parentId?: string; + scope: Scope; + }> = [{ scope }]; + + let current = visit.pop(); + while (current) { + let id = current.scope.expect(Id); + let result = visitor(sum, { + scope: current.scope, + parentId: current.parentId, + }); + if (result != null) { + sum = result; + } + + let children = current.scope.expect(Children); + visit.push(...[...children].map((scope) => ({ scope, parentId: id }))); + current = visit.pop(); + } + return sum; +} diff --git a/inspector/scope/mod.ts b/inspector/scope/mod.ts new file mode 100644 index 00000000..c3fef7db --- /dev/null +++ b/inspector/scope/mod.ts @@ -0,0 +1,2 @@ +export * from "./implementation.ts"; +export * from "./protocol.ts"; diff --git a/inspector/scope/protocol.ts b/inspector/scope/protocol.ts new file mode 100644 index 00000000..054cfd1e --- /dev/null +++ b/inspector/scope/protocol.ts @@ -0,0 +1,81 @@ +import { scope } from "arktype"; +import { createProtocol } from "../lib/mod.ts"; + +const $ = scope({ + ScopeNode: { + id: "string", + "parentId?": "string", + data: "Record", + }, + ScopeTree: "ScopeNode[]", + Error: { + name: "string", + message: "string", + stack: "string?", + }, + Result: () => + $.type.or( + { + ok: "true", + }, + { + ok: "false", + error: "Error", + }, + ), + ScopeEvent: () => + $.type.or( + { + type: "'tree'", + value: "ScopeTree", + }, + { + type: "'created'", + id: "string", + parentId: "string", + }, + { + type: "'destroying'", + id: "string", + }, + { + type: "'destroyed'", + id: "string", + result: "Result", + }, + { + type: "'set'", + id: "string", + contextName: "string", + contextValue: "object.json", + }, + { + type: "'delete'", + id: "string", + contextName: "string", + didHave: "boolean", + }, + ), + Never: "never", + None: "never[]", + Undef: "undefined", +}); + +const schema = $.export(); + +export type ScopeEvent = typeof schema.ScopeEvent.infer; +export type ScopeNode = typeof schema.ScopeNode.infer; +export type ScopeTree = typeof schema.ScopeTree.infer; + +export const protocol = createProtocol({ + watchScopes: { + args: schema.None, + progress: schema.ScopeEvent, + returns: schema.Undef, + }, + getScopes: { + args: schema.None, + progress: schema.Never, + returns: schema.ScopeTree, + }, +}); diff --git a/inspector/tsconfig.json b/inspector/tsconfig.json new file mode 100644 index 00000000..4e82d08a --- /dev/null +++ b/inspector/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "jsx": "react-jsx" + }, + "include": ["**/*.ts", "package.json"], + "exclude": [ + "crank", + "*.config.ts", + "**/*.test.ts", + "dist", + "example.ts", + "pipeline-test.ts" + ], + "references": [ + { + "path": "../bdd" + } + ] +} diff --git a/package.json b/package.json index 69f5361e..e832db39 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,9 @@ "peerDependencyRules": { "ignoreMissing": [], "allowAny": [] + }, + "overrides": { + "effection": "4.1.0-alpha.3" } }, "volta": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6626d311..9400d1d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + effection: 4.1.0-alpha.3 + importers: .: @@ -18,8 +21,8 @@ importers: specifier: ^7 version: 7.7.1 effection: - specifier: ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 expect: specifier: ^29 version: 29.7.0 @@ -48,8 +51,8 @@ importers: specifier: workspace:* version: link:../tinyexec effection: - specifier: ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 generatorics: specifier: ^1 version: 1.1.0 @@ -69,14 +72,14 @@ importers: specifier: workspace:* version: link:../test-adapter effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 chain: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -85,8 +88,8 @@ importers: context-api: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -98,8 +101,8 @@ importers: specifier: workspace:* version: link:../timebox effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -108,21 +111,21 @@ importers: effect-ts: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* version: link:../bdd effect: specifier: ^3 - version: 3.19.14 + version: 3.19.15 fs: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -131,18 +134,82 @@ importers: fx: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* version: link:../bdd + inspector: + dependencies: + '@ark/util': + specifier: ^0.56.0 + version: 0.56.0 + '@b9g/crank': + specifier: ^0.7.5 + version: 0.7.5 + '@effectionx/stream-helpers': + specifier: workspace:* + version: link:../stream-helpers + '@standard-schema/spec': + specifier: ^1.0.0 + version: 1.1.0 + arktype: + specifier: ^2.1.27 + version: 2.1.29 + canvg: + specifier: ^4.0.3 + version: 4.0.3 + d3: + specifier: ^7.9.0 + version: 7.9.0 + h3: + specifier: 2.0.1-rc.14 + version: 2.0.1-rc.14 + remeda: + specifier: ^2 + version: 2.33.4 + zod: + specifier: ^4.1.13 + version: 4.3.5 + devDependencies: + '@effectionx/bdd': + specifier: workspace:* + version: link:../bdd + '@nano-router/history': + specifier: ^4.0.4 + version: 4.0.4 + '@nano-router/router': + specifier: ^4.0.4 + version: 4.0.4 + '@shoelace-style/shoelace': + specifier: ^2.20.1 + version: 2.20.1(@floating-ui/utils@0.2.10)(@types/react@19.2.8) + '@types/d3': + specifier: ^7.4.3 + version: 7.4.3 + effection: + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 + lightningcss: + specifier: ^1.31.1 + version: 1.31.1 + parse-sse: + specifier: ^0.1.0 + version: 0.1.0 + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2) + vite-plugin-static-copy: + specifier: ^3.2.0 + version: 3.2.0(vite@7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2)) + jsonl-store: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -151,8 +218,8 @@ importers: node: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -170,8 +237,8 @@ importers: specifier: ^2 version: 2.2.0 effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 shellwords-ts: specifier: ^3.0.1 version: 3.0.1 @@ -189,8 +256,8 @@ importers: raf: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -202,8 +269,8 @@ importers: scope-eval: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -212,8 +279,8 @@ importers: signals: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 immutable: specifier: ^5 version: 5.1.4 @@ -231,8 +298,8 @@ importers: specifier: workspace:* version: link:../timebox effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 immutable: specifier: ^5 version: 5.1.4 @@ -247,8 +314,8 @@ importers: stream-yaml: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 yaml: specifier: ^2 version: 2.8.2 @@ -263,8 +330,8 @@ importers: task-buffer: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -279,14 +346,14 @@ importers: test-adapter: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 timebox: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -295,8 +362,8 @@ importers: tinyexec: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 tinyexec: specifier: ^0.3.2 version: 0.3.2 @@ -307,8 +374,8 @@ importers: specifier: workspace:* version: link:../test-adapter effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -318,7 +385,7 @@ importers: version: link:../process vitest: specifier: ^3 - version: 3.2.4(@types/node@22.19.7)(yaml@2.8.2) + version: 3.2.4(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2) watch: dependencies: @@ -332,8 +399,8 @@ importers: specifier: ^4 version: 4.0.3 effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 ignore: specifier: ^7 version: 7.0.5 @@ -360,8 +427,8 @@ importers: websocket: dependencies: effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 devDependencies: '@effectionx/bdd': specifier: workspace:* @@ -379,8 +446,8 @@ importers: specifier: workspace:* version: link:../signals effection: - specifier: ^3 || ^4 - version: 4.0.0 + specifier: 4.1.0-alpha.3 + version: 4.1.0-alpha.3 web-worker: specifier: ^1 version: 1.5.0 @@ -394,6 +461,15 @@ importers: packages: + '@ark/schema@0.56.0': + resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} + + '@ark/util@0.56.0': + resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==} + + '@b9g/crank@0.7.5': + resolution: {integrity: sha512-tG82HhWizXZWVS2XZAElQ7/h31BrDoLh1N92M2JB8AOojc4xSHjZB2883ej9K7tbC3OnfA5dMp9IulJG1nrnBQ==} + '@babel/code-frame@7.28.6': resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} @@ -455,6 +531,10 @@ packages: cpu: [x64] os: [win32] + '@ctrl/tinycolor@4.2.0': + resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} + engines: {node: '>=14'} + '@esbuild/aix-ppc64@0.27.2': resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} @@ -614,6 +694,15 @@ packages: '@essentials/raf@1.2.0': resolution: {integrity: sha512-AWJvpprE2o7ATMb7HBYMVUVmPJBCt2wZp2rY7d+rAcNSMvzLbDepy9KFeqqrPZh+s9aIpbw1LgmuAW7kuRFgrQ==} + '@floating-ui/core@1.7.4': + resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} + + '@floating-ui/dom@1.7.5': + resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@jest/expect-utils@29.7.0': resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -629,131 +718,172 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@rollup/rollup-android-arm-eabi@4.55.1': - resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} + '@lit-labs/ssr-dom-shim@1.5.1': + resolution: {integrity: sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==} + + '@lit/react@1.0.8': + resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==} + peerDependencies: + '@types/react': 17 || 18 || 19 + + '@lit/reactive-element@2.1.2': + resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} + + '@nano-router/history@4.0.4': + resolution: {integrity: sha512-/g8U0MNNOiD3uflNjxLpnAObd/a+C0sMcQ6x0d5S3rQ58umGc/stOB1rta8tvmGPkIUqhFG6lfADT7jaHJgMmw==} + engines: {node: '>=16'} + + '@nano-router/path@4.0.4': + resolution: {integrity: sha512-Ajgcw5ayItidN6h/MC0re3fqkYscrBQHlco7+1FCIxw65Nqs/58+Wdeb1G/L1g3+LOTc4U6w/8FpFaVM++pr/g==} + engines: {node: '>=16'} + + '@nano-router/router@4.0.4': + resolution: {integrity: sha512-o0DXM4WU8Cyy8RmwRi4V/lgZ5JNOnU75l0Z/OxRGMrVep/3RB4OrM4NyWjEUDJ8zpKm8hiyO9za6Jr+Q9sQPOg==} + engines: {node: '>=16'} + + '@nano-router/routes@4.0.4': + resolution: {integrity: sha512-OKKhFW5WLwnVEARgdzUZ2xzrH67fS7QcYan3bnVzO1edp5NxjYznVZAb1kXRy6MtukbyRDdpinkeB0IGxEKstA==} + engines: {node: '>=16'} + + '@nano-router/url@4.0.4': + resolution: {integrity: sha512-VAfvEfzZYWr7kRDSxz5VaqaEmagK7jhuDOveC9okO6XXiPtXv8guR00UPoUpXCeI1K1thlc7CALE/dug4n6qZA==} + engines: {node: '>=16'} + + '@rollup/rollup-android-arm-eabi@4.55.2': + resolution: {integrity: sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.55.1': - resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} + '@rollup/rollup-android-arm64@4.55.2': + resolution: {integrity: sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.55.1': - resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} + '@rollup/rollup-darwin-arm64@4.55.2': + resolution: {integrity: sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.55.1': - resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} + '@rollup/rollup-darwin-x64@4.55.2': + resolution: {integrity: sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.55.1': - resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} + '@rollup/rollup-freebsd-arm64@4.55.2': + resolution: {integrity: sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.55.1': - resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} + '@rollup/rollup-freebsd-x64@4.55.2': + resolution: {integrity: sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.55.1': - resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.55.2': + resolution: {integrity: sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.55.1': - resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} + '@rollup/rollup-linux-arm-musleabihf@4.55.2': + resolution: {integrity: sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.55.1': - resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} + '@rollup/rollup-linux-arm64-gnu@4.55.2': + resolution: {integrity: sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.55.1': - resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} + '@rollup/rollup-linux-arm64-musl@4.55.2': + resolution: {integrity: sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.55.1': - resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} + '@rollup/rollup-linux-loong64-gnu@4.55.2': + resolution: {integrity: sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loong64-musl@4.55.1': - resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + '@rollup/rollup-linux-loong64-musl@4.55.2': + resolution: {integrity: sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.55.1': - resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} + '@rollup/rollup-linux-ppc64-gnu@4.55.2': + resolution: {integrity: sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-ppc64-musl@4.55.1': - resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + '@rollup/rollup-linux-ppc64-musl@4.55.2': + resolution: {integrity: sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.55.1': - resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} + '@rollup/rollup-linux-riscv64-gnu@4.55.2': + resolution: {integrity: sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.55.1': - resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} + '@rollup/rollup-linux-riscv64-musl@4.55.2': + resolution: {integrity: sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.55.1': - resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} + '@rollup/rollup-linux-s390x-gnu@4.55.2': + resolution: {integrity: sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.55.1': - resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} + '@rollup/rollup-linux-x64-gnu@4.55.2': + resolution: {integrity: sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.55.1': - resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} + '@rollup/rollup-linux-x64-musl@4.55.2': + resolution: {integrity: sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==} cpu: [x64] os: [linux] - '@rollup/rollup-openbsd-x64@4.55.1': - resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + '@rollup/rollup-openbsd-x64@4.55.2': + resolution: {integrity: sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.55.1': - resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} + '@rollup/rollup-openharmony-arm64@4.55.2': + resolution: {integrity: sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.55.1': - resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} + '@rollup/rollup-win32-arm64-msvc@4.55.2': + resolution: {integrity: sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.55.1': - resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} + '@rollup/rollup-win32-ia32-msvc@4.55.2': + resolution: {integrity: sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.55.1': - resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} + '@rollup/rollup-win32-x64-gnu@4.55.2': + resolution: {integrity: sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.55.1': - resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} + '@rollup/rollup-win32-x64-msvc@4.55.2': + resolution: {integrity: sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q==} cpu: [x64] os: [win32] + '@shoelace-style/animations@1.2.0': + resolution: {integrity: sha512-avvo1xxkLbv2dgtabdewBbqcJfV0e0zCwFqkPMnHFGbJbBHorRFfMAHh1NG9ymmXn0jW95ibUVH03E1NYXD6Gw==} + + '@shoelace-style/localize@3.2.1': + resolution: {integrity: sha512-r4C9C/5kSfMBIr0D9imvpRdCNXtUNgyYThc4YlS6K5Hchv1UyxNQ9mxwj+BTRH2i1Neits260sR3OjKMnplsFA==} + + '@shoelace-style/shoelace@2.20.1': + resolution: {integrity: sha512-FSghU95jZPGbwr/mybVvk66qRZYpx5FkXL+vLNpy1Vp8UsdwSxXjIHE3fsvMbKWTKi9UFfewHTkc5e7jAqRYoQ==} + engines: {node: '>=14.17.0'} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -772,12 +902,108 @@ packages: '@types/cross-spawn@6.0.6': resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -790,6 +1016,12 @@ packages: '@types/node@22.19.7': resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==} + '@types/raf@3.4.3': + resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==} + + '@types/react@19.2.8': + resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} + '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} @@ -799,6 +1031,9 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -845,10 +1080,24 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arkregex@0.0.5: + resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==} + + arktype@2.1.29: + resolution: {integrity: sha512-jyfKk4xIOzvYNayqnD8ZJQqOwcrTOUbIU4293yrzAjA3O1dWh61j71ArMQ6tS/u4pD7vabSPe7nG3RCyoXW6RQ==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -857,6 +1106,10 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + canvg@4.0.3: + resolution: {integrity: sha512-fKzMoMBwus3CWo1Uy8XJc4tqqn98RoRrGV6CsIkaNiQT5lOeHuMh4fOt+LXLzn2Wqtr4p/c2TOLz4xtu4oBlFA==} + engines: {node: '>=12.0.0'} + chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} @@ -869,6 +1122,10 @@ packages: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -884,13 +1141,152 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + composed-offset-position@0.0.6: + resolution: {integrity: sha512-Q7dLompI6lUwd7LWyIcP66r4WcS9u7AL2h8HaeipiRfCRPLMWqRx8fYsjb4OHi6UQFifO7XtNC2IlEJ1ozIFxw==} + peerDependencies: + '@floating-ui/utils': ^0.2.5 + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + ctrlc-windows@2.2.0: resolution: {integrity: sha512-t9y568r+T8FUuBaqKK60YGFJdj3b3ktdJW9WXIT3CuBdQhAOYdSZu75jFUN0Ay4Yz5HHicVQqAYCwcnqhOn23g==} + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -904,15 +1300,22 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - effect@3.19.14: - resolution: {integrity: sha512-3vwdq0zlvQOxXzXNKRIPKTqZNMyGCdaFUBfMPqpsyzZDre67kgC1EEHDV4EoQTovJ4w5fmJW756f86kkuz7WFA==} + effect@3.19.15: + resolution: {integrity: sha512-vzMmgfZKLcojmUjBdlQx+uaKryO7yULlRxjpDnHdnvcp1NPHxJyoM6IOXBLlzz2I/uPtZpGKavt5hBv7IvGZkA==} - effection@4.0.0: - resolution: {integrity: sha512-eW2yqhyBdey4k8lkp7hpiev2FSHvJvQqvaIebI3EGikHZvfUWvNy7SmkwOnJa6WcsUtSh7VHUwdjHTbV++8M9w==} + effection@4.1.0-alpha.3: + resolution: {integrity: sha512-EQRygHWOFDopUWAdGBz87sIvLemhdgGTqKKpvrDmrE+ZaO0l85gEBJ2xXT4Rk5LqknRV4FcQrIeqZtn0OHoO/w==} engines: {node: '>= 16'} es-module-lexer@1.7.0: @@ -964,13 +1367,31 @@ packages: resolution: {integrity: sha512-LuYDCS1DbKQsvChP1xHmAzHnGdd0z0K1XMebmbNbFzGZI62KODnV2CXA7zOqebiDzlK2sxXrPGfwlDzSm9aP4g==} engines: {node: '>=6.0.0'} + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + h3@2.0.1-rc.14: + resolution: {integrity: sha512-163qbGmTr/9rqQRNuqMqtgXnOUAkE4KTdauiC9y0E5iG1I65kte9NyfWvZw5RTDMt6eY+DtyoNzrQ9wA2BfvGQ==} + engines: {node: '>=20.11.1'} + hasBin: true + peerDependencies: + crossws: ^0.4.1 + peerDependenciesMeta: + crossws: + optional: true + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} @@ -978,6 +1399,22 @@ packages: immutable@5.1.4: resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -1011,6 +1448,85 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + lightningcss-android-arm64@1.31.1: + resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.31.1: + resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.31.1: + resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.31.1: + resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.31.1: + resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.31.1: + resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.31.1: + resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.31.1: + resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.31.1: + resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.31.1: + resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.31.1: + resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.31.1: + resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + engines: {node: '>= 12.0.0'} + + lit-element@4.2.2: + resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==} + + lit-html@3.3.2: + resolution: {integrity: sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==} + + lit@3.3.2: + resolution: {integrity: sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -1029,6 +1545,18 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + + parse-sse@0.1.0: + resolution: {integrity: sha512-8bObUwtEuLp2Z1gP6iRVMBzmEqaU5ohmofa3WmZVFfFZFKRP/+c03y8NVYzzXmQMotQ6mDS5Mnyk6tT1gKOTcQ==} + engines: {node: '>=20'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1040,6 +1568,9 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1062,9 +1593,24 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qr-creator@1.0.0: + resolution: {integrity: sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==} + + querystring@0.2.1: + resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + + raf@3.4.1: + resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -1072,11 +1618,27 @@ packages: remeda@2.33.4: resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} - rollup@4.55.1: - resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} + rgbcolor@1.0.1: + resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==} + engines: {node: '>= 0.8.15'} + + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + + rollup@4.55.2: + resolution: {integrity: sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rou3@0.7.12: + resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} @@ -1104,6 +1666,11 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + srvx@0.11.2: + resolution: {integrity: sha512-u6NbjE84IJwm1XUnJ53WqylLTQ3BdWRw03lcjBNNeMBD+EFjkl0Cnw1RVaGSqRAo38pOHOPXJH30M6cuTINUxw==} + engines: {node: '>=20.16.0'} + hasBin: true + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -1111,6 +1678,10 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stackblur-canvas@2.7.0: + resolution: {integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==} + engines: {node: '>=0.1.14'} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} @@ -1121,6 +1692,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + svg-pathdata@6.0.3: + resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==} + engines: {node: '>=12.0.0'} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1198,6 +1773,12 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true + vite-plugin-static-copy@3.2.0: + resolution: {integrity: sha512-g2k9z8B/1Bx7D4wnFjPLx9dyYGrqWMLTpwTtPHhcU+ElNZP2O4+4OsyaficiDClus0dzVhdGvoGFYMJxoXZ12Q==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + vite@7.3.1: resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1303,8 +1884,19 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.3.5: + resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} + snapshots: + '@ark/schema@0.56.0': + dependencies: + '@ark/util': 0.56.0 + + '@ark/util@0.56.0': {} + + '@b9g/crank@0.7.5': {} + '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -1348,6 +1940,8 @@ snapshots: '@biomejs/cli-win32-x64@1.9.4': optional: true + '@ctrl/tinycolor@4.2.0': {} + '@esbuild/aix-ppc64@0.27.2': optional: true @@ -1428,6 +2022,17 @@ snapshots: '@essentials/raf@1.2.0': {} + '@floating-ui/core@1.7.4': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.5': + dependencies: + '@floating-ui/core': 1.7.4 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/utils@0.2.10': {} + '@jest/expect-utils@29.7.0': dependencies: jest-get-type: 29.6.3 @@ -1447,81 +2052,128 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.5': {} - '@rollup/rollup-android-arm-eabi@4.55.1': + '@lit-labs/ssr-dom-shim@1.5.1': {} + + '@lit/react@1.0.8(@types/react@19.2.8)': + dependencies: + '@types/react': 19.2.8 + + '@lit/reactive-element@2.1.2': + dependencies: + '@lit-labs/ssr-dom-shim': 1.5.1 + + '@nano-router/history@4.0.4': {} + + '@nano-router/path@4.0.4': {} + + '@nano-router/router@4.0.4': + dependencies: + '@nano-router/history': 4.0.4 + '@nano-router/routes': 4.0.4 + '@nano-router/url': 4.0.4 + + '@nano-router/routes@4.0.4': + dependencies: + '@nano-router/path': 4.0.4 + + '@nano-router/url@4.0.4': + dependencies: + '@nano-router/path': 4.0.4 + querystring: 0.2.1 + + '@rollup/rollup-android-arm-eabi@4.55.2': optional: true - '@rollup/rollup-android-arm64@4.55.1': + '@rollup/rollup-android-arm64@4.55.2': optional: true - '@rollup/rollup-darwin-arm64@4.55.1': + '@rollup/rollup-darwin-arm64@4.55.2': optional: true - '@rollup/rollup-darwin-x64@4.55.1': + '@rollup/rollup-darwin-x64@4.55.2': optional: true - '@rollup/rollup-freebsd-arm64@4.55.1': + '@rollup/rollup-freebsd-arm64@4.55.2': optional: true - '@rollup/rollup-freebsd-x64@4.55.1': + '@rollup/rollup-freebsd-x64@4.55.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + '@rollup/rollup-linux-arm-gnueabihf@4.55.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.55.1': + '@rollup/rollup-linux-arm-musleabihf@4.55.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.55.1': + '@rollup/rollup-linux-arm64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.55.1': + '@rollup/rollup-linux-arm64-musl@4.55.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.55.1': + '@rollup/rollup-linux-loong64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-loong64-musl@4.55.1': + '@rollup/rollup-linux-loong64-musl@4.55.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.55.1': + '@rollup/rollup-linux-ppc64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-ppc64-musl@4.55.1': + '@rollup/rollup-linux-ppc64-musl@4.55.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.55.1': + '@rollup/rollup-linux-riscv64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.55.1': + '@rollup/rollup-linux-riscv64-musl@4.55.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.55.1': + '@rollup/rollup-linux-s390x-gnu@4.55.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.55.1': + '@rollup/rollup-linux-x64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-x64-musl@4.55.1': + '@rollup/rollup-linux-x64-musl@4.55.2': optional: true - '@rollup/rollup-openbsd-x64@4.55.1': + '@rollup/rollup-openbsd-x64@4.55.2': optional: true - '@rollup/rollup-openharmony-arm64@4.55.1': + '@rollup/rollup-openharmony-arm64@4.55.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.55.1': + '@rollup/rollup-win32-arm64-msvc@4.55.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.55.1': + '@rollup/rollup-win32-ia32-msvc@4.55.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.55.1': + '@rollup/rollup-win32-x64-gnu@4.55.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.55.1': + '@rollup/rollup-win32-x64-msvc@4.55.2': optional: true + '@shoelace-style/animations@1.2.0': {} + + '@shoelace-style/localize@3.2.1': {} + + '@shoelace-style/shoelace@2.20.1(@floating-ui/utils@0.2.10)(@types/react@19.2.8)': + dependencies: + '@ctrl/tinycolor': 4.2.0 + '@floating-ui/dom': 1.7.5 + '@lit/react': 1.0.8(@types/react@19.2.8) + '@shoelace-style/animations': 1.2.0 + '@shoelace-style/localize': 3.2.1 + composed-offset-position: 0.0.6(@floating-ui/utils@0.2.10) + lit: 3.3.2 + qr-creator: 1.0.0 + transitivePeerDependencies: + - '@floating-ui/utils' + - '@types/react' + '@sinclair/typebox@0.27.8': {} '@sinonjs/commons@3.0.1': @@ -1543,10 +2195,129 @@ snapshots: dependencies: '@types/node': 22.19.7 + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/deep-eql@4.0.2': {} '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -1561,12 +2332,20 @@ snapshots: dependencies: undici-types: 6.21.0 + '@types/raf@3.4.3': {} + + '@types/react@19.2.8': + dependencies: + csstype: 3.2.3 + '@types/semver@7.7.1': {} '@types/sinonjs__fake-timers@8.1.5': {} '@types/stack-utils@2.0.3': {} + '@types/trusted-types@2.0.7': {} + '@types/ws@8.18.1': dependencies: '@types/node': 22.19.7 @@ -1585,13 +2364,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@22.19.7)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@22.19.7)(yaml@2.8.2) + vite: 7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2) '@vitest/pretty-format@3.2.4': dependencies: @@ -1625,14 +2404,39 @@ snapshots: ansi-styles@5.2.0: {} + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arkregex@0.0.5: + dependencies: + '@ark/util': 0.56.0 + + arktype@2.1.29: + dependencies: + '@ark/schema': 0.56.0 + '@ark/util': 0.56.0 + arkregex: 0.0.5 + assertion-error@2.0.1: {} + binary-extensions@2.3.0: {} + braces@3.0.3: dependencies: fill-range: 7.1.1 cac@6.7.14: {} + canvg@4.0.3: + dependencies: + '@types/raf': 3.4.3 + raf: 3.4.1 + rgbcolor: 1.0.1 + stackblur-canvas: 2.7.0 + svg-pathdata: 6.0.3 + chai@5.3.3: dependencies: assertion-error: 2.0.1 @@ -1648,6 +2452,18 @@ snapshots: check-error@2.1.3: {} + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -1660,28 +2476,194 @@ snapshots: color-name@1.1.4: {} + commander@7.2.0: {} + + composed-offset-position@0.0.6(@floating-ui/utils@0.2.10): + dependencies: + '@floating-ui/utils': 0.2.10 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + csstype@3.2.3: {} + ctrlc-windows@2.2.0: {} + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + debug@4.4.3: dependencies: ms: 2.1.3 deep-eql@5.0.2: {} + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + + detect-libc@2.1.2: {} + diff-sequences@29.6.3: {} - effect@3.19.14: + effect@3.19.15: dependencies: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 - effection@4.0.0: {} + effection@4.1.0-alpha.3: {} es-module-lexer@1.7.0: {} @@ -1747,14 +2729,39 @@ snapshots: generatorics@1.1.0: {} + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + graceful-fs@4.2.11: {} + h3@2.0.1-rc.14: + dependencies: + rou3: 0.7.12 + srvx: 0.11.2 + has-flag@4.0.0: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ignore@7.0.5: {} immutable@5.1.4: {} + internmap@2.0.3: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + is-number@7.0.0: {} isexe@2.0.0: {} @@ -1800,6 +2807,71 @@ snapshots: js-tokens@9.0.1: {} + lightningcss-android-arm64@1.31.1: + optional: true + + lightningcss-darwin-arm64@1.31.1: + optional: true + + lightningcss-darwin-x64@1.31.1: + optional: true + + lightningcss-freebsd-x64@1.31.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.31.1: + optional: true + + lightningcss-linux-arm64-gnu@1.31.1: + optional: true + + lightningcss-linux-arm64-musl@1.31.1: + optional: true + + lightningcss-linux-x64-gnu@1.31.1: + optional: true + + lightningcss-linux-x64-musl@1.31.1: + optional: true + + lightningcss-win32-arm64-msvc@1.31.1: + optional: true + + lightningcss-win32-x64-msvc@1.31.1: + optional: true + + lightningcss@1.31.1: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.31.1 + lightningcss-darwin-arm64: 1.31.1 + lightningcss-darwin-x64: 1.31.1 + lightningcss-freebsd-x64: 1.31.1 + lightningcss-linux-arm-gnueabihf: 1.31.1 + lightningcss-linux-arm64-gnu: 1.31.1 + lightningcss-linux-arm64-musl: 1.31.1 + lightningcss-linux-x64-gnu: 1.31.1 + lightningcss-linux-x64-musl: 1.31.1 + lightningcss-win32-arm64-msvc: 1.31.1 + lightningcss-win32-x64-msvc: 1.31.1 + + lit-element@4.2.2: + dependencies: + '@lit-labs/ssr-dom-shim': 1.5.1 + '@lit/reactive-element': 2.1.2 + lit-html: 3.3.2 + + lit-html@3.3.2: + dependencies: + '@types/trusted-types': 2.0.7 + + lit@3.3.2: + dependencies: + '@lit/reactive-element': 2.1.2 + lit-element: 4.2.2 + lit-html: 3.3.2 + loupe@3.2.1: {} magic-string@0.30.21: @@ -1815,12 +2887,20 @@ snapshots: nanoid@3.3.11: {} + normalize-path@3.0.0: {} + + p-map@7.0.4: {} + + parse-sse@0.1.0: {} + path-key@3.1.1: {} pathe@2.0.3: {} pathval@2.0.1: {} + performance-now@2.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -1841,43 +2921,65 @@ snapshots: pure-rand@6.1.0: {} + qr-creator@1.0.0: {} + + querystring@0.2.1: {} + + raf@3.4.1: + dependencies: + performance-now: 2.1.0 + react-is@18.3.1: {} + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + readdirp@4.1.2: {} remeda@2.33.4: {} - rollup@4.55.1: + rgbcolor@1.0.1: {} + + robust-predicates@3.0.2: {} + + rollup@4.55.2: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.55.1 - '@rollup/rollup-android-arm64': 4.55.1 - '@rollup/rollup-darwin-arm64': 4.55.1 - '@rollup/rollup-darwin-x64': 4.55.1 - '@rollup/rollup-freebsd-arm64': 4.55.1 - '@rollup/rollup-freebsd-x64': 4.55.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 - '@rollup/rollup-linux-arm-musleabihf': 4.55.1 - '@rollup/rollup-linux-arm64-gnu': 4.55.1 - '@rollup/rollup-linux-arm64-musl': 4.55.1 - '@rollup/rollup-linux-loong64-gnu': 4.55.1 - '@rollup/rollup-linux-loong64-musl': 4.55.1 - '@rollup/rollup-linux-ppc64-gnu': 4.55.1 - '@rollup/rollup-linux-ppc64-musl': 4.55.1 - '@rollup/rollup-linux-riscv64-gnu': 4.55.1 - '@rollup/rollup-linux-riscv64-musl': 4.55.1 - '@rollup/rollup-linux-s390x-gnu': 4.55.1 - '@rollup/rollup-linux-x64-gnu': 4.55.1 - '@rollup/rollup-linux-x64-musl': 4.55.1 - '@rollup/rollup-openbsd-x64': 4.55.1 - '@rollup/rollup-openharmony-arm64': 4.55.1 - '@rollup/rollup-win32-arm64-msvc': 4.55.1 - '@rollup/rollup-win32-ia32-msvc': 4.55.1 - '@rollup/rollup-win32-x64-gnu': 4.55.1 - '@rollup/rollup-win32-x64-msvc': 4.55.1 + '@rollup/rollup-android-arm-eabi': 4.55.2 + '@rollup/rollup-android-arm64': 4.55.2 + '@rollup/rollup-darwin-arm64': 4.55.2 + '@rollup/rollup-darwin-x64': 4.55.2 + '@rollup/rollup-freebsd-arm64': 4.55.2 + '@rollup/rollup-freebsd-x64': 4.55.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.2 + '@rollup/rollup-linux-arm-musleabihf': 4.55.2 + '@rollup/rollup-linux-arm64-gnu': 4.55.2 + '@rollup/rollup-linux-arm64-musl': 4.55.2 + '@rollup/rollup-linux-loong64-gnu': 4.55.2 + '@rollup/rollup-linux-loong64-musl': 4.55.2 + '@rollup/rollup-linux-ppc64-gnu': 4.55.2 + '@rollup/rollup-linux-ppc64-musl': 4.55.2 + '@rollup/rollup-linux-riscv64-gnu': 4.55.2 + '@rollup/rollup-linux-riscv64-musl': 4.55.2 + '@rollup/rollup-linux-s390x-gnu': 4.55.2 + '@rollup/rollup-linux-x64-gnu': 4.55.2 + '@rollup/rollup-linux-x64-musl': 4.55.2 + '@rollup/rollup-openbsd-x64': 4.55.2 + '@rollup/rollup-openharmony-arm64': 4.55.2 + '@rollup/rollup-win32-arm64-msvc': 4.55.2 + '@rollup/rollup-win32-ia32-msvc': 4.55.2 + '@rollup/rollup-win32-x64-gnu': 4.55.2 + '@rollup/rollup-win32-x64-msvc': 4.55.2 fsevents: 2.3.3 + rou3@0.7.12: {} + + rw@1.3.3: {} + + safer-buffer@2.1.2: {} + semver@7.7.3: {} shebang-command@2.0.0: @@ -1894,12 +2996,16 @@ snapshots: source-map-js@1.2.1: {} + srvx@0.11.2: {} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 stackback@0.0.2: {} + stackblur-canvas@2.7.0: {} + std-env@3.10.0: {} strip-literal@3.1.0: @@ -1910,6 +3016,8 @@ snapshots: dependencies: has-flag: 4.0.0 + svg-pathdata@6.0.3: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -1962,13 +3070,13 @@ snapshots: undici-types@6.21.0: {} - vite-node@3.2.4(@types/node@22.19.7)(yaml@2.8.2): + vite-node@3.2.4(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@22.19.7)(yaml@2.8.2) + vite: 7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti @@ -1983,24 +3091,33 @@ snapshots: - tsx - yaml - vite@7.3.1(@types/node@22.19.7)(yaml@2.8.2): + vite-plugin-static-copy@3.2.0(vite@7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2)): + dependencies: + chokidar: 3.6.0 + p-map: 7.0.4 + picocolors: 1.1.1 + tinyglobby: 0.2.15 + vite: 7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2) + + vite@7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.55.1 + rollup: 4.55.2 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.19.7 fsevents: 2.3.3 + lightningcss: 1.31.1 yaml: 2.8.2 - vitest@3.2.4(@types/node@22.19.7)(yaml@2.8.2): + vitest@3.2.4(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@22.19.7)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -2018,8 +3135,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@22.19.7)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@22.19.7)(yaml@2.8.2) + vite: 7.3.1(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2) + vite-node: 3.2.4(@types/node@22.19.7)(lightningcss@1.31.1)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.7 @@ -2057,3 +3174,5 @@ snapshots: zod: 3.25.76 zod@3.25.76: {} + + zod@4.3.5: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index eeea2322..903b107b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -8,6 +8,7 @@ packages: - "effect-ts" - "fs" - "fx" + - "inspector" - "jsonl-store" - "node" - "process" diff --git a/stream-helpers/subject.ts b/stream-helpers/subject.ts index 516e8326..8819c0d4 100644 --- a/stream-helpers/subject.ts +++ b/stream-helpers/subject.ts @@ -35,10 +35,13 @@ import type { Stream, Subscription } from "effection"; * ]); * ``` */ -export function createSubject(): ( - stream: Stream, -) => Stream { - let current: IteratorResult | undefined = undefined; +export function createSubject( + initial?: T, +): (stream: Stream) => Stream { + let current: IteratorResult | undefined = + typeof initial !== "undefined" + ? { done: false, value: initial } + : undefined; return (stream: Stream) => ({ *[Symbol.iterator]() { diff --git a/tsconfig.json b/tsconfig.json index 64ff488e..162c1c2d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -35,6 +35,7 @@ { "path": "vitest" }, { "path": "watch" }, { "path": "websocket" }, - { "path": "worker" } + { "path": "worker" }, + { "path": "inspector" } ] } diff --git a/watch/main.ts b/watch/main.ts index eadefd6a..7d69cc82 100644 --- a/watch/main.ts +++ b/watch/main.ts @@ -5,7 +5,7 @@ import { parser } from "zod-opts"; import packageJson from "./package.json" with { type: "json" }; import { watch } from "./watch.ts"; -const builtins = ["-h", "--help", "-V", "--version"]; +const builtins = ["-h", "--help", "-V", "--version", "--path"]; main(function* (argv) { let { args, rest } = extract(argv); @@ -72,8 +72,18 @@ function extract(argv: string[]): Extract { let rest: string[] = argv.slice(); for (let arg = rest.shift(); arg; arg = rest.shift()) { + if (!arg.startsWith("-")) { + rest.push(arg); + break; + } if (builtins.includes(arg)) { args.push(arg); + if (arg === "--path") { + const next = rest.shift(); + if (next !== undefined) { + args.push(next); + } + } } else { rest.unshift(arg); break;