@codeyam-editor/codeyam-editor 0.1.0-staging.27ed016

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.
package/npm/utils.js ADDED
@@ -0,0 +1,356 @@
1
+ const { execSync, spawn, spawnSync } = require("child_process");
2
+ const net = require("net");
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+
6
+ const rootDir = path.resolve(__dirname, "..");
7
+ const serverStatePath = path.join(rootDir, ".codeyam", "server-state.json");
8
+
9
+ /**
10
+ * Map (process.platform, process.arch) → the platform sub-package that
11
+ * carries the matching native binary. Kept as a small data table so adding
12
+ * a new platform (e.g. linux/arm64) is one entry, not a new branch.
13
+ */
14
+ const PLATFORM_PACKAGES = {
15
+ "darwin-arm64": { pkg: "@codeyam-editor/codeyam-editor-darwin-arm64", binary: "codeyam-editor" },
16
+ "darwin-x64": { pkg: "@codeyam-editor/codeyam-editor-darwin-x64", binary: "codeyam-editor" },
17
+ "linux-x64": { pkg: "@codeyam-editor/codeyam-editor-linux-x64", binary: "codeyam-editor" },
18
+ "win32-x64": { pkg: "@codeyam-editor/codeyam-editor-win32-x64", binary: "codeyam-editor.exe" },
19
+ };
20
+
21
+ /**
22
+ * Platform-correct executable filename for the codeyam-editor binary.
23
+ * Windows requires the `.exe` extension; on Unix the binary has no extension.
24
+ * Accepts an explicit platform so the helper is testable across platforms.
25
+ */
26
+ function binaryName(platform = process.platform) {
27
+ return platform === "win32" ? "codeyam-editor.exe" : "codeyam-editor";
28
+ }
29
+
30
+ /** Look up the platform sub-package metadata for a given platform/arch pair. */
31
+ function platformPackageInfo(platform = process.platform, arch = process.arch) {
32
+ return PLATFORM_PACKAGES[`${platform}-${arch}`] || null;
33
+ }
34
+
35
+ /**
36
+ * Resolve the native binary path.
37
+ *
38
+ * Production install (npm install @codeyam-editor/codeyam-editor):
39
+ * npm installed the matching @codeyam-editor/codeyam-editor-<plat>-<arch>
40
+ * sub-package via optionalDependencies. require.resolve finds the binary
41
+ * inside that sibling package.
42
+ *
43
+ * Dev checkout (`cargo build` in the repo):
44
+ * No platform sub-package installed; fall through to target/debug or
45
+ * target/release.
46
+ *
47
+ * Returns null if no binary can be found at any of these locations — the
48
+ * caller (ensureBinary / cli.js) decides whether to error or to invoke
49
+ * `cargo build` based on whether a Cargo.toml is present.
50
+ */
51
+ function findBinary() {
52
+ const info = platformPackageInfo();
53
+ if (info) {
54
+ try {
55
+ const resolved = require.resolve(`${info.pkg}/bin/${info.binary}`, {
56
+ paths: [rootDir],
57
+ });
58
+ if (fs.existsSync(resolved)) return resolved;
59
+ } catch (e) {
60
+ if (e.code !== "MODULE_NOT_FOUND") throw e;
61
+ }
62
+ }
63
+
64
+ const name = binaryName();
65
+ const devCandidates = [
66
+ path.join(rootDir, "target", "debug", name),
67
+ path.join(rootDir, "target", "release", name),
68
+ ];
69
+ for (const candidate of devCandidates) {
70
+ if (fs.existsSync(candidate)) return candidate;
71
+ }
72
+
73
+ return null;
74
+ }
75
+
76
+ /**
77
+ * Return the binary path, building from source if we're in a dev checkout.
78
+ *
79
+ * Production install: if findBinary returns null, the platform sub-package
80
+ * is missing — npm install failed silently (likely because the user's
81
+ * platform isn't in the build matrix). Emit a clear, actionable error
82
+ * naming the expected sub-package, and exit 1. **Do not** fall through to
83
+ * `cargo build` — there's no Cargo.toml in the npm install dir, and the
84
+ * resulting "could not find Cargo.toml" error is misleading to users.
85
+ *
86
+ * Dev checkout: `Cargo.toml` is present at rootDir → run `cargo build`,
87
+ * same as the legacy behavior.
88
+ */
89
+ function ensureBinary() {
90
+ const existing = findBinary();
91
+ if (existing) return existing;
92
+
93
+ const isDevCheckout = fs.existsSync(path.join(rootDir, "Cargo.toml"));
94
+
95
+ if (!isDevCheckout) {
96
+ const info = platformPackageInfo();
97
+ if (!info) {
98
+ console.error(
99
+ `codeyam-editor: unsupported platform ${process.platform}/${process.arch}.\n` +
100
+ `Supported: darwin/arm64, darwin/x64, linux/x64, win32/x64.`
101
+ );
102
+ } else {
103
+ console.error(
104
+ `codeyam-editor: native binary missing.\n` +
105
+ `Expected at ${info.pkg}/bin/${info.binary} — npm should have installed ` +
106
+ `that sub-package as an optionalDependency.\n` +
107
+ `Try: npm install --force ${info.pkg}@$(npm view @codeyam-editor/codeyam-editor version)`
108
+ );
109
+ }
110
+ process.exit(1);
111
+ }
112
+
113
+ try {
114
+ execSync("cargo --version", { stdio: "ignore" });
115
+ } catch {
116
+ console.error(
117
+ "codeyam-editor binary not found and `cargo` is not on PATH. " +
118
+ "Install Rust from https://rustup.rs/ or reinstall @codeyam-editor/codeyam-editor."
119
+ );
120
+ process.exit(1);
121
+ }
122
+
123
+ console.error("Building codeyam-editor...");
124
+ try {
125
+ execSync("cargo build", { cwd: rootDir, stdio: "inherit" });
126
+ } catch {
127
+ console.error("Failed to build. Is Rust installed? https://rustup.rs/");
128
+ process.exit(1);
129
+ }
130
+
131
+ const binary = findBinary();
132
+ if (!binary) {
133
+ console.error("Binary not found after build.");
134
+ process.exit(1);
135
+ }
136
+ return binary;
137
+ }
138
+
139
+ /** Resolve the UI dist directory for the binary to serve. */
140
+ function uiDistDir() {
141
+ return path.join(rootDir, "ui", "dist");
142
+ }
143
+
144
+ /** Try to connect to a specific host:port. Returns true if something is listening. */
145
+ function tryConnect(port, host) {
146
+ return new Promise((resolve) => {
147
+ const socket = new net.Socket();
148
+ socket.setTimeout(300);
149
+ socket.once("connect", () => { socket.destroy(); resolve(true); });
150
+ socket.once("error", () => { socket.destroy(); resolve(false); });
151
+ socket.once("timeout", () => { socket.destroy(); resolve(false); });
152
+ socket.connect(port, host);
153
+ });
154
+ }
155
+
156
+ /** Check if a port is in use (tries both IPv4 and IPv6). */
157
+ async function isPortInUse(port) {
158
+ return (await tryConnect(port, "127.0.0.1")) || (await tryConnect(port, "::1"));
159
+ }
160
+
161
+ /**
162
+ * Poll a port until something is listening, or timeout.
163
+ * Returns true if the port became active, false on timeout.
164
+ */
165
+ async function waitForPort(port, timeoutMs = 10000, intervalMs = 200) {
166
+ const deadline = Date.now() + timeoutMs;
167
+ while (Date.now() < deadline) {
168
+ if (await isPortInUse(port)) return true;
169
+ await new Promise((r) => setTimeout(r, intervalMs));
170
+ }
171
+ return false;
172
+ }
173
+
174
+ /**
175
+ * Poll until a port stops listening, or timeout.
176
+ * Returns true if the port became inactive, false on timeout.
177
+ */
178
+ async function waitForPortToClose(port, timeoutMs = 10000, intervalMs = 200) {
179
+ const deadline = Date.now() + timeoutMs;
180
+ while (Date.now() < deadline) {
181
+ if (!(await isPortInUse(port))) return true;
182
+ await new Promise((r) => setTimeout(r, intervalMs));
183
+ }
184
+ return false;
185
+ }
186
+
187
+ function readServerState() {
188
+ try {
189
+ return JSON.parse(fs.readFileSync(serverStatePath, "utf8"));
190
+ } catch {
191
+ return null;
192
+ }
193
+ }
194
+
195
+ function clearServerState() {
196
+ try {
197
+ fs.unlinkSync(serverStatePath);
198
+ } catch {}
199
+ }
200
+
201
+ async function requestServerShutdown(port = 14199, timeoutMs = 1500) {
202
+ const controller = new AbortController();
203
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
204
+
205
+ try {
206
+ const resp = await fetch(`http://127.0.0.1:${port}/api/editor-server/shutdown`, {
207
+ method: "POST",
208
+ signal: controller.signal,
209
+ });
210
+ return resp.ok;
211
+ } catch {
212
+ return false;
213
+ } finally {
214
+ clearTimeout(timeout);
215
+ }
216
+ }
217
+
218
+ function tryKillPid(pid) {
219
+ try {
220
+ // On Windows, `process.kill(pid, "SIGINT")` either errors or no-ops
221
+ // depending on Node version. Drop the signal so Node maps to a
222
+ // platform TerminateProcess. Less graceful, but the child does exit.
223
+ if (process.platform === "win32") {
224
+ process.kill(pid);
225
+ } else {
226
+ process.kill(pid, "SIGINT");
227
+ }
228
+ return true;
229
+ } catch {
230
+ return false;
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Send the platform-correct termination signal to a spawned child process.
236
+ * Used by editor.js / editor-dev.js / container.js when the user hits Ctrl+C —
237
+ * `child.kill("SIGINT")` is unreliable on Windows.
238
+ */
239
+ function killChildProcess(child) {
240
+ if (!child) return;
241
+ if (process.platform === "win32") {
242
+ child.kill();
243
+ } else {
244
+ child.kill("SIGINT");
245
+ }
246
+ }
247
+
248
+ function findListeningPids(port) {
249
+ // Process discovery on Windows is best-effort — `lsof` is not installed and
250
+ // a `netstat -ano` parser is a follow-up. The API-shutdown path and the
251
+ // PID-file path together stop the server cleanly in normal operation.
252
+ if (process.platform === "win32") return [];
253
+
254
+ const result = spawnSync("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
255
+ encoding: "utf8",
256
+ });
257
+
258
+ if (result.error) return [];
259
+
260
+ return result.stdout
261
+ .split(/\s+/)
262
+ .map((line) => parseInt(line, 10))
263
+ .filter((pid) => Number.isInteger(pid));
264
+ }
265
+
266
+ /** Stop the Rust backend server if it is running. */
267
+ async function stopServer(port = 14199) {
268
+ if (!(await isPortInUse(port))) {
269
+ clearServerState();
270
+ return false;
271
+ }
272
+
273
+ if (await requestServerShutdown(port)) {
274
+ if (await waitForPortToClose(port, 10000, 200)) {
275
+ clearServerState();
276
+ return true;
277
+ }
278
+ }
279
+
280
+ const state = readServerState();
281
+ if (state && Number.isInteger(state.pid) && tryKillPid(state.pid)) {
282
+ if (await waitForPortToClose(port, 5000, 200)) {
283
+ clearServerState();
284
+ return true;
285
+ }
286
+ }
287
+
288
+ for (const pid of findListeningPids(port)) {
289
+ tryKillPid(pid);
290
+ }
291
+
292
+ if (await waitForPortToClose(port, 5000, 200)) {
293
+ clearServerState();
294
+ return true;
295
+ }
296
+
297
+ throw new Error(`Server on port ${port} did not stop cleanly`);
298
+ }
299
+
300
+ /** Stop any existing server on the port, then start a fresh one. */
301
+ async function restartServer(port = 14199) {
302
+ if (await isPortInUse(port)) {
303
+ console.error(`Stopping existing server on port ${port}...`);
304
+ await stopServer(port);
305
+ }
306
+ return ensureServer(port);
307
+ }
308
+
309
+ /** Start the Rust backend server if not already running. Returns the child process (or null if already running). */
310
+ async function ensureServer(port = 14199) {
311
+ if (await isPortInUse(port)) {
312
+ console.error(`Server already running on port ${port}`);
313
+ return null;
314
+ }
315
+
316
+ const binary = ensureBinary();
317
+ const child = spawn(binary, ["start", "--no-open", "--port", String(port)], {
318
+ stdio: "inherit",
319
+ cwd: process.cwd(),
320
+ detached: false,
321
+ env: { ...process.env, CODEYAM_EDITOR_UI_DIR: uiDistDir() },
322
+ });
323
+
324
+ const ready = await waitForPort(port);
325
+ if (!ready) {
326
+ console.error("Server failed to start within 10 seconds");
327
+ child.kill();
328
+ process.exit(1);
329
+ }
330
+
331
+ return child;
332
+ }
333
+
334
+ module.exports = {
335
+ rootDir,
336
+ serverStatePath,
337
+ binaryName,
338
+ platformPackageInfo,
339
+ PLATFORM_PACKAGES,
340
+ findBinary,
341
+ ensureBinary,
342
+ uiDistDir,
343
+ tryConnect,
344
+ isPortInUse,
345
+ waitForPort,
346
+ waitForPortToClose,
347
+ readServerState,
348
+ clearServerState,
349
+ requestServerShutdown,
350
+ tryKillPid,
351
+ findListeningPids,
352
+ stopServer,
353
+ restartServer,
354
+ ensureServer,
355
+ killChildProcess,
356
+ };
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@codeyam-editor/codeyam-editor",
3
+ "version": "0.1.0-staging.27ed016",
4
+ "description": "Language-agnostic managed execution sandbox for scenario-driven development",
5
+ "bin": {
6
+ "codeyam-editor": "./npm/cli.js"
7
+ },
8
+ "dependencies": {
9
+ "playwright": "^1.58.2"
10
+ },
11
+ "optionalDependencies": {
12
+ "@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.0-staging.27ed016",
13
+ "@codeyam-editor/codeyam-editor-darwin-x64": "0.1.0-staging.27ed016",
14
+ "@codeyam-editor/codeyam-editor-linux-x64": "0.1.0-staging.27ed016",
15
+ "@codeyam-editor/codeyam-editor-win32-x64": "0.1.0-staging.27ed016"
16
+ },
17
+ "keywords": [
18
+ "codeyam",
19
+ "editor",
20
+ "development",
21
+ "scenarios"
22
+ ],
23
+ "homepage": "https://codeyam.com/",
24
+ "license": "MIT",
25
+ "engines": {
26
+ "node": ">=20.0.0"
27
+ },
28
+ "files": [
29
+ "npm/",
30
+ "ui/"
31
+ ]
32
+ }
@@ -0,0 +1,2 @@
1
+ import{j as e}from"./markdown-v0F0UEt3.js";import{b as a}from"./react-CSS0HapR.js";import{u as T}from"./useEvents-DggWrtHe.js";function M({connected:t}){return e.jsx("span",{className:`inline-block rounded-full px-2 py-0.5 text-xs font-medium text-[var(--text-primary)] ${t?"bg-[var(--accent-green)]":"bg-[var(--accent-red)]"}`,children:t?"connected":"reconnecting…"})}function P(){const[t,s]=a.useState(null),[n,r]=a.useState(!0),{events:l}=T(),o=a.useCallback(async()=>{try{const c=await(await fetch("/api/inspector/status")).json();s(c)}catch{}finally{r(!1)}},[]);return a.useEffect(()=>{o()},[o]),a.useEffect(()=>{const i=l[l.length-1];i&&i.type==="scenario_switch"&&o()},[l,o]),{scenario:(t==null?void 0:t.scenario)??null,previewScenario:(t==null?void 0:t.previewScenario)??null,routes:(t==null?void 0:t.routes)??[],routeCount:(t==null?void 0:t.routeCount)??0,loading:n,refetch:o}}function k({title:t}){return e.jsx("h2",{style:{fontSize:14,fontWeight:600,color:"#f0f6fc",margin:"0 0 8px 0",borderBottom:"1px solid #30363d",paddingBottom:8},children:t})}function f({color:t,children:s}){return e.jsx("span",{style:{background:`${t}22`,color:t,border:`1px solid ${t}55`,borderRadius:4,padding:"2px 8px",fontSize:11,fontWeight:600,letterSpacing:"0.5px",whiteSpace:"nowrap"},children:s})}const z={GET:"#58a6ff",POST:"#238636",PUT:"#d29922",DELETE:"#da3633",PATCH:"#bc8cff"};function L({method:t}){const s=z[t.toUpperCase()]??"#8b949e";return e.jsx("span",{style:{color:s,fontWeight:600,fontSize:11,minWidth:48,display:"inline-block"},children:t.toUpperCase()})}function E({color:t,children:s}){return e.jsx("div",{style:{padding:"12px 16px",borderRadius:6,border:`1px solid ${t}44`,background:`${t}11`,color:t},children:s})}const h={padding:"8px 12px",textAlign:"center",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px"},u={padding:"6px 12px"},w={background:"#161b22",border:"1px solid #30363d",borderRadius:6,color:"#c9d1d9",padding:"6px 12px",fontSize:13,fontFamily:"inherit"},B={...w,appearance:"none",paddingRight:24,backgroundImage:`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238b949e' d='M6 8L1 3h10z'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 8px center"};function O({routes:t}){return e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d"},children:[e.jsx("th",{style:h,children:"Method"}),e.jsx("th",{style:{...h,textAlign:"left"},children:"Pattern"}),e.jsx("th",{style:h,children:"Status"})]})}),e.jsx("tbody",{children:t.map((s,n)=>e.jsxs("tr",{style:{borderBottom:"1px solid #21262d"},children:[e.jsx("td",{style:{...u,textAlign:"center"},children:e.jsx(L,{method:s.method})}),e.jsx("td",{style:u,children:s.pattern}),e.jsx("td",{style:{...u,textAlign:"center",color:"#8b949e"},children:s.status})]},n))})]})}function I(){const{scenario:t,previewScenario:s,routes:n,routeCount:r,loading:l}=P();return e.jsxs("section",{children:[e.jsx(k,{title:"Active Scenario"}),l?e.jsx(E,{color:"#8b949e",children:"Loading..."}):t?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(f,{color:"#238636",children:"ACTIVE"}),e.jsx("span",{style:{color:"#f0f6fc",fontWeight:500},children:t.name}),e.jsxs("span",{style:{color:"#8b949e"},children:["(",t.slug,")"]})]}),e.jsxs("div",{style:{color:"#8b949e",fontSize:12},children:[r," mock route",r!==1?"s":""," loaded"]}),n.length>0&&e.jsx(O,{routes:n})]}):s?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(f,{color:"#58a6ff",children:"PREVIEW"}),e.jsx("span",{style:{color:"#f0f6fc",fontWeight:500},children:s.name}),e.jsxs("span",{style:{color:"#8b949e"},children:["(",s.slug,")"]})]}),e.jsx("div",{style:{color:"#8b949e",fontSize:12},children:"Component preview — no HTTP mocks active"})]}):e.jsx(E,{color:"#d29922",children:"No scenario active — all requests pass through to upstream"})]})}function A(t){try{return new URL(t).pathname}catch{return t}}function H({textUrlFilter:t,onTextUrlFilterChange:s,methodFilter:n,onMethodFilterChange:r,sourceFilter:l,onSourceFilterChange:o}){return e.jsxs("div",{style:{display:"flex",gap:8,marginBottom:12,alignItems:"center"},children:[e.jsx("input",{type:"text",placeholder:"Filter by URL...",value:t,onChange:i=>s(i.target.value),style:{...w,flex:1,minWidth:0}}),e.jsxs("select",{value:n,onChange:i=>r(i.target.value),style:B,children:[e.jsx("option",{value:"ALL",children:"All Methods"}),e.jsx("option",{value:"GET",children:"GET"}),e.jsx("option",{value:"POST",children:"POST"}),e.jsx("option",{value:"PUT",children:"PUT"}),e.jsx("option",{value:"DELETE",children:"DELETE"}),e.jsx("option",{value:"PATCH",children:"PATCH"})]}),e.jsxs("select",{value:l,onChange:i=>o(i.target.value),style:B,children:[e.jsx("option",{value:"ALL",children:"All Sources"}),e.jsx("option",{value:"MOCKED",children:"Mocked"}),e.jsx("option",{value:"PASSTHROUGH",children:"Passthrough"})]})]})}const U={color:"#8b949e",fontSize:11,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.5px",marginBottom:4},R={background:"#161b22",border:"1px solid #30363d",borderRadius:4,padding:"8px 12px",margin:0,fontSize:11,color:"#c9d1d9",fontFamily:"monospace",maxHeight:200,overflow:"auto",whiteSpace:"pre-wrap",wordBreak:"break-all"};function v({label:t,children:s}){return e.jsxs("div",{style:{marginBottom:12},children:[e.jsx("div",{style:U,children:t}),s]})}function W({event:t}){let s=[];try{const o=new URL(t.url,"http://localhost");s=Array.from(o.searchParams.entries())}catch{}const n=t.requestHeaders&&Object.keys(t.requestHeaders).length>0,r=t.requestBody!=null,l=t.responseBody!=null;return e.jsxs("div",{style:{background:"#0d1117",padding:"12px 16px",borderTop:"1px solid #30363d"},children:[s.length>0&&e.jsx(v,{label:"Query Parameters",children:e.jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"2px 12px",fontSize:12},children:s.map(([o,i],c)=>e.jsxs("div",{style:{display:"contents"},children:[e.jsx("span",{style:{color:"#58a6ff",fontFamily:"monospace"},children:o}),e.jsx("span",{style:{color:"#c9d1d9",fontFamily:"monospace"},children:i})]},c))})}),n&&e.jsx(v,{label:"Request Headers",children:e.jsx("pre",{style:R,children:Object.entries(t.requestHeaders).map(([o,i])=>`${o}: ${i}`).join(`
2
+ `)})}),r&&e.jsx(v,{label:"Request Body",children:e.jsx("pre",{style:R,children:typeof t.requestBody=="string"?t.requestBody:JSON.stringify(t.requestBody,null,2)})}),l&&e.jsx(v,{label:"Response Body",children:e.jsx("pre",{style:R,children:typeof t.responseBody=="string"?t.responseBody:JSON.stringify(t.responseBody,null,2)})}),s.length===0&&!n&&!r&&!l&&e.jsx("div",{style:{color:"#8b949e",fontSize:12},children:"No additional details available for this request"})]})}function F({event:t}){const[s,n]=a.useState(!1),r=new Date(t.timestampMs).toLocaleTimeString(),l=t.mocked;return e.jsxs(e.Fragment,{children:[e.jsxs("tr",{onClick:()=>n(!s),style:{borderBottom:"1px solid #21262d",background:l?"transparent":"rgba(210, 153, 34, 0.05)",cursor:"pointer"},children:[e.jsxs("td",{style:{...u,color:"#8b949e",textAlign:"center"},children:[e.jsx("span",{style:{display:"inline-block",width:12,marginRight:4,fontSize:10,color:"#8b949e",transition:"transform 0.15s",transform:s?"rotate(90deg)":"rotate(0deg)"},children:"▶"}),r]}),e.jsx("td",{style:{...u,textAlign:"center"},children:e.jsx(L,{method:t.method})}),e.jsx("td",{style:{...u,maxWidth:400,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.url}),e.jsx("td",{style:{...u,textAlign:"center",color:"#8b949e"},children:t.status??"---"}),e.jsxs("td",{style:{...u,textAlign:"center",color:"#8b949e"},children:[t.durationMs,"ms"]}),e.jsx("td",{style:{...u,textAlign:"center"},children:l?t.mockSource==="default"?e.jsx(f,{color:"#1f6feb",children:"MOCKED (default)"}):e.jsx(f,{color:"#238636",children:"MOCKED (scenario)"}):e.jsx(f,{color:"#d29922",children:"PASSTHROUGH"})})]}),s&&e.jsx("tr",{children:e.jsx("td",{colSpan:6,style:{padding:0},children:e.jsx(W,{event:t})})})]})}function D({events:t}){return e.jsx("div",{style:{maxHeight:300,overflowY:"auto",border:"1px solid #30363d",borderRadius:6},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d",position:"sticky",top:0,background:"#0d1117"},children:[e.jsx("th",{style:h,children:"Time"}),e.jsx("th",{style:h,children:"Method"}),e.jsx("th",{style:{...h,textAlign:"left"},children:"URL"}),e.jsx("th",{style:h,children:"Status"}),e.jsx("th",{style:h,children:"Duration"}),e.jsx("th",{style:h,children:"Source"})]})}),e.jsx("tbody",{children:t.map(s=>e.jsx(F,{event:s},s.id))})]})})}function q(t){if(t===void 0)return"checked";if(t==="checked")return"excluded"}function $({chips:t,chipStates:s,onChipStatesChange:n}){if(t.length===0)return null;const r=o=>{const i=new Map(s),c=q(i.get(o));c===void 0?i.delete(o):i.set(o,c),n(i)},l=()=>{n(new Map)};return e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:6,marginBottom:12},children:[s.size>0&&e.jsx("button",{onClick:l,style:{background:"#da363322",color:"#da3633",border:"1px solid #da363355",borderRadius:4,padding:"2px 8px",fontSize:11,fontWeight:600,cursor:"pointer",fontFamily:"inherit"},children:"Clear all"}),t.map(({path:o,count:i})=>{const c=s.get(o),d=c==="checked",g=c==="excluded";let j="#30363d",b="#8b949e",S="#30363d",y="";return d?(j="#58a6ff22",b="#58a6ff",S="#58a6ff55",y="✓ "):g&&(j="#da363322",b="#da3633",S="#da363355",y="✗ "),e.jsxs("button",{onClick:()=>r(o),style:{background:j,color:b,border:`1px solid ${S}`,borderRadius:4,padding:"2px 8px",fontSize:11,fontFamily:"monospace",cursor:"pointer",whiteSpace:"nowrap"},children:[y,o,e.jsxs("span",{style:{marginLeft:4,opacity:.6,fontFamily:"inherit"},children:["(",i,")"]})]},o)})]})}function N(){const{events:t}=T(),[s,n]=a.useState(""),[r,l]=a.useState(()=>new Map),[o,i]=a.useState("ALL"),[c,d]=a.useState("ALL"),g=t.filter(p=>p.type==="http_request"),j=a.useMemo(()=>{const p=new Map;for(const x of g){const m=A(x.url);p.set(m,(p.get(m)||0)+1)}return Array.from(p.entries()).sort((x,m)=>m[1]-x[1]).slice(0,10).map(([x,m])=>({path:x,count:m}))},[g]),b=a.useMemo(()=>Array.from(r.values()).some(p=>p==="checked"),[r]),y=g.filter(p=>{if(s&&!p.url.toLowerCase().includes(s.toLowerCase()))return!1;const x=A(p.url);return!(r.get(x)==="excluded"||b&&r.get(x)!=="checked"||o!=="ALL"&&p.method.toUpperCase()!==o||c==="MOCKED"&&!p.mocked||c==="PASSTHROUGH"&&p.mocked)}).slice(-50).reverse();return e.jsxs("section",{children:[e.jsx(k,{title:"Live Traffic"}),e.jsx(H,{textUrlFilter:s,onTextUrlFilterChange:n,methodFilter:o,onMethodFilterChange:i,sourceFilter:c,onSourceFilterChange:p=>d(p)}),e.jsx($,{chips:j,chipStates:r,onChipStatesChange:l}),y.length===0?e.jsx(E,{color:"#8b949e",children:g.length>0?"No matching traffic — try adjusting the filters":"No HTTP traffic yet — requests will appear here in real-time"}):e.jsx(D,{events:y})]})}function G(){const[t,s]=a.useState(null),[n,r]=a.useState(!1);return{explain:a.useCallback(async(o,i)=>{r(!0);try{const d=await(await fetch("/api/inspector/explain",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({method:o,url:i})})).json();s(d)}catch{}finally{r(!1)}},[]),result:t,loading:n}}function _({result:t}){return e.jsxs("div",{style:{border:"1px solid #30363d",borderRadius:6,padding:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:12},children:[e.jsxs("span",{style:{color:"#f0f6fc",fontWeight:500},children:[t.method," ",t.url]}),t.wouldMatch?e.jsx(f,{color:"#238636",children:"WOULD MATCH"}):e.jsx(f,{color:"#da3633",children:"NO MATCH"})]}),t.attempts.length===0?e.jsx("div",{style:{color:"#8b949e"},children:"No routes loaded to match against"}):e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:6},children:t.attempts.map((s,n)=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 8px",borderRadius:4,background:s.failure?"transparent":"rgba(35, 134, 54, 0.1)"},children:[e.jsx("span",{style:{color:s.failure?"#da3633":"#238636",fontWeight:600,width:16},children:s.failure?"x":"v"}),e.jsx(L,{method:s.method}),e.jsx("span",{children:s.pattern}),s.failure&&e.jsx("span",{style:{color:"#8b949e",fontSize:11},children:s.failure.reason==="methodMismatch"?`method: expected ${s.failure.expected}, got ${s.failure.actual}`:`path "${s.failure.path}" does not match "${s.failure.pattern}"`})]},n))})]})}function K(){const{explain:t,result:s,loading:n}=G(),[r,l]=a.useState("GET"),[o,i]=a.useState(""),c=d=>{d.preventDefault(),o.trim()&&t(r,o.trim())};return e.jsxs("section",{children:[e.jsx(k,{title:"Match Explainer"}),e.jsxs("form",{onSubmit:c,style:{display:"flex",gap:8,marginBottom:12},children:[e.jsx("select",{value:r,onChange:d=>l(d.target.value),style:{...w,width:100},children:["GET","POST","PUT","DELETE","PATCH"].map(d=>e.jsx("option",{value:d,children:d},d))}),e.jsx("input",{type:"text",value:o,onChange:d=>i(d.target.value),placeholder:"/api/users",style:{...w,flex:1}}),e.jsx("button",{type:"submit",disabled:n||!o.trim(),style:{background:"#238636",color:"#fff",border:"none",borderRadius:6,padding:"6px 16px",cursor:"pointer",fontSize:12,fontWeight:500,opacity:n||!o.trim()?.5:1},children:n?"Checking...":"Explain"})]}),s&&e.jsx(_,{result:s})]})}const C={"/api/health":"Health check — confirms the proxy and mock engine are running","/api/events":"SSE stream of real-time events (traffic, errors) powering this Inspector","/api/config":"Returns current CodeYam configuration for the project","/api/editor-dev-server":"Polls/controls the dev server status (start, stop, restart)","/api/inspector/status":"Returns active scenario and loaded mock routes","/api/inspector/explain":"Tests which mock route would match a given method + URL","/api/scenarios":"Lists all defined scenarios with metadata","/api/tests":"Returns the AI-maintained test registry joined with per-test-evidence, grouped by file","/api/test-results":"Returns latest test execution results","/api/screenshots/*":"Serves captured scenario screenshots","/api/session-info":"Returns current editor session metadata","/api/data-structure":"Returns the app's data structure definition","/api/dependency-graph":"Returns the project's component dependency graph","/api/app-route-entities":"Lists app routes and their associated entities","/api/glossary":"Returns the project's component glossary","/api/step":"Returns current editor workflow step","/api/editor-commands":"Lists available editor commands"};function J(t){if(C[t])return C[t];for(const[s,n]of Object.entries(C))if(s.endsWith("/*")){const r=s.slice(0,-1);if(t.startsWith(r))return n}}function V(t){const s=new Set([...t,...Object.keys(C)]),n=[];for(const r of Array.from(s).sort()){if(r.endsWith("/*"))continue;const l=J(r);n.push({path:r,description:l??"Application endpoint"})}return n}function Y(){const{events:t}=T(),s=a.useMemo(()=>{const n=[];for(const r of t)r.type==="http_request"&&n.push(A(r.url));return V(n)},[t]);return s.length===0?null:e.jsxs("section",{children:[e.jsx(k,{title:"URL Glossary"}),e.jsx("div",{style:{border:"1px solid #30363d",borderRadius:6,overflow:"hidden"},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d",background:"#161b22"},children:[e.jsx("th",{style:{padding:"6px 12px",textAlign:"left",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px",width:"30%"},children:"Path"}),e.jsx("th",{style:{padding:"6px 12px",textAlign:"left",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px"},children:"Description"})]})}),e.jsx("tbody",{children:s.map(({path:n,description:r})=>e.jsxs("tr",{style:{borderBottom:"1px solid #21262d"},children:[e.jsx("td",{style:{padding:"4px 12px",fontFamily:"monospace",color:"#58a6ff",fontSize:11},children:n}),e.jsx("td",{style:{padding:"4px 12px",color:"#8b949e"},children:r})]},n))})]})})]})}function Q(){const{connected:t}=T();return e.jsxs("div",{style:{background:"#0d1117",color:"#c9d1d9",minHeight:"100vh",fontFamily:"'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace",fontSize:13,padding:24,display:"flex",flexDirection:"column",gap:24},children:[e.jsxs("header",{style:{display:"flex",alignItems:"center",gap:12},children:[e.jsx("h1",{style:{fontSize:18,fontWeight:600,color:"#f0f6fc",margin:0},children:"Container Inspector"}),e.jsx("span",{style:{color:"#8b949e",fontSize:12},children:"Read-only view of proxy and mock engine state"}),e.jsx(M,{connected:t})]}),e.jsx(I,{}),e.jsx(N,{}),e.jsx(K,{}),e.jsx(Y,{})]})}const te=Object.freeze(Object.defineProperty({__proto__:null,ContainerInspector:Q},Symbol.toStringTag,{value:"Module"}));export{f as B,Q as C,F as I,L as M,k as S,E as a,Y as b,$ as c,D as d,H as e,W as f,_ as g,K as h,N as i,O as j,I as k,M as l,te as m,h as t};