@fluojs/studio 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ :root{color-scheme:dark;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;background:#070b16;color:#e5e7eb}*{box-sizing:border-box}body{min-height:100vh;margin:0;background:radial-gradient(circle at top left,rgba(59,130,246,.22),transparent 34rem),radial-gradient(circle at 80% 10%,rgba(14,165,233,.16),transparent 28rem),linear-gradient(180deg,#07101f,#0b1020 55%,#070b16);color:#e5e7eb}button,input{font:inherit}main{width:min(1480px,calc(100vw - 32px));margin:0 auto;padding:28px 0 48px}h1,h2,h3,h4,p{margin-top:0}h1{margin-bottom:12px;font-size:clamp(34px,5vw,68px);letter-spacing:-.065em;line-height:.95}h2{margin-bottom:10px;font-size:22px;letter-spacing:-.03em}h3{margin-bottom:8px}p{line-height:1.65}code{border:1px solid rgba(148,163,184,.26);border-radius:8px;background:#0f172ad1;color:#bfdbfe;padding:2px 7px}.studio-hero{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:24px;align-items:end;margin-bottom:18px;border:1px solid rgba(147,197,253,.2);border-radius:28px;background:linear-gradient(135deg,#0f172ac2,#1e293b94);box-shadow:0 28px 90px #00000047;padding:32px}.studio-hero p{max-width:820px;color:#b6c4d8}.hero-command{border:1px solid rgba(96,165,250,.42);border-radius:18px;background:#0f172ae6;box-shadow:inset 0 1px #ffffff0d;padding:14px 18px;white-space:nowrap}.card{border:1px solid rgba(148,163,184,.2);border-radius:22px;background:linear-gradient(180deg,#0f172ae0,#111827d1);box-shadow:0 20px 80px #00000038;padding:18px;margin-bottom:16px}.section-title-row{display:flex;gap:16px;align-items:flex-start;justify-content:space-between}.eyebrow{margin:0 0 6px;color:#93c5fd;font-size:12px;font-weight:800;letter-spacing:.12em;text-transform:uppercase}.mode-badge,.status-pill,.chip{display:inline-flex;align-items:center;border:1px solid rgba(148,163,184,.24);border-radius:999px;background:#0f172ab8;color:#cbd5e1;padding:5px 10px;font-size:12px;line-height:1.2}.mode-badge{color:#bfdbfe}.status-pill-success{border-color:#22c55e5c;color:#bbf7d0}.status-pill-warning{border-color:#f59e0b6b;color:#fde68a}.status-pill-danger{border-color:#f871716b;color:#fecaca}.status-pill-accent{border-color:#60a5fa6b;color:#bfdbfe}.status-pill-muted{color:#94a3b8}.chips{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:10px}.muted{color:#94a3b8}.notice{margin:12px 0 0;color:#93c5fd}.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}button{border:1px solid rgba(96,165,250,.32);border-radius:12px;background:linear-gradient(180deg,#2563eb,#1d4ed8);color:#fff;cursor:pointer;padding:9px 13px}button:disabled{border-color:#64748b47;background:#475569;cursor:not-allowed}button:hover:not(:disabled),button:focus-visible:not(:disabled){border-color:#93c5fdcc;outline:none;transform:translateY(-1px)}label{display:block;margin-bottom:10px}input[type=text]{width:100%;margin-top:6px;border:1px solid rgba(148,163,184,.28);border-radius:12px;background:#0f172ad1;color:#e5e7eb;padding:10px 12px}input[type=file]{width:100%;border:1px dashed rgba(148,163,184,.36);border-radius:14px;padding:16px}.filter-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;margin-bottom:10px}.filter-row span{color:#cbd5e1;font-weight:700}.uploader.drag-active{border-color:#60a5fa;box-shadow:0 0 0 2px #60a5fa59 inset}.live-connection{position:relative;overflow:hidden}.live-connection:before{position:absolute;top:0;right:0;bottom:0;left:0;background:radial-gradient(circle at 0% 0%,rgba(34,211,238,.14),transparent 26rem);content:"";pointer-events:none}.live-status-main{position:relative;display:flex;gap:18px;align-items:flex-start;justify-content:space-between}.connection-orb-wrap{display:grid;gap:8px;justify-items:center;min-width:120px;text-transform:uppercase}.connection-orb{display:block;width:22px;height:22px;border-radius:999px;background:#64748b;box-shadow:0 0 30px #64748bcc}.connection-connected .connection-orb{background:#22c55e;box-shadow:0 0 35px #22c55ec7}.connection-connecting .connection-orb,.connection-reconnecting .connection-orb,.connection-restarting .connection-orb{background:#f59e0b;box-shadow:0 0 35px #f59e0bcc}.connection-stale .connection-orb,.connection-error .connection-orb,.connection-disconnected .connection-orb{background:#ef4444;box-shadow:0 0 35px #ef4444c7}.dashboard-grid{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(360px,.75fr);gap:16px;align-items:start}.live-graph-card,.timing-card,.live-diagnostics-card{grid-column:1 / -1}.live-graph-layout,.routes-layout,.request-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(280px,.34fr);gap:16px}.live-graph-canvas,#graph-host{overflow:auto;min-height:320px;border:1px solid rgba(148,163,184,.18);border-radius:18px;background:#020617ad}.live-graph-canvas svg,#graph-host svg{min-width:780px;width:100%}.live-edge{stroke:#64748b99;stroke-width:1.4}.live-edge-highlighted{stroke:#f59e0b;stroke-width:2.4}.live-edge-arrow{fill:#64748b}.live-edge-label{fill:#fde68a;font-size:11px;paint-order:stroke;stroke:#020617;stroke-width:3px}.live-node rect{fill:#1e293bf5;stroke:#94a3b873;stroke-width:1.2}.live-node text{fill:#e5e7eb;font-size:11px;text-anchor:middle;pointer-events:none}.live-node .live-node-kind{fill:#94a3b8;font-size:10px}.live-node-module rect,.live-node-active rect{fill:#1e40afeb}.live-node-provider rect{fill:#14532de0}.live-node-controller rect{fill:#5b21b6e0}.live-node-route rect{fill:#0c4a6ee0}.live-node-external rect,.live-node-platform rect{fill:#475569e0}.live-node-selected rect{stroke:#fbbf24;stroke-width:3}.live-node-related rect{stroke:#38bdf8;stroke-width:2.2}.live-graph-details,.route-detail,.request-detail{border:1px solid rgba(148,163,184,.18);border-radius:18px;background:#0f172aa8;padding:14px}.edge-list,.route-list,.request-timeline{display:grid;gap:8px}.edge-row,.route-row,.request-row,.connection-button{display:grid;width:100%;gap:4px;border-color:#94a3b82e;background:#0f172adb;color:#e5e7eb;text-align:left}.edge-row span,.route-row small,.request-row small,.connection-button small{color:#94a3b8}.route-row-selected,.request-row-selected{border-color:#60a5fa;box-shadow:0 0 0 1px #60a5fa3d inset}.method{width:fit-content;border-radius:999px;background:#60a5fa29;color:#bfdbfe;padding:3px 7px;font-size:11px;font-weight:800}.request-row-danger{border-color:#f871716b}.request-row-success{border-color:#22c55e52}.request-row-accent{border-color:#60a5fa5c}.timing-grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}.timing-total{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:10px;border:1px solid rgba(148,163,184,.18);border-radius:14px;background:#0f172aa8;padding:10px 12px}table{width:100%;border-collapse:collapse}th,td{border-bottom:1px solid rgba(148,163,184,.18);text-align:left;font-size:13px;padding:8px 6px}pre{overflow:auto;max-height:340px;border:1px solid rgba(148,163,184,.18);border-radius:14px;background:#020617b8;padding:14px}.split-grid,.section-pair{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}.empty-state{display:grid;gap:4px;place-items:start;border:1px dashed rgba(148,163,184,.32);border-radius:16px;color:#94a3b8;padding:18px}.empty-state strong{color:#e5e7eb}.edge-line{stroke:#64748b;stroke-width:1.6}.edge-selected{stroke:#f59e0b;stroke-width:2.6}.edge-arrow{fill:#64748b}.module-node{fill:#1e293b;stroke:#64748b;stroke-width:1.5;cursor:pointer}.module-node:focus-visible{outline:none;stroke:#60a5fa;stroke-width:3}.module-root{stroke:#3b82f6;stroke-width:2.6}.component-ready{fill:#14532d}.component-degraded{fill:#7c2d12}.component-not-ready{fill:#7f1d1d}.component-external{fill:#312e81;cursor:default}.module-selected{stroke:#f59e0b;stroke-width:3}.module-neighbor{stroke:#38bdf8;stroke-width:2.6}.module-dependent{stroke:#a78bfa;stroke-width:2.6}.module-label{fill:#e5e7eb;font-size:11px;pointer-events:none}.diagnostics-list{display:grid;gap:12px}.issue{margin-bottom:0}.issue.severity-error,.inline-diagnostic.severity-error{border-color:#ef4444}.issue.severity-warning{border-color:#f59e0b}.issue.severity-info{border-color:#3b82f6}.inline-diagnostic{border:1px solid rgba(248,113,113,.38);border-radius:14px;background:#7f1d1d3d;padding:12px}a{color:#93c5fd}.inspector-card{background:linear-gradient(135deg,#0f172af5,#111827eb)}.connection-hero{display:flex;flex-wrap:wrap;gap:16px;align-items:flex-start;justify-content:space-between;border:1px solid rgba(148,163,184,.2);border-radius:16px;background:#0f172ad1;padding:14px;margin-bottom:14px}.connection-metrics{display:flex;flex-wrap:wrap;gap:8px}.connection-metrics span,.connection-pill{border:1px solid rgba(148,163,184,.24);border-radius:999px;background:#111827e0;color:#cbd5e1;padding:6px 10px;font-size:12px}.connection-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}.connection-group h4{margin:0 0 8px}.connection-button:hover,.connection-button:focus-visible{border-color:#60a5fa;outline:none}.connection-button span,.connection-button small{display:block}.external-pill{display:inline-block;margin:0 6px 6px 0}.connection-diagnostic{border-left:3px solid #64748b;padding:8px 0 8px 10px;margin-bottom:8px}.connection-diagnostic.severity-error{border-left-color:#ef4444}.connection-diagnostic.severity-warning{border-left-color:#f59e0b}.connection-diagnostic.severity-info{border-left-color:#3b82f6}.connection-diagnostic span{display:block;color:#94a3b8;font-size:12px;margin-top:2px}.connection-diagnostic p{margin:6px 0 0}@media(max-width:960px){main{width:min(100vw - 20px,920px);padding-top:14px}.studio-hero,.dashboard-grid,.live-graph-layout,.routes-layout,.request-layout{grid-template-columns:1fr}.hero-command{width:fit-content}}
@@ -38,6 +38,126 @@ export interface StudioPayload {
38
38
  snapshot?: PlatformShellSnapshot;
39
39
  timing?: BootstrapTimingDiagnostics;
40
40
  }
41
+ /** Live Studio graph node kinds emitted by runtime-connected devtools. */
42
+ export type StudioGraphNodeKind = 'module' | 'provider' | 'controller' | 'route' | 'platform' | 'external';
43
+ /** Live Studio graph edge kinds emitted by runtime-connected devtools. */
44
+ export type StudioGraphEdgeKind = 'imports' | 'owns_provider' | 'owns_controller' | 'exposes_route' | 'depends_on' | 'exports';
45
+ /** Serializable node in the runtime-connected Studio dependency graph. */
46
+ export interface StudioGraphNode {
47
+ id: string;
48
+ kind: StudioGraphNodeKind;
49
+ label: string;
50
+ metadata?: Record<string, unknown>;
51
+ status?: 'active' | 'idle' | 'warning' | 'error';
52
+ }
53
+ /** Serializable edge in the runtime-connected Studio dependency graph. */
54
+ export interface StudioGraphEdge {
55
+ from: string;
56
+ id: string;
57
+ kind: StudioGraphEdgeKind;
58
+ label?: string;
59
+ metadata?: Record<string, unknown>;
60
+ to: string;
61
+ }
62
+ /** Route descriptor projected into the live Studio UI. */
63
+ export interface StudioRouteDescriptor {
64
+ controller: string;
65
+ handler: string;
66
+ id: string;
67
+ method: string;
68
+ module?: string;
69
+ path: string;
70
+ version?: string;
71
+ }
72
+ /** Request lifecycle status understood by the live Studio request-flow panel. */
73
+ export type StudioRequestStatus = 'started' | 'matched' | 'succeeded' | 'failed' | 'finished';
74
+ /** Request trace emitted by runtime observers without request/response bodies. */
75
+ export interface StudioRequestTrace {
76
+ controller?: string;
77
+ durationMs?: number;
78
+ error?: {
79
+ message: string;
80
+ name?: string;
81
+ };
82
+ finishedAt?: string;
83
+ handler?: string;
84
+ method: string;
85
+ path: string;
86
+ requestId: string;
87
+ routeId?: string;
88
+ startedAt: string;
89
+ status: StudioRequestStatus;
90
+ statusCode?: number;
91
+ url: string;
92
+ }
93
+ /** Runtime diagnostic surfaced in the live Studio diagnostics panel. */
94
+ export interface StudioLiveDiagnostic {
95
+ code: string;
96
+ fixHint?: string;
97
+ message: string;
98
+ scope?: string;
99
+ severity: PlatformDiagnosticSeverity;
100
+ targetId?: string;
101
+ }
102
+ /** Live snapshot consumed by the React Studio shell and sidecar replay cache. */
103
+ export interface StudioLiveSnapshot {
104
+ appId: string;
105
+ diagnostics: StudioLiveDiagnostic[];
106
+ generatedAt: string;
107
+ graph: {
108
+ edges: StudioGraphEdge[];
109
+ nodes: StudioGraphNode[];
110
+ };
111
+ requests: StudioRequestTrace[];
112
+ routes: StudioRouteDescriptor[];
113
+ timing?: BootstrapTimingDiagnostics;
114
+ version: 1;
115
+ }
116
+ /** Studio connection status presented by the live UI. */
117
+ export type StudioConnectionStatus = 'connected' | 'connecting' | 'disconnected' | 'error' | 'reconnecting' | 'restarting' | 'stale' | 'static';
118
+ /** Studio connection state used by sidecar/UI state machines. */
119
+ export interface StudioConnectionState {
120
+ lastEventAt?: string;
121
+ message?: string;
122
+ status: StudioConnectionStatus;
123
+ }
124
+ /**
125
+ * Describes Studio Live Event Source data used by the Studio devtool.
126
+ */
127
+ export interface StudioLiveEventSource {
128
+ appId: string;
129
+ runtime: 'node' | 'bun' | 'deno' | 'worker' | 'unknown';
130
+ }
131
+ /**
132
+ * Describes Studio Live Event Base data used by the Studio devtool.
133
+ */
134
+ export interface StudioLiveEventBase<TType extends string, TPayload> {
135
+ emittedAt: string;
136
+ epoch: string;
137
+ eventId: string;
138
+ payload: TPayload;
139
+ sequence: number;
140
+ source: StudioLiveEventSource;
141
+ type: TType;
142
+ version: 1;
143
+ }
144
+ /**
145
+ * Defines Studio Heartbeat Payload values used by the Studio devtool.
146
+ */
147
+ export type StudioHeartbeatPayload = {
148
+ uptimeMs?: number;
149
+ };
150
+ /** Runtime/app restart lifecycle hint emitted by CLI-owned dev supervision when available. */
151
+ export interface StudioRestartPayload {
152
+ phase: 'scheduled' | 'starting' | 'started' | 'stopping' | 'stopped';
153
+ reason?: string;
154
+ }
155
+ /** Runtime/app disconnect lifecycle hint emitted when the local bridge loses the app process. */
156
+ export interface StudioDisconnectPayload {
157
+ reason?: string;
158
+ }
159
+ /** Event envelope exchanged between runtime, CLI sidecar, and Studio UI. */
160
+ export type StudioLiveEvent = StudioLiveEventBase<'disconnect', StudioDisconnectPayload> | StudioLiveEventBase<'diagnostic', StudioLiveDiagnostic> | StudioLiveEventBase<'heartbeat', StudioHeartbeatPayload> | StudioLiveEventBase<'request', StudioRequestTrace> | StudioLiveEventBase<'restart', StudioRestartPayload> | StudioLiveEventBase<'snapshot', StudioLiveSnapshot> | StudioLiveEventBase<'timing', BootstrapTimingDiagnostics>;
41
161
  /**
42
162
  * Filter state applied to the loaded platform snapshot inside Studio.
43
163
  */
@@ -53,6 +173,28 @@ export interface ParsedPayload {
53
173
  payload: StudioPayload;
54
174
  rawJson: string;
55
175
  }
176
+ /**
177
+ * Validates a runtime-connected Studio event envelope.
178
+ *
179
+ * @param value Candidate event parsed from JSON or received through SSE.
180
+ * @returns The typed Studio live event.
181
+ * @throws Error when the event does not match the live Studio contract.
182
+ */
183
+ export declare function validateStudioLiveEvent(value: unknown): StudioLiveEvent;
184
+ /**
185
+ * Parses a live Studio event JSON envelope from the runtime sidecar stream.
186
+ *
187
+ * @param rawJson Raw JSON encoded event.
188
+ * @returns The validated Studio live event.
189
+ */
190
+ export declare function parseStudioLiveEvent(rawJson: string): StudioLiveEvent;
191
+ /**
192
+ * Runtime-safe type guard for Studio live event envelopes.
193
+ *
194
+ * @param value Candidate value.
195
+ * @returns `true` when the value matches the live Studio event contract.
196
+ */
197
+ export declare function isStudioLiveEvent(value: unknown): value is StudioLiveEvent;
56
198
  /**
57
199
  * Parses a Studio JSON file into the documented snapshot/timing envelope.
58
200
  *
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEtF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxD,eAAe,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,0BAA0B,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,MAAM,CAAC,EAAE,0BAA0B,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,uBAAuB,EAAE,CAAC;IAC7C,UAAU,EAAE,0BAA0B,EAAE,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AA0MD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CA4BjE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,qBAAqB,EAAE,MAAM,EAAE,WAAW,GAAG,qBAAqB,CAwCxG;AA8BD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,CAsErE"}
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"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"}
package/dist/contracts.js CHANGED
@@ -18,6 +18,46 @@
18
18
  * Serializable Studio payload envelope built from inspect snapshot/timing exports.
19
19
  */
20
20
 
21
+ /** Live Studio graph node kinds emitted by runtime-connected devtools. */
22
+
23
+ /** Live Studio graph edge kinds emitted by runtime-connected devtools. */
24
+
25
+ /** Serializable node in the runtime-connected Studio dependency graph. */
26
+
27
+ /** Serializable edge in the runtime-connected Studio dependency graph. */
28
+
29
+ /** Route descriptor projected into the live Studio UI. */
30
+
31
+ /** Request lifecycle status understood by the live Studio request-flow panel. */
32
+
33
+ /** Request trace emitted by runtime observers without request/response bodies. */
34
+
35
+ /** Runtime diagnostic surfaced in the live Studio diagnostics panel. */
36
+
37
+ /** Live snapshot consumed by the React Studio shell and sidecar replay cache. */
38
+
39
+ /** Studio connection status presented by the live UI. */
40
+
41
+ /** Studio connection state used by sidecar/UI state machines. */
42
+
43
+ /**
44
+ * Describes Studio Live Event Source data used by the Studio devtool.
45
+ */
46
+
47
+ /**
48
+ * Describes Studio Live Event Base data used by the Studio devtool.
49
+ */
50
+
51
+ /**
52
+ * Defines Studio Heartbeat Payload values used by the Studio devtool.
53
+ */
54
+
55
+ /** Runtime/app restart lifecycle hint emitted by CLI-owned dev supervision when available. */
56
+
57
+ /** Runtime/app disconnect lifecycle hint emitted when the local bridge loses the app process. */
58
+
59
+ /** Event envelope exchanged between runtime, CLI sidecar, and Studio UI. */
60
+
21
61
  /**
22
62
  * Filter state applied to the loaded platform snapshot inside Studio.
23
63
  */
@@ -44,6 +84,360 @@ function isHealthStatus(value) {
44
84
  function isDiagnosticSeverity(value) {
45
85
  return value === 'error' || value === 'warning' || value === 'info';
46
86
  }
87
+ function isNumber(value) {
88
+ return typeof value === 'number' && Number.isFinite(value);
89
+ }
90
+ function validateString(value, message) {
91
+ if (typeof value !== 'string') {
92
+ throw new Error(message);
93
+ }
94
+ return value;
95
+ }
96
+ function validateOptionalString(value, message) {
97
+ if (value === undefined) {
98
+ return undefined;
99
+ }
100
+ return validateString(value, message);
101
+ }
102
+ function validateOptionalNumber(value, message) {
103
+ if (value === undefined) {
104
+ return undefined;
105
+ }
106
+ if (!isNumber(value)) {
107
+ throw new Error(message);
108
+ }
109
+ return value;
110
+ }
111
+ function validateMetadata(value, message) {
112
+ if (value === undefined) {
113
+ return undefined;
114
+ }
115
+ if (!isRecord(value)) {
116
+ throw new Error(message);
117
+ }
118
+ return value;
119
+ }
120
+ function isStudioGraphNodeKind(value) {
121
+ return value === 'module' || value === 'provider' || value === 'controller' || value === 'route' || value === 'platform' || value === 'external';
122
+ }
123
+ function isStudioGraphEdgeKind(value) {
124
+ return value === 'imports' || value === 'owns_provider' || value === 'owns_controller' || value === 'exposes_route' || value === 'depends_on' || value === 'exports';
125
+ }
126
+ function isStudioRequestStatus(value) {
127
+ return value === 'started' || value === 'matched' || value === 'succeeded' || value === 'failed' || value === 'finished';
128
+ }
129
+ function validateStudioGraphNode(value) {
130
+ if (!isRecord(value) || !isStudioGraphNodeKind(value.kind)) {
131
+ throw new Error('Invalid Studio live graph node payload.');
132
+ }
133
+ const node = {
134
+ id: validateString(value.id, 'Invalid Studio live graph node payload.'),
135
+ kind: value.kind,
136
+ label: validateString(value.label, 'Invalid Studio live graph node payload.')
137
+ };
138
+ const metadata = validateMetadata(value.metadata, 'Invalid Studio live graph node metadata payload.');
139
+ if (metadata) {
140
+ node.metadata = metadata;
141
+ }
142
+ if (value.status !== undefined) {
143
+ if (value.status !== 'active' && value.status !== 'idle' && value.status !== 'warning' && value.status !== 'error') {
144
+ throw new Error('Invalid Studio live graph node status payload.');
145
+ }
146
+ node.status = value.status;
147
+ }
148
+ return node;
149
+ }
150
+ function validateStudioGraphEdge(value) {
151
+ if (!isRecord(value) || !isStudioGraphEdgeKind(value.kind)) {
152
+ throw new Error('Invalid Studio live graph edge payload.');
153
+ }
154
+ const edge = {
155
+ from: validateString(value.from, 'Invalid Studio live graph edge payload.'),
156
+ id: validateString(value.id, 'Invalid Studio live graph edge payload.'),
157
+ kind: value.kind,
158
+ to: validateString(value.to, 'Invalid Studio live graph edge payload.')
159
+ };
160
+ const label = validateOptionalString(value.label, 'Invalid Studio live graph edge label payload.');
161
+ if (label !== undefined) {
162
+ edge.label = label;
163
+ }
164
+ const metadata = validateMetadata(value.metadata, 'Invalid Studio live graph edge metadata payload.');
165
+ if (metadata) {
166
+ edge.metadata = metadata;
167
+ }
168
+ return edge;
169
+ }
170
+ function validateStudioRouteDescriptor(value) {
171
+ if (!isRecord(value)) {
172
+ throw new Error('Invalid Studio live route descriptor payload.');
173
+ }
174
+ const route = {
175
+ controller: validateString(value.controller, 'Invalid Studio live route descriptor payload.'),
176
+ handler: validateString(value.handler, 'Invalid Studio live route descriptor payload.'),
177
+ id: validateString(value.id, 'Invalid Studio live route descriptor payload.'),
178
+ method: validateString(value.method, 'Invalid Studio live route descriptor payload.'),
179
+ path: validateString(value.path, 'Invalid Studio live route descriptor payload.')
180
+ };
181
+ const moduleName = validateOptionalString(value.module, 'Invalid Studio live route descriptor module payload.');
182
+ if (moduleName !== undefined) {
183
+ route.module = moduleName;
184
+ }
185
+ const version = validateOptionalString(value.version, 'Invalid Studio live route descriptor version payload.');
186
+ if (version !== undefined) {
187
+ route.version = version;
188
+ }
189
+ return route;
190
+ }
191
+ function validateStudioRequestTrace(value) {
192
+ if (!isRecord(value) || !isStudioRequestStatus(value.status)) {
193
+ throw new Error('Invalid Studio live request trace payload.');
194
+ }
195
+ const trace = {
196
+ method: validateString(value.method, 'Invalid Studio live request trace payload.'),
197
+ path: validateString(value.path, 'Invalid Studio live request trace payload.'),
198
+ requestId: validateString(value.requestId, 'Invalid Studio live request trace payload.'),
199
+ startedAt: validateString(value.startedAt, 'Invalid Studio live request trace payload.'),
200
+ status: value.status,
201
+ url: validateString(value.url, 'Invalid Studio live request trace payload.')
202
+ };
203
+ for (const key of ['controller', 'finishedAt', 'handler', 'routeId']) {
204
+ const stringValue = validateOptionalString(value[key], 'Invalid Studio live request trace optional string payload.');
205
+ if (stringValue !== undefined) {
206
+ trace[key] = stringValue;
207
+ }
208
+ }
209
+ const durationMs = validateOptionalNumber(value.durationMs, 'Invalid Studio live request trace duration payload.');
210
+ if (durationMs !== undefined) {
211
+ trace.durationMs = durationMs;
212
+ }
213
+ const statusCode = validateOptionalNumber(value.statusCode, 'Invalid Studio live request trace status code payload.');
214
+ if (statusCode !== undefined) {
215
+ trace.statusCode = statusCode;
216
+ }
217
+ if (value.error !== undefined) {
218
+ if (!isRecord(value.error)) {
219
+ throw new Error('Invalid Studio live request trace error payload.');
220
+ }
221
+ trace.error = {
222
+ message: validateString(value.error.message, 'Invalid Studio live request trace error payload.')
223
+ };
224
+ const errorName = validateOptionalString(value.error.name, 'Invalid Studio live request trace error name payload.');
225
+ if (errorName !== undefined) {
226
+ trace.error.name = errorName;
227
+ }
228
+ }
229
+ return trace;
230
+ }
231
+ function validateStudioLiveDiagnostic(value) {
232
+ if (!isRecord(value) || !isDiagnosticSeverity(value.severity)) {
233
+ throw new Error('Invalid Studio live diagnostic payload.');
234
+ }
235
+ const diagnostic = {
236
+ code: validateString(value.code, 'Invalid Studio live diagnostic payload.'),
237
+ message: validateString(value.message, 'Invalid Studio live diagnostic payload.'),
238
+ severity: value.severity
239
+ };
240
+ for (const key of ['fixHint', 'scope', 'targetId']) {
241
+ const stringValue = validateOptionalString(value[key], 'Invalid Studio live diagnostic optional field payload.');
242
+ if (stringValue !== undefined) {
243
+ diagnostic[key] = stringValue;
244
+ }
245
+ }
246
+ return diagnostic;
247
+ }
248
+ function validateStudioRestartPayload(value) {
249
+ if (!isRecord(value)) {
250
+ throw new Error('Invalid Studio live restart payload.');
251
+ }
252
+ const phase = value.phase;
253
+ if (phase !== 'scheduled' && phase !== 'starting' && phase !== 'started' && phase !== 'stopping' && phase !== 'stopped') {
254
+ throw new Error('Invalid Studio live restart phase payload.');
255
+ }
256
+ const payload = {
257
+ phase
258
+ };
259
+ const reason = validateOptionalString(value.reason, 'Invalid Studio live restart reason payload.');
260
+ if (reason !== undefined) {
261
+ payload.reason = reason;
262
+ }
263
+ return payload;
264
+ }
265
+ function validateStudioDisconnectPayload(value) {
266
+ if (!isRecord(value)) {
267
+ throw new Error('Invalid Studio live disconnect payload.');
268
+ }
269
+ const reason = validateOptionalString(value.reason, 'Invalid Studio live disconnect reason payload.');
270
+ return reason === undefined ? {} : {
271
+ reason
272
+ };
273
+ }
274
+ function validateStudioLiveSnapshot(value) {
275
+ if (!isRecord(value) || value.version !== 1 || !isRecord(value.graph)) {
276
+ throw new Error('Invalid Studio live snapshot payload.');
277
+ }
278
+ if (!Array.isArray(value.graph.nodes) || !Array.isArray(value.graph.edges) || !Array.isArray(value.routes) || !Array.isArray(value.diagnostics) || !Array.isArray(value.requests)) {
279
+ throw new Error('Invalid Studio live snapshot payload.');
280
+ }
281
+ const timing = validateTiming(value.timing);
282
+ const snapshot = {
283
+ appId: validateString(value.appId, 'Invalid Studio live snapshot payload.'),
284
+ diagnostics: value.diagnostics.map(diagnostic => validateStudioLiveDiagnostic(diagnostic)),
285
+ generatedAt: validateString(value.generatedAt, 'Invalid Studio live snapshot payload.'),
286
+ graph: {
287
+ edges: value.graph.edges.map(edge => validateStudioGraphEdge(edge)),
288
+ nodes: value.graph.nodes.map(node => validateStudioGraphNode(node))
289
+ },
290
+ requests: value.requests.map(request => validateStudioRequestTrace(request)),
291
+ routes: value.routes.map(route => validateStudioRouteDescriptor(route)),
292
+ version: 1
293
+ };
294
+ if (timing) {
295
+ snapshot.timing = timing;
296
+ }
297
+ return snapshot;
298
+ }
299
+ function validateStudioLiveEventSource(value) {
300
+ if (!isRecord(value)) {
301
+ throw new Error('Invalid Studio live event source payload.');
302
+ }
303
+ const runtime = value.runtime;
304
+ if (runtime !== 'node' && runtime !== 'bun' && runtime !== 'deno' && runtime !== 'worker' && runtime !== 'unknown') {
305
+ throw new Error('Invalid Studio live event runtime payload.');
306
+ }
307
+ return {
308
+ appId: validateString(value.appId, 'Invalid Studio live event source payload.'),
309
+ runtime
310
+ };
311
+ }
312
+ function validateStudioLiveEventPayload(type, payload) {
313
+ if (type === 'snapshot') {
314
+ return validateStudioLiveSnapshot(payload);
315
+ }
316
+ if (type === 'request') {
317
+ return validateStudioRequestTrace(payload);
318
+ }
319
+ if (type === 'timing') {
320
+ const timing = validateTiming(payload);
321
+ if (!timing) {
322
+ throw new Error('Invalid Studio live timing event payload.');
323
+ }
324
+ return timing;
325
+ }
326
+ if (type === 'diagnostic') {
327
+ return validateStudioLiveDiagnostic(payload);
328
+ }
329
+ if (type === 'heartbeat') {
330
+ if (!isRecord(payload)) {
331
+ throw new Error('Invalid Studio live heartbeat payload.');
332
+ }
333
+ const uptimeMs = validateOptionalNumber(payload.uptimeMs, 'Invalid Studio live heartbeat uptime payload.');
334
+ return uptimeMs === undefined ? {} : {
335
+ uptimeMs
336
+ };
337
+ }
338
+ if (type === 'restart') {
339
+ return validateStudioRestartPayload(payload);
340
+ }
341
+ if (type === 'disconnect') {
342
+ return validateStudioDisconnectPayload(payload);
343
+ }
344
+ throw new Error('Invalid Studio live event type payload.');
345
+ }
346
+
347
+ /**
348
+ * Validates a runtime-connected Studio event envelope.
349
+ *
350
+ * @param value Candidate event parsed from JSON or received through SSE.
351
+ * @returns The typed Studio live event.
352
+ * @throws Error when the event does not match the live Studio contract.
353
+ */
354
+ export function validateStudioLiveEvent(value) {
355
+ if (!isRecord(value) || value.version !== 1 || !isNumber(value.sequence)) {
356
+ throw new Error('Invalid Studio live event payload.');
357
+ }
358
+ const type = value.type;
359
+ const payload = validateStudioLiveEventPayload(type, value.payload);
360
+ const eventBase = {
361
+ emittedAt: validateString(value.emittedAt, 'Invalid Studio live event payload.'),
362
+ epoch: validateString(value.epoch, 'Invalid Studio live event payload.'),
363
+ eventId: validateString(value.eventId, 'Invalid Studio live event payload.'),
364
+ sequence: value.sequence,
365
+ source: validateStudioLiveEventSource(value.source),
366
+ version: 1
367
+ };
368
+ if (type === 'snapshot') {
369
+ return {
370
+ ...eventBase,
371
+ payload: payload,
372
+ type
373
+ };
374
+ }
375
+ if (type === 'request') {
376
+ return {
377
+ ...eventBase,
378
+ payload: payload,
379
+ type
380
+ };
381
+ }
382
+ if (type === 'timing') {
383
+ return {
384
+ ...eventBase,
385
+ payload: payload,
386
+ type
387
+ };
388
+ }
389
+ if (type === 'diagnostic') {
390
+ return {
391
+ ...eventBase,
392
+ payload: payload,
393
+ type
394
+ };
395
+ }
396
+ if (type === 'restart') {
397
+ return {
398
+ ...eventBase,
399
+ payload: payload,
400
+ type
401
+ };
402
+ }
403
+ if (type === 'disconnect') {
404
+ return {
405
+ ...eventBase,
406
+ payload: payload,
407
+ type
408
+ };
409
+ }
410
+ return {
411
+ ...eventBase,
412
+ payload: payload,
413
+ type: 'heartbeat'
414
+ };
415
+ }
416
+
417
+ /**
418
+ * Parses a live Studio event JSON envelope from the runtime sidecar stream.
419
+ *
420
+ * @param rawJson Raw JSON encoded event.
421
+ * @returns The validated Studio live event.
422
+ */
423
+ export function parseStudioLiveEvent(rawJson) {
424
+ return validateStudioLiveEvent(JSON.parse(rawJson));
425
+ }
426
+
427
+ /**
428
+ * Runtime-safe type guard for Studio live event envelopes.
429
+ *
430
+ * @param value Candidate value.
431
+ * @returns `true` when the value matches the live Studio event contract.
432
+ */
433
+ export function isStudioLiveEvent(value) {
434
+ try {
435
+ validateStudioLiveEvent(value);
436
+ return true;
437
+ } catch {
438
+ return false;
439
+ }
440
+ }
47
441
  function validateSnapshot(value) {
48
442
  if (!isRecord(value)) {
49
443
  return null;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { applyFilters, parseStudioPayload, renderMermaid, type FilterState, type ParsedPayload, type PlatformDiagnosticIssue, type PlatformDiagnosticSeverity, type PlatformReadinessStatus, type StudioReportArtifact, type StudioReportSummary, type PlatformShellSnapshot, type StudioPayload, } from './contracts.js';
1
+ export { applyFilters, parseStudioLiveEvent, parseStudioPayload, renderMermaid, validateStudioLiveEvent, isStudioLiveEvent, type FilterState, type ParsedPayload, type PlatformDiagnosticIssue, type PlatformDiagnosticSeverity, type PlatformReadinessStatus, type StudioReportArtifact, type StudioReportSummary, type PlatformShellSnapshot, type StudioPayload, type StudioConnectionState, type StudioConnectionStatus, type StudioDisconnectPayload, type StudioGraphEdge, type StudioGraphEdgeKind, type StudioGraphNode, type StudioGraphNodeKind, type StudioHeartbeatPayload, type StudioLiveDiagnostic, type StudioLiveEvent, type StudioLiveEventBase, type StudioLiveEventSource, type StudioLiveSnapshot, type StudioRequestStatus, type StudioRequestTrace, type StudioRestartPayload, type StudioRouteDescriptor, } from './contracts.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,gBAAgB,CAAC"}
package/dist/index.html CHANGED
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Fluo Studio</title>
7
- <script type="module" crossorigin src="./assets/index-BOSlyIRm.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-RQNFORxf.css">
7
+ <script type="module" crossorigin src="./assets/index-AjSkQOVN.js"></script>
8
+ <link rel="stylesheet" crossorigin href="./assets/index-ort96Zw9.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="app"></div>
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { applyFilters, parseStudioPayload, renderMermaid } from './contracts.js';
1
+ export { applyFilters, parseStudioLiveEvent, parseStudioPayload, renderMermaid, validateStudioLiveEvent, isStudioLiveEvent } from './contracts.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluojs/studio",
3
- "description": "File-first diagnostics viewer for Fluo runtime platform snapshot and timing JSON exports.",
3
+ "description": "Runtime-connected React devtool for Fluo apps with static diagnostics report compatibility.",
4
4
  "keywords": [
5
5
  "fluo",
6
6
  "studio",
@@ -9,7 +9,7 @@
9
9
  "module-graph",
10
10
  "devtools"
11
11
  ],
12
- "version": "1.0.4",
12
+ "version": "1.0.6",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -41,9 +41,13 @@
41
41
  "dist"
42
42
  ],
43
43
  "dependencies": {
44
- "@fluojs/runtime": "^1.1.2"
44
+ "react": "^19.2.6",
45
+ "react-dom": "^19.2.6",
46
+ "@fluojs/runtime": "^1.1.6"
45
47
  },
46
48
  "devDependencies": {
49
+ "@types/react": "^19.2.14",
50
+ "@types/react-dom": "^19.2.3",
47
51
  "happy-dom": "^20.9.0",
48
52
  "vitest": "^3.2.4",
49
53
  "@fluojs-internal/tooling-vite": "^0.0.1"