zelune 1.6.3 → 1.6.5

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/bin/cli.mjs +13 -53
  3. package/dist/assets/CheckoutScreen-CoLb16nl.js +229 -0
  4. package/dist/assets/HomeScreen-DtWSrKS1.js +316 -0
  5. package/dist/assets/LoginScreen-C1EtAYek.js +189 -0
  6. package/dist/assets/ProductDetailScreen-a9PXPTEY.js +196 -0
  7. package/dist/assets/ProfileScreen-ChKW9gJP.js +185 -0
  8. package/dist/assets/index-xam7XuSg.js +44764 -0
  9. package/{index.html → dist/index.html} +3 -1
  10. package/mcp/server.mjs +1906 -32
  11. package/package.json +10 -13
  12. package/plugin.json +1 -1
  13. package/socket.yml +11 -0
  14. package/mcp/server.ts +0 -446
  15. package/plugins/viteReactNativeFallbackPlugin.ts +0 -522
  16. package/plugins/viteRnSourceInject.ts +0 -105
  17. package/plugins/viteVirtualScreensPlugin.ts +0 -216
  18. package/src/canvas/CanvasApp.tsx +0 -1655
  19. package/src/canvas/FlowArrowsLayer.tsx +0 -239
  20. package/src/canvas/InspectorPanel.tsx +0 -1494
  21. package/src/canvas/ScreenArtboard.tsx +0 -1491
  22. package/src/canvas/types.ts +0 -23
  23. package/src/main.tsx +0 -80
  24. package/src/runtime/MockNavigationContext.tsx +0 -1869
  25. package/src/runtime/ScreenErrorBoundary.tsx +0 -86
  26. package/src/runtime/nativewindShim.ts +0 -997
  27. package/src/runtime/reactNativeShim.ts +0 -1674
  28. package/src/screens/CheckoutScreen.tsx +0 -229
  29. package/src/screens/HomeScreen.tsx +0 -288
  30. package/src/screens/LoginScreen.tsx +0 -176
  31. package/src/screens/ProductDetailScreen.tsx +0 -207
  32. package/src/screens/ProfileScreen.tsx +0 -172
  33. package/src/screens/index.ts +0 -1
  34. package/src/server/apiMiddleware.ts +0 -378
  35. package/src/server/astEngine.ts +0 -2624
  36. package/src/vite-env.d.ts +0 -7
  37. package/tsconfig.json +0 -23
  38. package/vite.config.ts +0 -339
  39. /package/{src/styles.css → dist/assets/index-C7nrS82N.css} +0 -0
package/mcp/server.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import fsSync from "node:fs";
1
+ import fs$1 from "node:fs";
2
2
  import path from "node:path";
3
3
  import readline from "node:readline";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -6,7 +6,8 @@ import fs from "node:fs/promises";
6
6
  import { parse } from "@babel/parser";
7
7
  import _generate from "@babel/generator";
8
8
  import * as t from "@babel/types";
9
- const generate = _generate.default ?? _generate;
9
+ import http from "node:http";
10
+ const generate$1 = _generate.default ?? _generate;
10
11
  function getJsxTagName(nameNode) {
11
12
  if (t.isJSXIdentifier(nameNode)) {
12
13
  return nameNode.name;
@@ -99,7 +100,7 @@ function countScreenFilesInDirectory(screensDir, maxDepth = 4) {
99
100
  if (depth > maxDepth) return;
100
101
  let entries = [];
101
102
  try {
102
- entries = fsSync.readdirSync(curr, { withFileTypes: true });
103
+ entries = fs$1.readdirSync(curr, { withFileTypes: true });
103
104
  } catch {
104
105
  return;
105
106
  }
@@ -128,7 +129,7 @@ function hasDirectScreenFiles(dirPath) {
128
129
  for (const rel of SCREEN_DIR_CANDIDATES) {
129
130
  const full = path.join(dirPath, rel);
130
131
  try {
131
- if (fsSync.existsSync(full) && fsSync.statSync(full).isDirectory()) {
132
+ if (fs$1.existsSync(full) && fs$1.statSync(full).isDirectory()) {
132
133
  const count = countScreenFilesInDirectory(full);
133
134
  if (count > 0) {
134
135
  return { found: true, screenCount: count };
@@ -145,13 +146,13 @@ function scoreMobileCandidate(dirPath, screenCount) {
145
146
  if (/mobile|native|expo|app|client/.test(folderName)) {
146
147
  score += 10;
147
148
  }
148
- if (fsSync.existsSync(path.join(dirPath, "app.json")) || fsSync.existsSync(path.join(dirPath, "eas.json"))) {
149
+ if (fs$1.existsSync(path.join(dirPath, "app.json")) || fs$1.existsSync(path.join(dirPath, "eas.json"))) {
149
150
  score += 25;
150
151
  }
151
152
  try {
152
153
  const pkgPath = path.join(dirPath, "package.json");
153
- if (fsSync.existsSync(pkgPath)) {
154
- const pkgRaw = fsSync.readFileSync(pkgPath, "utf-8");
154
+ if (fs$1.existsSync(pkgPath)) {
155
+ const pkgRaw = fs$1.readFileSync(pkgPath, "utf-8");
155
156
  if (pkgRaw.includes('"react-native"') || pkgRaw.includes('"expo"')) {
156
157
  score += 20;
157
158
  }
@@ -162,7 +163,7 @@ function scoreMobileCandidate(dirPath, screenCount) {
162
163
  }
163
164
  function findMobileAppRoot(rawRoot) {
164
165
  const normalizedRoot = path.resolve(rawRoot);
165
- if (!fsSync.existsSync(normalizedRoot)) {
166
+ if (!fs$1.existsSync(normalizedRoot)) {
166
167
  return normalizedRoot;
167
168
  }
168
169
  const direct = hasDirectScreenFiles(normalizedRoot);
@@ -175,7 +176,7 @@ function findMobileAppRoot(rawRoot) {
175
176
  if (depth > 2) return;
176
177
  let entries = [];
177
178
  try {
178
- entries = fsSync.readdirSync(parentDir, { withFileTypes: true });
179
+ entries = fs$1.readdirSync(parentDir, { withFileTypes: true });
179
180
  } catch {
180
181
  return;
181
182
  }
@@ -200,20 +201,20 @@ function findMobileAppRoot(rawRoot) {
200
201
  }
201
202
  function getActiveProjectRoot(fallbackRoot) {
202
203
  const envTarget = process.env.ANTIGRAVITY_TARGET_PROJECT;
203
- const baseRoot = envTarget && fsSync.existsSync(envTarget) ? path.resolve(envTarget) : path.resolve(fallbackRoot);
204
+ const baseRoot = envTarget && fs$1.existsSync(envTarget) ? path.resolve(envTarget) : path.resolve(fallbackRoot);
204
205
  return findMobileAppRoot(baseRoot);
205
206
  }
206
207
  function resolveScreensDirectory(projectRoot) {
207
208
  const normalizedRoot = findMobileAppRoot(projectRoot);
208
209
  for (const rel of SCREEN_DIR_CANDIDATES) {
209
210
  const full = path.join(normalizedRoot, rel);
210
- if (fsSync.existsSync(full) && fsSync.statSync(full).isDirectory() && countScreenFilesInDirectory(full) > 0) {
211
+ if (fs$1.existsSync(full) && fs$1.statSync(full).isDirectory() && countScreenFilesInDirectory(full) > 0) {
211
212
  return { dirPath: full, relDir: rel };
212
213
  }
213
214
  }
214
215
  for (const rel of SCREEN_DIR_CANDIDATES) {
215
216
  const full = path.join(normalizedRoot, rel);
216
- if (fsSync.existsSync(full) && fsSync.statSync(full).isDirectory()) {
217
+ if (fs$1.existsSync(full) && fs$1.statSync(full).isDirectory()) {
217
218
  return { dirPath: full, relDir: rel };
218
219
  }
219
220
  }
@@ -223,20 +224,20 @@ function resolveScreensDirectory(projectRoot) {
223
224
  };
224
225
  }
225
226
  const FORBIDDEN_OBJECT_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
226
- function safeRealpath(targetPath) {
227
+ function safeRealpath$1(targetPath) {
227
228
  try {
228
- return fsSync.realpathSync(targetPath);
229
+ return fs$1.realpathSync(targetPath);
229
230
  } catch {
230
231
  return path.resolve(targetPath);
231
232
  }
232
233
  }
233
234
  function resolveSafeScreenPath(workspaceRoot, relativeFile) {
234
- const normalizedRoot = safeRealpath(getActiveProjectRoot(workspaceRoot));
235
+ const normalizedRoot = safeRealpath$1(getActiveProjectRoot(workspaceRoot));
235
236
  const cleanRel = String(relativeFile ?? "").replace(/^[/\\]+/, "");
236
237
  const resolved = path.resolve(normalizedRoot, cleanRel);
237
238
  const allowedDirs = ["src/screens", "screens", "app", "src/app"].map((d) => {
238
239
  const candidate = path.resolve(normalizedRoot, d);
239
- return fsSync.existsSync(candidate) ? safeRealpath(candidate) : candidate;
240
+ return fs$1.existsSync(candidate) ? safeRealpath$1(candidate) : candidate;
240
241
  });
241
242
  const isLexicallyAllowed = allowedDirs.some(
242
243
  (dir) => resolved.startsWith(dir + path.sep) || resolved === dir
@@ -249,14 +250,14 @@ function resolveSafeScreenPath(workspaceRoot, relativeFile) {
249
250
  if (!resolved.endsWith(".tsx") && !resolved.endsWith(".jsx")) {
250
251
  throw new Error(`Invalid file extension for "${relativeFile}". Only .tsx and .jsx are allowed.`);
251
252
  }
252
- if (fsSync.existsSync(resolved)) {
253
- const stat = fsSync.lstatSync(resolved);
253
+ if (fs$1.existsSync(resolved)) {
254
+ const stat = fs$1.lstatSync(resolved);
254
255
  if (stat.isSymbolicLink()) {
255
256
  throw new Error(
256
257
  `Security violation: Symbolic link "${relativeFile}" is not permitted inside screen directories`
257
258
  );
258
259
  }
259
- const realTarget = safeRealpath(resolved);
260
+ const realTarget = safeRealpath$1(resolved);
260
261
  const isRealInsideAllowed = allowedDirs.some(
261
262
  (dir) => realTarget.startsWith(dir + path.sep) || realTarget === dir
262
263
  );
@@ -365,7 +366,7 @@ function extractElementNavigationTarget(openingElement) {
365
366
  }
366
367
  if (t.isJSXExpressionContainer(attr.value)) {
367
368
  const expr = attr.value.expression;
368
- const codeStr = generate(expr).code;
369
+ const codeStr = generate$1(expr).code;
369
370
  const match = codeStr.match(/(?:navigate|push|replace|jumpTo)\(\s*['"`]([^'"`$]+)['"`]/);
370
371
  if (match) return normalizeRouteTarget(match[1]);
371
372
  const objMatch = codeStr.match(/(?:pathname|screen|route|name)\s*:\s*['"`]([^'"`$]+)['"`]/);
@@ -429,7 +430,7 @@ function discoverScreenFilesSync(workspaceRoot) {
429
430
  if (depth > 4) return;
430
431
  let dirents = [];
431
432
  try {
432
- dirents = fsSync.readdirSync(currDir, { withFileTypes: true });
433
+ dirents = fs$1.readdirSync(currDir, { withFileTypes: true });
433
434
  } catch {
434
435
  return;
435
436
  }
@@ -636,7 +637,7 @@ async function discoverScreens(workspaceRoot) {
636
637
  const extractTriggerLabelFromAncestry = (nodePath, fallbackTarget) => {
637
638
  const jsxParent = nodePath.findParent((p) => p.isJSXElement());
638
639
  if (jsxParent) {
639
- const rawCode = generate(jsxParent.node).code;
640
+ const rawCode = generate$1(jsxParent.node).code;
640
641
  const textMatches = Array.from(rawCode.matchAll(/>([^<>{}\n]+)</g)).map((m) => m[1].trim()).filter(Boolean);
641
642
  if (textMatches.length > 0) {
642
643
  return textMatches.slice(0, 2).join(" · ");
@@ -666,7 +667,7 @@ async function discoverScreens(workspaceRoot) {
666
667
  }
667
668
  }
668
669
  if (attrName === "onPress" && t.isJSXExpressionContainer(attr.value)) {
669
- const exprCode = generate(attr.value.expression).code;
670
+ const exprCode = generate$1(attr.value.expression).code;
670
671
  if (/\b(?:goBack|back|pop|popToTop)\s*\(/.test(exprCode)) {
671
672
  hasBackNavigation = true;
672
673
  backLine = line;
@@ -931,7 +932,7 @@ async function inspectElement(workspaceRoot, params) {
931
932
  const textInfo = inspectJsxTextChildren(element);
932
933
  const styleInfo = resolveElementStyles(opening, styleSheetInfo);
933
934
  const navigationTarget = extractElementNavigationTarget(opening);
934
- const snippetRaw = generate(element, { concise: false }).code;
935
+ const snippetRaw = generate$1(element, { concise: false }).code;
935
936
  const codeSnippet = snippetRaw.length > 600 ? `${snippetRaw.slice(0, 600)}
936
937
  /* ... */` : snippetRaw;
937
938
  return {
@@ -1065,7 +1066,7 @@ async function patchElement(workspaceRoot, payload) {
1065
1066
  upsertObjectProperty(targetObject, styleKey, styleVal);
1066
1067
  }
1067
1068
  }
1068
- const output = generate(ast, {
1069
+ const output = generate$1(ast, {
1069
1070
  retainLines: false,
1070
1071
  comments: true,
1071
1072
  jsescOption: { minimal: true }
@@ -1201,7 +1202,7 @@ async function reorderElement(workspaceRoot, payload) {
1201
1202
  }
1202
1203
  }
1203
1204
  });
1204
- const output = generate(ast, {
1205
+ const output = generate$1(ast, {
1205
1206
  retainLines: false,
1206
1207
  comments: true,
1207
1208
  jsescOption: { minimal: true }
@@ -1733,7 +1734,7 @@ async function insertElement(workspaceRoot, payload) {
1733
1734
  }
1734
1735
  }
1735
1736
  });
1736
- const output = generate(ast, {
1737
+ const output = generate$1(ast, {
1737
1738
  retainLines: false,
1738
1739
  comments: true,
1739
1740
  jsescOption: { minimal: true }
@@ -1810,7 +1811,7 @@ async function duplicateElement(workspaceRoot, payload) {
1810
1811
  }
1811
1812
  }
1812
1813
  });
1813
- const output = generate(ast, {
1814
+ const output = generate$1(ast, {
1814
1815
  retainLines: false,
1815
1816
  comments: true,
1816
1817
  jsescOption: { minimal: true }
@@ -1878,7 +1879,7 @@ async function deleteElement(workspaceRoot, payload) {
1878
1879
  throw new Error("Could not find element inside parent children.");
1879
1880
  }
1880
1881
  siblings.splice(pos, 1);
1881
- const output = generate(ast, {
1882
+ const output = generate$1(ast, {
1882
1883
  retainLines: false,
1883
1884
  comments: true,
1884
1885
  jsescOption: { minimal: true }
@@ -1903,6 +1904,1878 @@ async function deleteElement(workspaceRoot, payload) {
1903
1904
  };
1904
1905
  });
1905
1906
  }
1907
+ async function undoLastPatch(workspaceRoot) {
1908
+ const entry = undoStack.pop();
1909
+ if (!entry) {
1910
+ return {
1911
+ restoredFile: null,
1912
+ description: null,
1913
+ undoAvailable: 0,
1914
+ redoAvailable: redoStack.length
1915
+ };
1916
+ }
1917
+ const fullPath = resolveSafeScreenPath(workspaceRoot, entry.file);
1918
+ await withFileLock(fullPath, async () => {
1919
+ await fs.writeFile(fullPath, entry.previousContent, "utf-8");
1920
+ });
1921
+ redoStack.push(entry);
1922
+ return {
1923
+ restoredFile: entry.file,
1924
+ description: entry.description,
1925
+ undoAvailable: undoStack.length,
1926
+ redoAvailable: redoStack.length
1927
+ };
1928
+ }
1929
+ async function redoLastPatch(workspaceRoot) {
1930
+ const entry = redoStack.pop();
1931
+ if (!entry) {
1932
+ return {
1933
+ restoredFile: null,
1934
+ description: null,
1935
+ undoAvailable: undoStack.length,
1936
+ redoAvailable: 0
1937
+ };
1938
+ }
1939
+ const fullPath = resolveSafeScreenPath(workspaceRoot, entry.file);
1940
+ await withFileLock(fullPath, async () => {
1941
+ await fs.writeFile(fullPath, entry.nextContent, "utf-8");
1942
+ });
1943
+ undoStack.push(entry);
1944
+ return {
1945
+ restoredFile: entry.file,
1946
+ description: entry.description,
1947
+ undoAvailable: undoStack.length,
1948
+ redoAvailable: redoStack.length
1949
+ };
1950
+ }
1951
+ function getHistoryStatus() {
1952
+ return {
1953
+ undoAvailable: undoStack.length,
1954
+ redoAvailable: redoStack.length
1955
+ };
1956
+ }
1957
+ const MAX_BODY_BYTES = 1e6;
1958
+ const LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]", "::1"]);
1959
+ const FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1960
+ function isLoopbackHostHeader(hostHeader) {
1961
+ if (!hostHeader) return false;
1962
+ const trimmed = hostHeader.trim().toLowerCase();
1963
+ if (trimmed.startsWith("[")) {
1964
+ const closeIdx = trimmed.indexOf("]");
1965
+ if (closeIdx === -1) return false;
1966
+ const ipv6Host = trimmed.slice(0, closeIdx + 1);
1967
+ return LOOPBACK_HOSTS.has(ipv6Host);
1968
+ }
1969
+ const hostname = trimmed.split(":")[0];
1970
+ return LOOPBACK_HOSTS.has(hostname);
1971
+ }
1972
+ function verifyApiRequestSecurity(req) {
1973
+ const host = typeof req.headers.host === "string" ? req.headers.host : void 0;
1974
+ if (!isLoopbackHostHeader(host)) {
1975
+ return {
1976
+ allowed: false,
1977
+ reason: "Forbidden Host header: Local API only accepts loopback connections (127.0.0.1, localhost, [::1])"
1978
+ };
1979
+ }
1980
+ const secFetchSite = typeof req.headers["sec-fetch-site"] === "string" ? req.headers["sec-fetch-site"].toLowerCase() : void 0;
1981
+ if (secFetchSite && secFetchSite !== "same-origin" && secFetchSite !== "none") {
1982
+ return {
1983
+ allowed: false,
1984
+ reason: `Forbidden cross-site request (Sec-Fetch-Site: ${secFetchSite})`
1985
+ };
1986
+ }
1987
+ const origin = typeof req.headers.origin === "string" ? req.headers.origin : void 0;
1988
+ if (origin) {
1989
+ try {
1990
+ const parsedOrigin = new URL(origin);
1991
+ if (!LOOPBACK_HOSTS.has(parsedOrigin.hostname.toLowerCase())) {
1992
+ return {
1993
+ allowed: false,
1994
+ reason: `Forbidden cross-origin request from ${origin}`
1995
+ };
1996
+ }
1997
+ } catch {
1998
+ return {
1999
+ allowed: false,
2000
+ reason: "Malformed Origin header"
2001
+ };
2002
+ }
2003
+ }
2004
+ if (req.method === "POST") {
2005
+ const contentType = typeof req.headers["content-type"] === "string" ? req.headers["content-type"].toLowerCase() : "";
2006
+ if (!contentType.startsWith("application/json")) {
2007
+ return {
2008
+ allowed: false,
2009
+ reason: "POST requests to /api/* must specify Content-Type: application/json"
2010
+ };
2011
+ }
2012
+ }
2013
+ return { allowed: true };
2014
+ }
2015
+ function sanitizeLayoutPayload(input) {
2016
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
2017
+ throw new Error("Invalid layout payload: expected an object map of screen coordinates");
2018
+ }
2019
+ const sanitized = /* @__PURE__ */ Object.create(null);
2020
+ const entries = Object.entries(input);
2021
+ if (entries.length > 200) {
2022
+ throw new Error("Invalid layout payload: too many screen entries");
2023
+ }
2024
+ for (const [screenId, rawBox] of entries) {
2025
+ if (!screenId || FORBIDDEN_KEYS.has(screenId) || screenId.length > 120) {
2026
+ throw new Error(`Invalid screen key in layout payload: "${screenId}"`);
2027
+ }
2028
+ if (!rawBox || typeof rawBox !== "object" || Array.isArray(rawBox)) {
2029
+ throw new Error(`Invalid layout coordinates for screen "${screenId}"`);
2030
+ }
2031
+ const box = rawBox;
2032
+ const x = Number(box.x);
2033
+ const y = Number(box.y);
2034
+ const width = Number(box.width);
2035
+ const height = Number(box.height);
2036
+ if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(width) || !Number.isFinite(height) || Math.abs(x) > 1e5 || Math.abs(y) > 1e5 || width < 100 || width > 5e3 || height < 100 || height > 5e3) {
2037
+ throw new Error(`Out-of-bounds layout coordinates for screen "${screenId}"`);
2038
+ }
2039
+ sanitized[screenId] = {
2040
+ x: Math.round(x),
2041
+ y: Math.round(y),
2042
+ width: Math.round(width),
2043
+ height: Math.round(height)
2044
+ };
2045
+ }
2046
+ return sanitized;
2047
+ }
2048
+ async function readJsonBody(req) {
2049
+ return new Promise((resolve, reject) => {
2050
+ let raw = "";
2051
+ let byteCount = 0;
2052
+ let aborted = false;
2053
+ req.on("data", (chunk) => {
2054
+ if (aborted) return;
2055
+ const chunkBytes = typeof chunk === "string" ? Buffer.byteLength(chunk, "utf-8") : chunk.length;
2056
+ byteCount += chunkBytes;
2057
+ if (byteCount > MAX_BODY_BYTES) {
2058
+ aborted = true;
2059
+ req.destroy();
2060
+ reject(new Error("Request payload too large"));
2061
+ return;
2062
+ }
2063
+ raw += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
2064
+ });
2065
+ req.on("end", () => {
2066
+ if (aborted) return;
2067
+ try {
2068
+ resolve(raw ? JSON.parse(raw) : {});
2069
+ } catch (err) {
2070
+ reject(err);
2071
+ }
2072
+ });
2073
+ req.on("error", (err) => {
2074
+ if (!aborted) {
2075
+ aborted = true;
2076
+ reject(err);
2077
+ }
2078
+ });
2079
+ });
2080
+ }
2081
+ const generate = _generate.default ?? _generate;
2082
+ const ALLOWED_SCREEN_PREFIXES = ["src/screens/", "screens/", "app/", "src/app/"];
2083
+ const ASSET_EXT_REGEX = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico|ttf|otf|woff2?|mp3|mp4|wav|m4a|webm|lottie|pdf|bin)$/i;
2084
+ const RESOLVABLE_EXTENSIONS = [
2085
+ ".web.tsx",
2086
+ ".web.ts",
2087
+ ".web.jsx",
2088
+ ".web.js",
2089
+ ".tsx",
2090
+ ".ts",
2091
+ ".jsx",
2092
+ ".js",
2093
+ ".native.tsx",
2094
+ ".native.ts",
2095
+ ".native.jsx",
2096
+ ".native.js",
2097
+ ".ios.tsx",
2098
+ ".ios.ts",
2099
+ ".android.tsx",
2100
+ ".android.ts",
2101
+ ".mjs",
2102
+ ".cjs",
2103
+ ".json",
2104
+ ".css"
2105
+ ];
2106
+ const ZELUNE_JSX_REACT_IDENT = "__zeluneReact";
2107
+ function stripJsonCommentsAndTrailingCommas(input) {
2108
+ const withoutComments = input.replace(
2109
+ /("(?:\\.|[^"\\])*")|\/\*[\s\S]*?\*\/|\/\/.*/g,
2110
+ (_match, quotedString) => quotedString ?? ""
2111
+ );
2112
+ return withoutComments.replace(/,\s*([}\]])/g, "$1");
2113
+ }
2114
+ function tryResolveLocalModule(candidateBase) {
2115
+ try {
2116
+ const cleanBase = candidateBase.split("?")[0];
2117
+ if (fs$1.existsSync(cleanBase) && fs$1.statSync(cleanBase).isFile()) {
2118
+ return cleanBase;
2119
+ }
2120
+ for (const ext of RESOLVABLE_EXTENSIONS) {
2121
+ const withExt = cleanBase + ext;
2122
+ if (fs$1.existsSync(withExt) && fs$1.statSync(withExt).isFile()) {
2123
+ return withExt;
2124
+ }
2125
+ }
2126
+ if (fs$1.existsSync(cleanBase) && fs$1.statSync(cleanBase).isDirectory()) {
2127
+ for (const ext of RESOLVABLE_EXTENSIONS) {
2128
+ const indexFile = path.join(cleanBase, `index${ext}`);
2129
+ if (fs$1.existsSync(indexFile) && fs$1.statSync(indexFile).isFile()) {
2130
+ return indexFile;
2131
+ }
2132
+ }
2133
+ }
2134
+ } catch {
2135
+ }
2136
+ return null;
2137
+ }
2138
+ function loadTsconfigAliases(roots) {
2139
+ var _a, _b;
2140
+ const mappings = [];
2141
+ for (const rootDir of roots) {
2142
+ try {
2143
+ const tsconfigPath = path.join(rootDir, "tsconfig.json");
2144
+ if (!fs$1.existsSync(tsconfigPath)) continue;
2145
+ const raw = fs$1.readFileSync(tsconfigPath, "utf-8");
2146
+ const parsed = JSON.parse(stripJsonCommentsAndTrailingCommas(raw));
2147
+ const baseUrl = ((_a = parsed.compilerOptions) == null ? void 0 : _a.baseUrl) ?? ".";
2148
+ const paths = ((_b = parsed.compilerOptions) == null ? void 0 : _b.paths) ?? {};
2149
+ for (const [pattern, targets] of Object.entries(paths)) {
2150
+ if (!Array.isArray(targets)) continue;
2151
+ const cleanPrefix = pattern.replace(/\/\*$/, "");
2152
+ if (!cleanPrefix) continue;
2153
+ for (const target of targets) {
2154
+ const cleanTarget = target.replace(/\/\*$/, "");
2155
+ const resolvedDir = path.resolve(rootDir, baseUrl, cleanTarget);
2156
+ mappings.push({ prefix: cleanPrefix, targetDir: resolvedDir });
2157
+ }
2158
+ }
2159
+ } catch {
2160
+ }
2161
+ }
2162
+ return mappings;
2163
+ }
2164
+ function cleanJsxText(rawText) {
2165
+ const lines = rawText.split(/\r\n|\n|\r/);
2166
+ let lastNonEmptyLine = 0;
2167
+ for (let i = 0; i < lines.length; i++) {
2168
+ if (/[^ \t]/.test(lines[i])) {
2169
+ lastNonEmptyLine = i;
2170
+ }
2171
+ }
2172
+ let str = "";
2173
+ for (let i = 0; i < lines.length; i++) {
2174
+ const line = lines[i];
2175
+ const isFirstLine = i === 0;
2176
+ const isLastLine = i === lines.length - 1;
2177
+ const isLastNonEmptyLine = i === lastNonEmptyLine;
2178
+ let trimmedLine = line.replace(/\t/g, " ");
2179
+ if (!isFirstLine) {
2180
+ trimmedLine = trimmedLine.replace(/^[ ]+/, "");
2181
+ }
2182
+ if (!isLastLine) {
2183
+ trimmedLine = trimmedLine.replace(/[ ]+$/, "");
2184
+ }
2185
+ if (trimmedLine) {
2186
+ if (!isLastNonEmptyLine) {
2187
+ trimmedLine += " ";
2188
+ }
2189
+ str += trimmedLine;
2190
+ }
2191
+ }
2192
+ return str.length > 0 ? str : null;
2193
+ }
2194
+ function convertJsxElementNameToExpr(nameNode) {
2195
+ if (t.isJSXIdentifier(nameNode)) {
2196
+ if (nameNode.name === "this") {
2197
+ return t.thisExpression();
2198
+ }
2199
+ if (/^[a-z]/.test(nameNode.name) || nameNode.name.includes("-")) {
2200
+ return t.stringLiteral(nameNode.name);
2201
+ }
2202
+ return t.identifier(nameNode.name);
2203
+ }
2204
+ if (t.isJSXMemberExpression(nameNode)) {
2205
+ return t.memberExpression(
2206
+ convertJsxElementNameToExpr(nameNode.object),
2207
+ t.identifier(nameNode.property.name)
2208
+ );
2209
+ }
2210
+ if (t.isJSXNamespacedName(nameNode)) {
2211
+ return t.stringLiteral(`${nameNode.namespace.name}:${nameNode.name.name}`);
2212
+ }
2213
+ return t.stringLiteral("div");
2214
+ }
2215
+ function convertJsxAttributesToExpr(attributes, onJsxSeen) {
2216
+ if (attributes.length === 0) {
2217
+ return t.nullLiteral();
2218
+ }
2219
+ const props = [];
2220
+ for (const attr of attributes) {
2221
+ if (t.isJSXSpreadAttribute(attr)) {
2222
+ props.push(t.spreadElement(attr.argument));
2223
+ continue;
2224
+ }
2225
+ const rawKey = t.isJSXIdentifier(attr.name) ? attr.name.name : `${attr.name.namespace.name}:${attr.name.name.name}`;
2226
+ const keyNode = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(rawKey) ? t.identifier(rawKey) : t.stringLiteral(rawKey);
2227
+ let valExpr;
2228
+ if (attr.value === null || attr.value === void 0) {
2229
+ valExpr = t.booleanLiteral(true);
2230
+ } else if (t.isJSXExpressionContainer(attr.value)) {
2231
+ if (t.isJSXEmptyExpression(attr.value.expression)) {
2232
+ valExpr = t.booleanLiteral(true);
2233
+ } else {
2234
+ valExpr = attr.value.expression;
2235
+ }
2236
+ } else if (t.isJSXElement(attr.value) || t.isJSXFragment(attr.value)) {
2237
+ valExpr = transformJsxNode(attr.value, onJsxSeen);
2238
+ } else {
2239
+ valExpr = attr.value;
2240
+ }
2241
+ props.push(t.objectProperty(keyNode, valExpr));
2242
+ }
2243
+ return t.objectExpression(props);
2244
+ }
2245
+ function convertJsxChildrenToExprs(children, onJsxSeen) {
2246
+ const out = [];
2247
+ for (const child of children) {
2248
+ if (!child) continue;
2249
+ if (t.isJSXText(child)) {
2250
+ const cleaned = cleanJsxText(child.value);
2251
+ if (cleaned !== null) {
2252
+ out.push(t.stringLiteral(cleaned));
2253
+ }
2254
+ } else if (t.isJSXExpressionContainer(child)) {
2255
+ if (!t.isJSXEmptyExpression(child.expression)) {
2256
+ out.push(child.expression);
2257
+ }
2258
+ } else if (t.isJSXSpreadChild(child)) {
2259
+ out.push(child.expression);
2260
+ } else if (t.isJSXElement(child) || t.isJSXFragment(child)) {
2261
+ out.push(transformJsxNode(child, onJsxSeen));
2262
+ } else if (t.isSpreadElement(child) || t.isExpression(child)) {
2263
+ out.push(child);
2264
+ }
2265
+ }
2266
+ return out;
2267
+ }
2268
+ function transformJsxNode(node, onJsxSeen) {
2269
+ onJsxSeen();
2270
+ const createElMember = t.memberExpression(
2271
+ t.identifier(ZELUNE_JSX_REACT_IDENT),
2272
+ t.identifier("createElement")
2273
+ );
2274
+ if (t.isJSXFragment(node)) {
2275
+ const fragMember = t.memberExpression(
2276
+ t.identifier(ZELUNE_JSX_REACT_IDENT),
2277
+ t.identifier("Fragment")
2278
+ );
2279
+ const children2 = convertJsxChildrenToExprs(node.children, onJsxSeen);
2280
+ return t.callExpression(createElMember, [fragMember, t.nullLiteral(), ...children2]);
2281
+ }
2282
+ const tagExpr = convertJsxElementNameToExpr(node.openingElement.name);
2283
+ const propsExpr = convertJsxAttributesToExpr(node.openingElement.attributes, onJsxSeen);
2284
+ const children = convertJsxChildrenToExprs(node.children, onJsxSeen);
2285
+ return t.callExpression(createElMember, [tagExpr, propsExpr, ...children]);
2286
+ }
2287
+ function convertTsEnumToVar(enumNode) {
2288
+ const props = [];
2289
+ let nextNumericValue = 0;
2290
+ for (const member of enumNode.members) {
2291
+ const keyNode = t.isIdentifier(member.id) ? t.identifier(member.id.name) : t.stringLiteral(member.id.value);
2292
+ let initExpr;
2293
+ if (member.initializer) {
2294
+ initExpr = member.initializer;
2295
+ if (t.isNumericLiteral(member.initializer)) {
2296
+ nextNumericValue = member.initializer.value + 1;
2297
+ }
2298
+ } else {
2299
+ initExpr = t.numericLiteral(nextNumericValue++);
2300
+ }
2301
+ props.push(t.objectProperty(keyNode, initExpr));
2302
+ }
2303
+ return t.variableDeclaration("const", [
2304
+ t.variableDeclarator(t.identifier(enumNode.id.name), t.objectExpression(props))
2305
+ ]);
2306
+ }
2307
+ function isTsDeclarationOnlyNode(item) {
2308
+ const nodeType = item.type;
2309
+ if (nodeType === "TSInterfaceDeclaration" || nodeType === "TSTypeAliasDeclaration" || nodeType === "TSDeclareFunction" || nodeType === "TSDeclareMethod" || nodeType === "TSModuleDeclaration" || nodeType === "TSIndexSignature" || nodeType === "TSAbstractMethodDefinition" || nodeType === "TSAbstractPropertyDefinition" || nodeType === "TSAbstractAccessorProperty") {
2310
+ return true;
2311
+ }
2312
+ if ((nodeType === "ClassMethod" || nodeType === "ClassProperty" || nodeType === "ClassPrivateProperty" || nodeType === "AccessorProperty") && (item.abstract === true || item.declare === true)) {
2313
+ return true;
2314
+ }
2315
+ if (nodeType === "VariableDeclaration" && item.declare === true) {
2316
+ return true;
2317
+ }
2318
+ if (nodeType === "ClassDeclaration" && item.declare === true) {
2319
+ return true;
2320
+ }
2321
+ return false;
2322
+ }
2323
+ function stripTypeScriptAndTransformJsxAst(node, onJsxSeen = () => {
2324
+ }) {
2325
+ var _a, _b, _c, _d, _e;
2326
+ if (!node || typeof node !== "object") return node;
2327
+ if (Array.isArray(node)) {
2328
+ const nextArr = [];
2329
+ for (let i = 0; i < node.length; i++) {
2330
+ const item = node[i];
2331
+ if (!item) continue;
2332
+ if (isTsDeclarationOnlyNode(item)) {
2333
+ continue;
2334
+ }
2335
+ if (item.type === "ImportDeclaration" && item.importKind === "type") {
2336
+ continue;
2337
+ }
2338
+ if (item.type === "ExportAllDeclaration" && item.exportKind === "type") {
2339
+ continue;
2340
+ }
2341
+ if (item.type === "ExportNamedDeclaration") {
2342
+ if (item.exportKind === "type") continue;
2343
+ if (item.declaration && isTsDeclarationOnlyNode(item.declaration)) {
2344
+ continue;
2345
+ }
2346
+ }
2347
+ if (item.type === "ExportDefaultDeclaration") {
2348
+ if (item.declaration && isTsDeclarationOnlyNode(item.declaration)) {
2349
+ continue;
2350
+ }
2351
+ }
2352
+ const transformed = stripTypeScriptAndTransformJsxAst(item, onJsxSeen);
2353
+ if (transformed !== null && transformed !== void 0) {
2354
+ nextArr.push(transformed);
2355
+ }
2356
+ }
2357
+ return nextArr;
2358
+ }
2359
+ while (node && (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression" || node.type === "TSTypeAssertion" || node.type === "TSNonNullExpression" || node.type === "TSInstantiationExpression")) {
2360
+ node = node.expression;
2361
+ }
2362
+ if (!node || typeof node !== "object") return node;
2363
+ if (node.type === "TSEnumDeclaration") {
2364
+ return convertTsEnumToVar(node);
2365
+ }
2366
+ if (node.type === "ExportNamedDeclaration" && ((_a = node.declaration) == null ? void 0 : _a.type) === "TSEnumDeclaration") {
2367
+ node.declaration = convertTsEnumToVar(node.declaration);
2368
+ }
2369
+ if (node.type === "ImportDeclaration" && Array.isArray(node.specifiers)) {
2370
+ const origCount = node.specifiers.length;
2371
+ node.specifiers = node.specifiers.filter(
2372
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2373
+ (s) => s.importKind !== "type"
2374
+ );
2375
+ if (origCount > 0 && node.specifiers.length === 0) {
2376
+ return null;
2377
+ }
2378
+ }
2379
+ if (node.type === "ExportNamedDeclaration" && Array.isArray(node.specifiers)) {
2380
+ node.specifiers = node.specifiers.filter(
2381
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2382
+ (s) => s.exportKind !== "type"
2383
+ );
2384
+ if (!node.declaration && node.specifiers.length === 0) {
2385
+ return null;
2386
+ }
2387
+ }
2388
+ delete node.typeAnnotation;
2389
+ delete node.returnType;
2390
+ delete node.typeParameters;
2391
+ delete node.typeArguments;
2392
+ delete node.implements;
2393
+ delete node.superTypeParameters;
2394
+ delete node.definite;
2395
+ delete node.accessibility;
2396
+ delete node.readonly;
2397
+ delete node.declare;
2398
+ delete node.override;
2399
+ delete node.abstract;
2400
+ delete node.importKind;
2401
+ delete node.exportKind;
2402
+ if (node.type !== "OptionalMemberExpression" && node.type !== "OptionalCallExpression") {
2403
+ delete node.optional;
2404
+ }
2405
+ if ((node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "ObjectMethod" || node.type === "ClassMethod" || node.type === "ClassPrivateMethod") && Array.isArray(node.params) && ((_b = node.params[0]) == null ? void 0 : _b.type) === "Identifier" && ((_c = node.params[0]) == null ? void 0 : _c.name) === "this") {
2406
+ node.params = node.params.slice(1);
2407
+ }
2408
+ if (node.type === "ClassMethod" && node.kind === "constructor" && Array.isArray(node.params) && ((_d = node.body) == null ? void 0 : _d.type) === "BlockStatement" && Array.isArray(node.body.body)) {
2409
+ const paramPropAssignments = [];
2410
+ for (const p of node.params) {
2411
+ if ((p == null ? void 0 : p.type) === "TSParameterProperty") {
2412
+ const inner = p.parameter;
2413
+ const propName = (inner == null ? void 0 : inner.type) === "Identifier" ? inner.name : (inner == null ? void 0 : inner.type) === "AssignmentPattern" && ((_e = inner.left) == null ? void 0 : _e.type) === "Identifier" ? inner.left.name : null;
2414
+ if (propName) {
2415
+ paramPropAssignments.push(
2416
+ t.expressionStatement(
2417
+ t.assignmentExpression(
2418
+ "=",
2419
+ t.memberExpression(t.thisExpression(), t.identifier(propName)),
2420
+ t.identifier(propName)
2421
+ )
2422
+ )
2423
+ );
2424
+ }
2425
+ }
2426
+ }
2427
+ if (paramPropAssignments.length > 0) {
2428
+ const superIdx = node.body.body.findIndex(
2429
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2430
+ (s) => {
2431
+ var _a2, _b2;
2432
+ return (s == null ? void 0 : s.type) === "ExpressionStatement" && ((_a2 = s.expression) == null ? void 0 : _a2.type) === "CallExpression" && ((_b2 = s.expression.callee) == null ? void 0 : _b2.type) === "Super";
2433
+ }
2434
+ );
2435
+ const insertPos = superIdx >= 0 ? superIdx + 1 : 0;
2436
+ node.body.body.splice(insertPos, 0, ...paramPropAssignments);
2437
+ }
2438
+ }
2439
+ if (node.type === "TSParameterProperty") {
2440
+ return stripTypeScriptAndTransformJsxAst(node.parameter, onJsxSeen);
2441
+ }
2442
+ for (const key of Object.keys(node)) {
2443
+ if (key === "loc" || key === "comments" || key === "leadingComments" || key === "trailingComments") {
2444
+ continue;
2445
+ }
2446
+ const val = node[key];
2447
+ if (val && typeof val === "object") {
2448
+ node[key] = stripTypeScriptAndTransformJsxAst(val, onJsxSeen);
2449
+ }
2450
+ }
2451
+ if (node.type === "JSXElement" || node.type === "JSXFragment") {
2452
+ return transformJsxNode(node, onJsxSeen);
2453
+ }
2454
+ return node;
2455
+ }
2456
+ function injectScreenAgyAttributes(ast, relPath) {
2457
+ let jsxIndex = 0;
2458
+ let hasJsx = false;
2459
+ function visit(node) {
2460
+ var _a, _b;
2461
+ if (!node || typeof node !== "object" || typeof node.type !== "string") return;
2462
+ const typed = node;
2463
+ if (typed.type === "JSXFragment") {
2464
+ hasJsx = true;
2465
+ } else if (typed.type === "JSXOpeningElement") {
2466
+ hasJsx = true;
2467
+ const tagName = getJsxTagName(typed.name);
2468
+ if (tagName !== "Fragment" && tagName !== "React.Fragment" && tagName !== "") {
2469
+ const hasAgyAttr = typed.attributes.some(
2470
+ (attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: "data-agy-ast-path" })
2471
+ );
2472
+ if (!hasAgyAttr) {
2473
+ const currentIndex = String(jsxIndex++);
2474
+ const line = String(((_a = typed.loc) == null ? void 0 : _a.start.line) ?? 1);
2475
+ const col = String(((_b = typed.loc) == null ? void 0 : _b.start.column) ?? 0);
2476
+ const dataSetProps = [
2477
+ t.objectProperty(t.identifier("agyFile"), t.stringLiteral(relPath)),
2478
+ t.objectProperty(t.identifier("agyLine"), t.stringLiteral(line)),
2479
+ t.objectProperty(t.identifier("agyCol"), t.stringLiteral(col)),
2480
+ t.objectProperty(t.identifier("agyAstPath"), t.stringLiteral(currentIndex)),
2481
+ t.objectProperty(t.identifier("agyTag"), t.stringLiteral(tagName))
2482
+ ];
2483
+ typed.attributes.push(
2484
+ t.jsxAttribute(
2485
+ t.jsxIdentifier("dataSet"),
2486
+ t.jsxExpressionContainer(t.objectExpression(dataSetProps))
2487
+ ),
2488
+ t.jsxAttribute(t.jsxIdentifier("data-agy-file"), t.stringLiteral(relPath)),
2489
+ t.jsxAttribute(t.jsxIdentifier("data-agy-line"), t.stringLiteral(line)),
2490
+ t.jsxAttribute(t.jsxIdentifier("data-agy-col"), t.stringLiteral(col)),
2491
+ t.jsxAttribute(t.jsxIdentifier("data-agy-ast-path"), t.stringLiteral(currentIndex)),
2492
+ t.jsxAttribute(t.jsxIdentifier("data-agy-tag"), t.stringLiteral(tagName))
2493
+ );
2494
+ }
2495
+ }
2496
+ }
2497
+ const keys = t.VISITOR_KEYS[typed.type];
2498
+ if (!keys) return;
2499
+ const rec = typed;
2500
+ for (const key of keys) {
2501
+ const child = rec[key];
2502
+ if (Array.isArray(child)) {
2503
+ for (let i = 0; i < child.length; i++) {
2504
+ if (child[i]) visit(child[i]);
2505
+ }
2506
+ } else if (child && typeof child === "object") {
2507
+ visit(child);
2508
+ }
2509
+ }
2510
+ }
2511
+ visit(ast);
2512
+ return hasJsx;
2513
+ }
2514
+ function collectNamespaceMemberAccesses(ast, namespaceLocalNames) {
2515
+ const accesses = /* @__PURE__ */ new Map();
2516
+ if (namespaceLocalNames.size === 0) return accesses;
2517
+ for (const name of namespaceLocalNames) {
2518
+ accesses.set(name, /* @__PURE__ */ new Set());
2519
+ }
2520
+ function visit(node) {
2521
+ var _a;
2522
+ if (!node || typeof node !== "object" || typeof node.type !== "string") return;
2523
+ const typed = node;
2524
+ if ((typed.type === "MemberExpression" || typed.type === "OptionalMemberExpression") && !typed.computed && typed.object.type === "Identifier" && namespaceLocalNames.has(typed.object.name) && typed.property.type === "Identifier") {
2525
+ (_a = accesses.get(typed.object.name)) == null ? void 0 : _a.add(typed.property.name);
2526
+ }
2527
+ const keys = t.VISITOR_KEYS[typed.type];
2528
+ if (!keys) return;
2529
+ const rec = typed;
2530
+ for (const key of keys) {
2531
+ const child = rec[key];
2532
+ if (Array.isArray(child)) {
2533
+ for (let i = 0; i < child.length; i++) {
2534
+ if (child[i]) visit(child[i]);
2535
+ }
2536
+ } else if (child && typeof child === "object") {
2537
+ visit(child);
2538
+ }
2539
+ }
2540
+ }
2541
+ visit(ast);
2542
+ return accesses;
2543
+ }
2544
+ function collectRuntimeReferencedIdentifiers(stmts) {
2545
+ const refs = /* @__PURE__ */ new Set();
2546
+ function walk(node) {
2547
+ if (!node || typeof node !== "object") return;
2548
+ if (Array.isArray(node)) {
2549
+ for (let i = 0; i < node.length; i++) {
2550
+ if (node[i]) walk(node[i]);
2551
+ }
2552
+ return;
2553
+ }
2554
+ if (node.type === "Identifier" && typeof node.name === "string") {
2555
+ refs.add(node.name);
2556
+ }
2557
+ for (const key of Object.keys(node)) {
2558
+ if (key === "loc" || key === "comments" || key === "leadingComments" || key === "trailingComments") {
2559
+ continue;
2560
+ }
2561
+ const val = node[key];
2562
+ if (val && typeof val === "object") {
2563
+ walk(val);
2564
+ }
2565
+ }
2566
+ }
2567
+ for (const stmt of stmts) {
2568
+ if (stmt && stmt.type !== "ImportDeclaration") {
2569
+ walk(stmt);
2570
+ }
2571
+ }
2572
+ return refs;
2573
+ }
2574
+ function getLocalTypeOnlyDeclaredNames(localFilePath) {
2575
+ var _a;
2576
+ const typeNames = /* @__PURE__ */ new Set();
2577
+ const valueNames = /* @__PURE__ */ new Set();
2578
+ try {
2579
+ if (!/\.(tsx?|mts|cts)$/i.test(localFilePath) || !fs$1.existsSync(localFilePath)) {
2580
+ return typeNames;
2581
+ }
2582
+ const raw = fs$1.readFileSync(localFilePath, "utf-8");
2583
+ const parsed = parse(raw, {
2584
+ sourceType: "module",
2585
+ plugins: ["typescript", "jsx", "decorators-legacy"],
2586
+ errorRecovery: true
2587
+ });
2588
+ for (const stmt of parsed.program.body) {
2589
+ if (stmt.type === "ExportNamedDeclaration") {
2590
+ if (stmt.exportKind === "type") {
2591
+ if (stmt.declaration && "id" in stmt.declaration && ((_a = stmt.declaration.id) == null ? void 0 : _a.type) === "Identifier") {
2592
+ typeNames.add(stmt.declaration.id.name);
2593
+ }
2594
+ for (const s of stmt.specifiers) {
2595
+ if (s.type === "ExportSpecifier") {
2596
+ const exp = s.exported.type === "Identifier" ? s.exported.name : s.exported.value;
2597
+ typeNames.add(exp);
2598
+ }
2599
+ }
2600
+ continue;
2601
+ }
2602
+ const decl = stmt.declaration;
2603
+ if (decl) {
2604
+ if (decl.type === "TSInterfaceDeclaration" || decl.type === "TSTypeAliasDeclaration") {
2605
+ typeNames.add(decl.id.name);
2606
+ } else if ((decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration" || decl.type === "TSEnumDeclaration") && decl.id) {
2607
+ valueNames.add(decl.id.name);
2608
+ } else if (decl.type === "VariableDeclaration") {
2609
+ for (const d of decl.declarations) {
2610
+ if (d.id.type === "Identifier") valueNames.add(d.id.name);
2611
+ }
2612
+ }
2613
+ }
2614
+ }
2615
+ }
2616
+ for (const v of valueNames) {
2617
+ typeNames.delete(v);
2618
+ }
2619
+ } catch {
2620
+ }
2621
+ return typeNames;
2622
+ }
2623
+ function compileModuleForBrowser(options) {
2624
+ const { filePath, targetProjectRoot, workspaceRoot = targetProjectRoot, versionTag } = options;
2625
+ const cleanFilePath = filePath.split("?")[0];
2626
+ const ext = path.extname(cleanFilePath).toLowerCase();
2627
+ if (ext === ".css") {
2628
+ return "export default {};\n";
2629
+ }
2630
+ if (ext === ".json") {
2631
+ const rawJson = fs$1.readFileSync(cleanFilePath, "utf-8");
2632
+ return `export default ${rawJson};
2633
+ `;
2634
+ }
2635
+ if (ASSET_EXT_REGEX.test(ext)) {
2636
+ const assetUrl = `/@zelune/asset?file=${encodeURIComponent(cleanFilePath)}`;
2637
+ return `export default { uri: ${JSON.stringify(assetUrl)} };
2638
+ `;
2639
+ }
2640
+ const code = fs$1.readFileSync(cleanFilePath, "utf-8");
2641
+ const ast = parse(code, {
2642
+ sourceType: "module",
2643
+ plugins: ["typescript", "jsx", "decorators-legacy"],
2644
+ errorRecovery: true
2645
+ });
2646
+ const normalizedTargetRoot = path.resolve(targetProjectRoot);
2647
+ const relPath = path.relative(normalizedTargetRoot, path.resolve(cleanFilePath)).replace(/\\/g, "/");
2648
+ const isScreenFile = ALLOWED_SCREEN_PREFIXES.some((prefix) => relPath.startsWith(prefix));
2649
+ let emittedJsx = false;
2650
+ if (isScreenFile) {
2651
+ if (injectScreenAgyAttributes(ast, relPath)) {
2652
+ emittedJsx = true;
2653
+ }
2654
+ }
2655
+ const uniqueRoots = Array.from(
2656
+ /* @__PURE__ */ new Set([path.resolve(targetProjectRoot), path.resolve(workspaceRoot)])
2657
+ );
2658
+ const tsconfigAliases = loadTsconfigAliases(uniqueRoots);
2659
+ function resolveAlias(specifier) {
2660
+ for (const mapping of tsconfigAliases) {
2661
+ if (specifier === mapping.prefix) {
2662
+ const found = tryResolveLocalModule(mapping.targetDir);
2663
+ if (found) return found;
2664
+ } else if (specifier.startsWith(mapping.prefix + "/")) {
2665
+ const rel = specifier.slice(mapping.prefix.length + 1);
2666
+ const found = tryResolveLocalModule(path.join(mapping.targetDir, rel));
2667
+ if (found) return found;
2668
+ }
2669
+ }
2670
+ if (specifier.startsWith("@/") || specifier.startsWith("~/")) {
2671
+ const rel = specifier.slice(2);
2672
+ for (const r of uniqueRoots) {
2673
+ const direct = tryResolveLocalModule(path.join(r, rel));
2674
+ if (direct) return direct;
2675
+ const inSrc = tryResolveLocalModule(path.join(r, "src", rel));
2676
+ if (inSrc) return inSrc;
2677
+ }
2678
+ }
2679
+ return null;
2680
+ }
2681
+ function resolveLocalOrAliasFile(specifier) {
2682
+ if (specifier.startsWith(".")) {
2683
+ const candidate = path.resolve(path.dirname(cleanFilePath), specifier);
2684
+ return tryResolveLocalModule(candidate);
2685
+ }
2686
+ if (specifier.startsWith("@/") || specifier.startsWith("~/") || tsconfigAliases.some((m) => specifier === m.prefix || specifier.startsWith(m.prefix + "/"))) {
2687
+ return resolveAlias(specifier);
2688
+ }
2689
+ return null;
2690
+ }
2691
+ function rewriteResolvedLocalFile(resolved, requestedExports) {
2692
+ const normalized = resolved.replace(/\\/g, "/");
2693
+ if (normalized.endsWith("/src/runtime/MockNavigationContext.tsx")) {
2694
+ return `/@zelune/shim/stub.js?pkg=zelune-mock-nav&exports=${encodeURIComponent(
2695
+ requestedExports.join(",")
2696
+ )}`;
2697
+ }
2698
+ if (normalized.endsWith("/src/runtime/reactNativeShim.ts")) {
2699
+ return "/@zelune/shim/react-native.js";
2700
+ }
2701
+ const vSuffix = versionTag ? `&t=${encodeURIComponent(versionTag)}` : "";
2702
+ return `/@zelune/module?file=${encodeURIComponent(resolved)}${vSuffix}`;
2703
+ }
2704
+ function rewriteSpecifier(specifier, requestedExports) {
2705
+ if (specifier === "react" || specifier === "react/jsx-runtime" || specifier === "react/jsx-dev-runtime") {
2706
+ return "/@zelune/shim/react.js";
2707
+ }
2708
+ if (specifier === "react-dom" || specifier === "react-dom/client") {
2709
+ return "/@zelune/shim/react-dom.js";
2710
+ }
2711
+ if (specifier === "react-native" || specifier === "react-native-web") {
2712
+ return "/@zelune/shim/react-native.js";
2713
+ }
2714
+ if (specifier === "lucide-react" || specifier === "lucide-react-native") {
2715
+ return `/@zelune/shim/lucide.js?exports=${encodeURIComponent(requestedExports.join(","))}`;
2716
+ }
2717
+ if (specifier.startsWith(".") || specifier.startsWith("@/") || specifier.startsWith("~/") || tsconfigAliases.some((m) => specifier === m.prefix || specifier.startsWith(m.prefix + "/"))) {
2718
+ const resolved = resolveLocalOrAliasFile(specifier);
2719
+ if (resolved) {
2720
+ return rewriteResolvedLocalFile(resolved, requestedExports);
2721
+ }
2722
+ return `/@zelune/shim/stub.js?pkg=${encodeURIComponent(specifier)}&exports=${encodeURIComponent(
2723
+ requestedExports.join(",")
2724
+ )}`;
2725
+ }
2726
+ return `/@zelune/shim/stub.js?pkg=${encodeURIComponent(specifier)}&exports=${encodeURIComponent(
2727
+ requestedExports.join(",")
2728
+ )}`;
2729
+ }
2730
+ const sideEffectImportNodes = /* @__PURE__ */ new WeakSet();
2731
+ for (const stmt of ast.program.body) {
2732
+ if (stmt.type === "ImportDeclaration" && stmt.specifiers.length === 0 && stmt.importKind !== "type") {
2733
+ sideEffectImportNodes.add(stmt);
2734
+ }
2735
+ }
2736
+ stripTypeScriptAndTransformJsxAst(ast, () => {
2737
+ emittedJsx = true;
2738
+ });
2739
+ const hoistedRequireImports = [];
2740
+ let reqCounter = 0;
2741
+ function transformRequireCalls(node) {
2742
+ var _a, _b;
2743
+ if (!node || typeof node !== "object") return node;
2744
+ if (Array.isArray(node)) {
2745
+ for (let i = 0; i < node.length; i++) {
2746
+ if (node[i]) node[i] = transformRequireCalls(node[i]);
2747
+ }
2748
+ return node;
2749
+ }
2750
+ for (const key of Object.keys(node)) {
2751
+ if (key === "loc" || key === "comments" || key === "leadingComments" || key === "trailingComments") {
2752
+ continue;
2753
+ }
2754
+ const val = node[key];
2755
+ if (val && typeof val === "object") {
2756
+ node[key] = transformRequireCalls(val);
2757
+ }
2758
+ }
2759
+ if (node.type === "CallExpression" && ((_a = node.callee) == null ? void 0 : _a.type) === "Identifier" && node.callee.name === "require" && Array.isArray(node.arguments) && node.arguments.length === 1 && ((_b = node.arguments[0]) == null ? void 0 : _b.type) === "StringLiteral") {
2760
+ const rawSpec = node.arguments[0].value;
2761
+ const localResolved = resolveLocalOrAliasFile(rawSpec);
2762
+ if (localResolved && ASSET_EXT_REGEX.test(path.extname(localResolved))) {
2763
+ const assetUrl = `/@zelune/asset?file=${encodeURIComponent(localResolved)}`;
2764
+ return t.objectExpression([
2765
+ t.objectProperty(t.identifier("uri"), t.stringLiteral(assetUrl))
2766
+ ]);
2767
+ }
2768
+ if (ASSET_EXT_REGEX.test(rawSpec)) {
2769
+ return t.objectExpression([
2770
+ t.objectProperty(t.identifier("uri"), t.stringLiteral(""))
2771
+ ]);
2772
+ }
2773
+ const reqIdent = t.identifier(`__zeluneReq_${reqCounter++}`);
2774
+ const rewritten = localResolved ? rewriteResolvedLocalFile(localResolved, []) : rewriteSpecifier(rawSpec, []);
2775
+ hoistedRequireImports.push(
2776
+ t.importDeclaration([t.importNamespaceSpecifier(reqIdent)], t.stringLiteral(rewritten))
2777
+ );
2778
+ return t.logicalExpression(
2779
+ "??",
2780
+ t.optionalMemberExpression(reqIdent, t.identifier("default"), false, true),
2781
+ reqIdent
2782
+ );
2783
+ }
2784
+ return node;
2785
+ }
2786
+ transformRequireCalls(ast.program.body);
2787
+ const runtimeReferencedIds = collectRuntimeReferencedIdentifiers(ast.program.body);
2788
+ const elidedBody = [];
2789
+ for (const stmt of ast.program.body) {
2790
+ if (stmt.type === "ImportDeclaration") {
2791
+ if (sideEffectImportNodes.has(stmt)) {
2792
+ elidedBody.push(stmt);
2793
+ continue;
2794
+ }
2795
+ stmt.specifiers = stmt.specifiers.filter((spec) => runtimeReferencedIds.has(spec.local.name));
2796
+ if (stmt.specifiers.length > 0) {
2797
+ elidedBody.push(stmt);
2798
+ }
2799
+ continue;
2800
+ }
2801
+ if (stmt.type === "ExportNamedDeclaration" && stmt.source && !stmt.declaration && stmt.specifiers.length > 0) {
2802
+ const localTarget = resolveLocalOrAliasFile(stmt.source.value);
2803
+ if (localTarget) {
2804
+ const typeOnlyNames = getLocalTypeOnlyDeclaredNames(localTarget);
2805
+ if (typeOnlyNames.size > 0) {
2806
+ stmt.specifiers = stmt.specifiers.filter((spec) => {
2807
+ if (spec.type !== "ExportSpecifier") return true;
2808
+ return !typeOnlyNames.has(spec.local.name);
2809
+ });
2810
+ if (stmt.specifiers.length === 0) {
2811
+ continue;
2812
+ }
2813
+ }
2814
+ }
2815
+ }
2816
+ elidedBody.push(stmt);
2817
+ }
2818
+ ast.program.body = elidedBody;
2819
+ const namespaceLocals = /* @__PURE__ */ new Set();
2820
+ for (const stmt of ast.program.body) {
2821
+ if (stmt.type === "ImportDeclaration") {
2822
+ for (const spec of stmt.specifiers) {
2823
+ if (spec.type === "ImportNamespaceSpecifier") {
2824
+ namespaceLocals.add(spec.local.name);
2825
+ }
2826
+ }
2827
+ }
2828
+ }
2829
+ const namespaceMemberMap = collectNamespaceMemberAccesses(ast, namespaceLocals);
2830
+ for (const stmt of ast.program.body) {
2831
+ if (stmt.type === "ImportDeclaration") {
2832
+ const requested = [];
2833
+ for (const spec of stmt.specifiers) {
2834
+ if (spec.type === "ImportSpecifier") {
2835
+ const importedName = spec.imported.type === "Identifier" ? spec.imported.name : spec.imported.value;
2836
+ if (importedName && importedName !== "default") {
2837
+ requested.push(importedName);
2838
+ }
2839
+ } else if (spec.type === "ImportNamespaceSpecifier") {
2840
+ const accessed = namespaceMemberMap.get(spec.local.name);
2841
+ if (accessed) {
2842
+ for (const memberName of accessed) {
2843
+ if (memberName !== "default") requested.push(memberName);
2844
+ }
2845
+ }
2846
+ }
2847
+ }
2848
+ stmt.source.value = rewriteSpecifier(stmt.source.value, requested);
2849
+ } else if ((stmt.type === "ExportNamedDeclaration" || stmt.type === "ExportAllDeclaration") && stmt.source) {
2850
+ const requested = [];
2851
+ if (stmt.type === "ExportNamedDeclaration") {
2852
+ for (const spec of stmt.specifiers) {
2853
+ if (spec.type === "ExportSpecifier") {
2854
+ const localName = spec.local.name;
2855
+ const exportedName = spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value;
2856
+ if (localName && localName !== "default") requested.push(localName);
2857
+ if (exportedName && exportedName !== "default") requested.push(exportedName);
2858
+ }
2859
+ }
2860
+ }
2861
+ stmt.source.value = rewriteSpecifier(stmt.source.value, requested);
2862
+ }
2863
+ }
2864
+ if (hoistedRequireImports.length > 0) {
2865
+ ast.program.body.unshift(...hoistedRequireImports);
2866
+ }
2867
+ if (emittedJsx) {
2868
+ ast.program.body.unshift(
2869
+ t.importDeclaration(
2870
+ [t.importDefaultSpecifier(t.identifier(ZELUNE_JSX_REACT_IDENT))],
2871
+ t.stringLiteral("/@zelune/shim/react.js")
2872
+ )
2873
+ );
2874
+ }
2875
+ const out = generate(ast, {
2876
+ retainLines: false,
2877
+ compact: false
2878
+ });
2879
+ return out.code;
2880
+ }
2881
+ function extractStaticAstValue(node, scope, depth = 0) {
2882
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2883
+ if (!node || depth > 12) return void 0;
2884
+ switch (node.type) {
2885
+ case "StringLiteral":
2886
+ case "NumericLiteral":
2887
+ case "BooleanLiteral":
2888
+ return node.value;
2889
+ case "NullLiteral":
2890
+ return null;
2891
+ case "UnaryExpression": {
2892
+ const arg = extractStaticAstValue(node.argument, scope, depth + 1);
2893
+ if (typeof arg === "number") {
2894
+ if (node.operator === "-") return -arg;
2895
+ if (node.operator === "+") return +arg;
2896
+ }
2897
+ return void 0;
2898
+ }
2899
+ case "TemplateLiteral": {
2900
+ if (Array.isArray(node.expressions) && node.expressions.length === 0) {
2901
+ return ((_c = (_b = (_a = node.quasis) == null ? void 0 : _a[0]) == null ? void 0 : _b.value) == null ? void 0 : _c.cooked) ?? ((_f = (_e = (_d = node.quasis) == null ? void 0 : _d[0]) == null ? void 0 : _e.value) == null ? void 0 : _f.raw) ?? "";
2902
+ }
2903
+ return void 0;
2904
+ }
2905
+ case "ArrayExpression": {
2906
+ const items = [];
2907
+ for (const el of node.elements ?? []) {
2908
+ if (!el) continue;
2909
+ if (el.type === "SpreadElement") {
2910
+ const spreadVal = extractStaticAstValue(el.argument, scope, depth + 1);
2911
+ if (Array.isArray(spreadVal)) items.push(...spreadVal);
2912
+ } else {
2913
+ const val = extractStaticAstValue(el, scope, depth + 1);
2914
+ if (val !== void 0) items.push(val);
2915
+ }
2916
+ }
2917
+ return items;
2918
+ }
2919
+ case "ObjectExpression": {
2920
+ const result = {};
2921
+ for (const prop of node.properties ?? []) {
2922
+ if (prop.type === "SpreadElement") {
2923
+ const spreadObj = extractStaticAstValue(prop.argument, scope, depth + 1);
2924
+ if (spreadObj && typeof spreadObj === "object" && !Array.isArray(spreadObj)) {
2925
+ Object.assign(result, spreadObj);
2926
+ }
2927
+ continue;
2928
+ }
2929
+ if (prop.type !== "ObjectProperty" || prop.computed) continue;
2930
+ const key = ((_g = prop.key) == null ? void 0 : _g.type) === "Identifier" ? prop.key.name : ((_h = prop.key) == null ? void 0 : _h.type) === "StringLiteral" || ((_i = prop.key) == null ? void 0 : _i.type) === "NumericLiteral" ? String(prop.key.value) : null;
2931
+ if (!key) continue;
2932
+ const val = extractStaticAstValue(prop.value, scope, depth + 1);
2933
+ if (val !== void 0) {
2934
+ result[key] = val;
2935
+ }
2936
+ }
2937
+ return result;
2938
+ }
2939
+ case "TSAsExpression":
2940
+ case "TSSatisfiesExpression":
2941
+ case "TSTypeAssertion":
2942
+ case "ParenthesizedExpression":
2943
+ return extractStaticAstValue(node.expression, scope, depth + 1);
2944
+ case "Identifier":
2945
+ return scope.get(node.name);
2946
+ default:
2947
+ return void 0;
2948
+ }
2949
+ }
2950
+ function parseTailwindConfigSource(raw) {
2951
+ try {
2952
+ const ast = parse(raw, {
2953
+ sourceType: "unambiguous",
2954
+ plugins: ["typescript", "jsx"],
2955
+ errorRecovery: true
2956
+ });
2957
+ const scope = /* @__PURE__ */ new Map();
2958
+ let exportedConfig;
2959
+ for (const stmt of ast.program.body) {
2960
+ if (stmt.type === "VariableDeclaration") {
2961
+ for (const decl of stmt.declarations) {
2962
+ if (decl.id.type === "Identifier" && decl.init) {
2963
+ const val = extractStaticAstValue(decl.init, scope);
2964
+ if (val !== void 0) {
2965
+ scope.set(decl.id.name, val);
2966
+ }
2967
+ }
2968
+ }
2969
+ } else if (stmt.type === "ExportDefaultDeclaration") {
2970
+ exportedConfig = extractStaticAstValue(stmt.declaration, scope);
2971
+ } else if (stmt.type === "ExpressionStatement" && stmt.expression.type === "AssignmentExpression") {
2972
+ const left = stmt.expression.left;
2973
+ if (left.type === "MemberExpression" && left.object.type === "Identifier" && left.property.type === "Identifier" && (left.object.name === "module" && left.property.name === "exports" || left.object.name === "exports" && left.property.name === "default")) {
2974
+ exportedConfig = extractStaticAstValue(stmt.expression.right, scope);
2975
+ }
2976
+ }
2977
+ }
2978
+ const cfg = exportedConfig;
2979
+ if ((cfg == null ? void 0 : cfg.theme) && typeof cfg.theme === "object") {
2980
+ const baseTheme = { ...cfg.theme };
2981
+ const extendTheme = cfg.theme.extend && typeof cfg.theme.extend === "object" ? cfg.theme.extend : {};
2982
+ delete baseTheme.extend;
2983
+ const merged = { ...baseTheme };
2984
+ for (const [k, v] of Object.entries(extendTheme)) {
2985
+ if (v && typeof v === "object" && !Array.isArray(v)) {
2986
+ merged[k] = {
2987
+ ...baseTheme[k] ?? {},
2988
+ ...v
2989
+ };
2990
+ } else {
2991
+ merged[k] = v;
2992
+ }
2993
+ }
2994
+ return merged;
2995
+ }
2996
+ } catch {
2997
+ }
2998
+ return {};
2999
+ }
3000
+ function loadProjectTailwindTheme(roots) {
3001
+ const candidates = [
3002
+ "tailwind.config.js",
3003
+ "tailwind.config.cjs",
3004
+ "tailwind.config.mjs",
3005
+ "tailwind.config.ts"
3006
+ ];
3007
+ const uniqueRoots = Array.from(new Set(roots.map((r) => path.resolve(r))));
3008
+ for (const rootDir of uniqueRoots) {
3009
+ for (const fileName of candidates) {
3010
+ const fullPath = path.join(rootDir, fileName);
3011
+ try {
3012
+ if (!fs$1.existsSync(fullPath)) continue;
3013
+ const raw = fs$1.readFileSync(fullPath, "utf-8");
3014
+ const parsedTheme = parseTailwindConfigSource(raw);
3015
+ if (Object.keys(parsedTheme).length > 0) {
3016
+ return parsedTheme;
3017
+ }
3018
+ } catch {
3019
+ }
3020
+ }
3021
+ }
3022
+ return {};
3023
+ }
3024
+ const MIME_TYPES = {
3025
+ ".html": "text/html; charset=utf-8",
3026
+ ".js": "application/javascript; charset=utf-8",
3027
+ ".mjs": "application/javascript; charset=utf-8",
3028
+ ".css": "text/css; charset=utf-8",
3029
+ ".json": "application/json; charset=utf-8",
3030
+ ".svg": "image/svg+xml",
3031
+ ".png": "image/png",
3032
+ ".jpg": "image/jpeg",
3033
+ ".jpeg": "image/jpeg",
3034
+ ".webp": "image/webp",
3035
+ ".gif": "image/gif",
3036
+ ".avif": "image/avif",
3037
+ ".bmp": "image/bmp",
3038
+ ".ico": "image/x-icon",
3039
+ ".ttf": "font/ttf",
3040
+ ".otf": "font/otf",
3041
+ ".woff": "font/woff",
3042
+ ".woff2": "font/woff2",
3043
+ ".mp3": "audio/mpeg",
3044
+ ".wav": "audio/wav",
3045
+ ".mp4": "video/mp4",
3046
+ ".webm": "video/webm"
3047
+ };
3048
+ const REACT_EXPORTS = [
3049
+ "Children",
3050
+ "Component",
3051
+ "Fragment",
3052
+ "Profiler",
3053
+ "PureComponent",
3054
+ "StrictMode",
3055
+ "Suspense",
3056
+ "cloneElement",
3057
+ "createContext",
3058
+ "createElement",
3059
+ "createFactory",
3060
+ "createRef",
3061
+ "forwardRef",
3062
+ "isValidElement",
3063
+ "lazy",
3064
+ "memo",
3065
+ "startTransition",
3066
+ "useCallback",
3067
+ "useContext",
3068
+ "useDebugValue",
3069
+ "useDeferredValue",
3070
+ "useEffect",
3071
+ "useId",
3072
+ "useImperativeHandle",
3073
+ "useInsertionEffect",
3074
+ "useLayoutEffect",
3075
+ "useMemo",
3076
+ "useReducer",
3077
+ "useRef",
3078
+ "useState",
3079
+ "useSyncExternalStore",
3080
+ "useTransition",
3081
+ "version"
3082
+ ];
3083
+ const REACT_NATIVE_EXPORTS = [
3084
+ "View",
3085
+ "Text",
3086
+ "Pressable",
3087
+ "TouchableOpacity",
3088
+ "TouchableHighlight",
3089
+ "TouchableWithoutFeedback",
3090
+ "TouchableNativeFeedback",
3091
+ "ScrollView",
3092
+ "FlatList",
3093
+ "SectionList",
3094
+ "VirtualizedList",
3095
+ "KeyboardAvoidingView",
3096
+ "TextInput",
3097
+ "Image",
3098
+ "ImageBackground",
3099
+ "SafeAreaView",
3100
+ "ActivityIndicator",
3101
+ "Switch",
3102
+ "Modal",
3103
+ "Button",
3104
+ "RefreshControl",
3105
+ "StatusBar",
3106
+ "StyleSheet",
3107
+ "Platform",
3108
+ "Dimensions",
3109
+ "useWindowDimensions",
3110
+ "PixelRatio",
3111
+ "Animated",
3112
+ "useAnimatedValue",
3113
+ "Easing",
3114
+ "Alert",
3115
+ "Linking",
3116
+ "Share",
3117
+ "Vibration",
3118
+ "Keyboard",
3119
+ "BackHandler",
3120
+ "AppState",
3121
+ "Appearance",
3122
+ "useColorScheme",
3123
+ "PanResponder",
3124
+ "LayoutAnimation",
3125
+ "UIManager",
3126
+ "InteractionManager",
3127
+ "NativeEventEmitter",
3128
+ "DeviceEventEmitter",
3129
+ "NativeAppEventEmitter",
3130
+ "NativeModules",
3131
+ "I18nManager",
3132
+ "AccessibilityInfo",
3133
+ "LogBox",
3134
+ "YellowBox",
3135
+ "findNodeHandle",
3136
+ "processColor",
3137
+ "PermissionsAndroid",
3138
+ "ToastAndroid",
3139
+ "ActionSheetIOS",
3140
+ "InputAccessoryView",
3141
+ "DrawerLayoutAndroid",
3142
+ "TurboModuleRegistry",
3143
+ "requireNativeComponent",
3144
+ "codegenNativeComponent",
3145
+ "PlatformColor",
3146
+ "DynamicColorIOS",
3147
+ "DevSettings",
3148
+ "Systrace",
3149
+ "Networking",
3150
+ "Settings"
3151
+ ];
3152
+ const DEFAULT_MOCK_NAV_EXPORTS = [
3153
+ "MockNavigationProvider",
3154
+ "useNavigation",
3155
+ "useRoute",
3156
+ "useFocusEffect",
3157
+ "useIsFocused",
3158
+ "useScrollToTop",
3159
+ "NavigationContainer",
3160
+ "CommonActions",
3161
+ "StackActions",
3162
+ "createNativeStackNavigator",
3163
+ "createStackNavigator",
3164
+ "createBottomTabNavigator",
3165
+ "createDrawerNavigator",
3166
+ "createMaterialTopTabNavigator",
3167
+ "DefaultTheme",
3168
+ "DarkTheme",
3169
+ "ThemeProvider",
3170
+ "useTheme",
3171
+ "useNavigationContainerRef",
3172
+ "useRouter",
3173
+ "router",
3174
+ "useLocalSearchParams",
3175
+ "useGlobalSearchParams",
3176
+ "usePathname",
3177
+ "useSegments",
3178
+ "useRootNavigationState",
3179
+ "Link",
3180
+ "Redirect",
3181
+ "Stack",
3182
+ "Tabs",
3183
+ "Drawer",
3184
+ "Slot",
3185
+ "SplashScreen",
3186
+ "SafeAreaProvider",
3187
+ "SafeAreaView",
3188
+ "useSafeAreaInsets",
3189
+ "useSafeAreaFrame",
3190
+ "SafeAreaInsetsContext",
3191
+ "SafeAreaFrameContext",
3192
+ "withSafeAreaInsets",
3193
+ "initialWindowMetrics",
3194
+ "StatusBar",
3195
+ "createVectorIconComponent",
3196
+ "Ionicons",
3197
+ "Feather",
3198
+ "MaterialIcons",
3199
+ "MaterialCommunityIcons",
3200
+ "FontAwesome",
3201
+ "FontAwesome5",
3202
+ "FontAwesome6",
3203
+ "AntDesign",
3204
+ "Entypo",
3205
+ "EvilIcons",
3206
+ "Foundation",
3207
+ "Octicons",
3208
+ "SimpleLineIcons",
3209
+ "Zocial",
3210
+ "Fontisto",
3211
+ "createIconSet",
3212
+ "createIconSetFromIcoMoon",
3213
+ "createIconSetFromFontello",
3214
+ "LinearGradient",
3215
+ "BlurView",
3216
+ "Image",
3217
+ "ImageBackground",
3218
+ "FlashList",
3219
+ "Svg",
3220
+ "Circle",
3221
+ "Ellipse",
3222
+ "G",
3223
+ "SvgText",
3224
+ "TSpan",
3225
+ "TextPath",
3226
+ "Path",
3227
+ "Polygon",
3228
+ "Polyline",
3229
+ "Line",
3230
+ "Rect",
3231
+ "Use",
3232
+ "SvgImage",
3233
+ "Symbol",
3234
+ "Defs",
3235
+ "RadialGradient",
3236
+ "Stop",
3237
+ "ClipPath",
3238
+ "Pattern",
3239
+ "Mask",
3240
+ "ForeignObject",
3241
+ "SvgXml",
3242
+ "SvgUri",
3243
+ "FadeIn",
3244
+ "FadeInDown",
3245
+ "FadeInUp",
3246
+ "FadeInLeft",
3247
+ "FadeInRight",
3248
+ "FadeOut",
3249
+ "FadeOutDown",
3250
+ "FadeOutUp",
3251
+ "SlideInDown",
3252
+ "SlideInUp",
3253
+ "SlideInLeft",
3254
+ "SlideInRight",
3255
+ "SlideOutDown",
3256
+ "SlideOutUp",
3257
+ "SlideOutLeft",
3258
+ "SlideOutRight",
3259
+ "ZoomIn",
3260
+ "ZoomOut",
3261
+ "Layout",
3262
+ "LinearTransition",
3263
+ "SequencedTransition",
3264
+ "FadingTransition",
3265
+ "useSharedValue",
3266
+ "useAnimatedStyle",
3267
+ "useDerivedValue",
3268
+ "useAnimatedProps",
3269
+ "useAnimatedScrollHandler",
3270
+ "useAnimatedRef",
3271
+ "useAnimatedGestureHandler",
3272
+ "withTiming",
3273
+ "withSpring",
3274
+ "withDelay",
3275
+ "withSequence",
3276
+ "withRepeat",
3277
+ "cancelAnimation",
3278
+ "runOnJS",
3279
+ "runOnUI",
3280
+ "interpolate",
3281
+ "Extrapolation",
3282
+ "Extrapolate",
3283
+ "Easing",
3284
+ "createAnimatedComponent",
3285
+ "Animated",
3286
+ "GestureHandlerRootView",
3287
+ "ScrollView",
3288
+ "FlatList",
3289
+ "TouchableOpacity",
3290
+ "TouchableHighlight",
3291
+ "TouchableWithoutFeedback",
3292
+ "Pressable",
3293
+ "Swipeable",
3294
+ "DrawerLayout",
3295
+ "PanGestureHandler",
3296
+ "TapGestureHandler",
3297
+ "LongPressGestureHandler",
3298
+ "GestureDetector",
3299
+ "Gesture",
3300
+ "State",
3301
+ "Directions",
3302
+ "ImpactFeedbackStyle",
3303
+ "NotificationFeedbackType",
3304
+ "impactAsync",
3305
+ "notificationAsync",
3306
+ "selectionAsync",
3307
+ "Constants",
3308
+ "useFonts",
3309
+ "loadAsync",
3310
+ "isLoaded",
3311
+ "preventAutoHideAsync",
3312
+ "hideAsync",
3313
+ "AsyncStorage",
3314
+ "getItemAsync",
3315
+ "setItemAsync",
3316
+ "deleteItemAsync",
3317
+ "setStringAsync",
3318
+ "getStringAsync",
3319
+ "openURL",
3320
+ "createURL",
3321
+ "create",
3322
+ "useStore",
3323
+ "QueryClient",
3324
+ "QueryClientProvider",
3325
+ "useQueryClient",
3326
+ "useQuery",
3327
+ "useInfiniteQuery",
3328
+ "useMutation",
3329
+ "createSafeChainableProxy",
3330
+ "SAFE_CHAINABLE_PROXY",
3331
+ "z",
3332
+ "string",
3333
+ "number",
3334
+ "boolean",
3335
+ "object",
3336
+ "array",
3337
+ "union",
3338
+ "literal",
3339
+ "record",
3340
+ "tuple",
3341
+ "any",
3342
+ "unknown",
3343
+ "optional",
3344
+ "nullable",
3345
+ "coerce",
3346
+ "zodResolver",
3347
+ "yupResolver",
3348
+ "scale",
3349
+ "verticalScale",
3350
+ "moderateScale",
3351
+ "moderateVerticalScale",
3352
+ "s",
3353
+ "vs",
3354
+ "ms",
3355
+ "mvs",
3356
+ "RFValue",
3357
+ "RFPercentage",
3358
+ "widthPercentageToDP",
3359
+ "heightPercentageToDP",
3360
+ "wp",
3361
+ "hp",
3362
+ "clsx",
3363
+ "cn",
3364
+ "twMerge",
3365
+ "styled",
3366
+ "cssInterop",
3367
+ "remapProps",
3368
+ "tw",
3369
+ "createTw",
3370
+ "useForm",
3371
+ "useFormContext",
3372
+ "FormProvider",
3373
+ "useWatch",
3374
+ "useFieldArray",
3375
+ "Controller",
3376
+ "SAFE_CONTEXT_FALLBACK",
3377
+ "createClient"
3378
+ ];
3379
+ function safeRealpath(targetPath) {
3380
+ try {
3381
+ return fs$1.realpathSync(targetPath);
3382
+ } catch {
3383
+ return path.resolve(targetPath);
3384
+ }
3385
+ }
3386
+ function sendJson(res, status, payload) {
3387
+ res.statusCode = status;
3388
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
3389
+ res.setHeader("X-Content-Type-Options", "nosniff");
3390
+ res.end(JSON.stringify(payload));
3391
+ }
3392
+ function sendJs(res, code) {
3393
+ res.statusCode = 200;
3394
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
3395
+ res.setHeader("Cache-Control", "no-store");
3396
+ res.setHeader("X-Content-Type-Options", "nosniff");
3397
+ res.end(code);
3398
+ }
3399
+ function buildReactShimModule() {
3400
+ const lines = [
3401
+ `const R = window.__ZELUNE_RUNTIME__.React;`,
3402
+ `export default R;`,
3403
+ `export const jsx = R.createElement;`,
3404
+ `export const jsxs = R.createElement;`,
3405
+ `export const jsxDEV = R.createElement;`
3406
+ ];
3407
+ for (const name of REACT_EXPORTS) {
3408
+ lines.push(`export const ${name} = R.${name};`);
3409
+ }
3410
+ return lines.join("\n");
3411
+ }
3412
+ function buildReactDomShimModule() {
3413
+ return [
3414
+ `const RD = window.__ZELUNE_RUNTIME__.ReactDOM;`,
3415
+ `export default RD;`,
3416
+ `export const createRoot = RD.createRoot;`,
3417
+ `export const hydrateRoot = RD.hydrateRoot;`,
3418
+ `export const flushSync = RD.flushSync;`,
3419
+ `export const createPortal = RD.createPortal;`
3420
+ ].join("\n");
3421
+ }
3422
+ function buildReactNativeShimModule() {
3423
+ const lines = [
3424
+ `const RN = window.__ZELUNE_RUNTIME__.ReactNative;`,
3425
+ `export default RN.default || RN;`
3426
+ ];
3427
+ for (const name of REACT_NATIVE_EXPORTS) {
3428
+ lines.push(`export const ${name} = RN.${name};`);
3429
+ }
3430
+ return lines.join("\n");
3431
+ }
3432
+ function buildLucideShimModule(requestedNames) {
3433
+ const lines = [
3434
+ `const L = window.__ZELUNE_RUNTIME__.LucideIcons || {};`,
3435
+ `const M = window.__ZELUNE_RUNTIME__.MockNav || {};`,
3436
+ `export default L;`
3437
+ ];
3438
+ const unique = Array.from(
3439
+ new Set(
3440
+ requestedNames.map((s) => s.trim()).filter((s) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s) && s !== "default")
3441
+ )
3442
+ );
3443
+ for (const name of unique) {
3444
+ lines.push(
3445
+ `export const ${name} = L[${JSON.stringify(name)}] || M.createVectorIconComponent(${JSON.stringify(name)});`
3446
+ );
3447
+ }
3448
+ return lines.join("\n");
3449
+ }
3450
+ function buildUniversalStubModule(requestedNames) {
3451
+ const lines = [
3452
+ `const React = window.__ZELUNE_RUNTIME__.React;`,
3453
+ `const RN = window.__ZELUNE_RUNTIME__.ReactNative;`,
3454
+ `const M = window.__ZELUNE_RUNTIME__.MockNav;`,
3455
+ `export default M.default || M;`,
3456
+ `const COMPOUND_SUB_NAMES = ['Item', 'Header', 'Footer', 'Title', 'Content', 'Trigger', 'Portal', 'Overlay', 'Close', 'Action', 'Cancel', 'Description', 'Label', 'Group', 'Separator', 'Value', 'Icon', 'Viewport', 'Root', 'Screen', 'Navigator', 'Provider', 'Consumer'];`,
3457
+ `function createSubStub(displayName) {`,
3458
+ ` const Sub = React.forwardRef(function SubComp(props, ref) {`,
3459
+ ` const content = typeof props?.children === 'function' ? props.children(M.SAFE_CHAINABLE_PROXY) : props?.children;`,
3460
+ ` return React.createElement(RN.View, { style: props?.style, className: props?.className, ref }, content);`,
3461
+ ` });`,
3462
+ ` Sub.displayName = displayName;`,
3463
+ ` return Sub;`,
3464
+ `}`,
3465
+ `function createComponentStub(displayName) {`,
3466
+ ` const Comp = React.forwardRef(function StubComp(props, ref) {`,
3467
+ ` if (typeof props?.render === 'function') {`,
3468
+ ` return props.render({`,
3469
+ ` field: { name: props?.name ?? '', value: props?.defaultValue ?? '', onChange: () => undefined, onBlur: () => undefined, ref: () => undefined },`,
3470
+ ` fieldState: { invalid: false, isTouched: false, isDirty: false, error: undefined },`,
3471
+ ` formState: { errors: {}, isSubmitting: false, isValid: true },`,
3472
+ ` });`,
3473
+ ` }`,
3474
+ ` const content = typeof props?.children === 'function' ? props.children(M.SAFE_CHAINABLE_PROXY) : props?.children;`,
3475
+ ` return React.createElement(RN.View, { style: props?.style, className: props?.className, ref }, content);`,
3476
+ ` });`,
3477
+ ` Comp.displayName = displayName;`,
3478
+ ` for (const sub of COMPOUND_SUB_NAMES) {`,
3479
+ ` Comp[sub] = createSubStub(displayName + '.' + sub);`,
3480
+ ` }`,
3481
+ ` return Comp;`,
3482
+ `}`,
3483
+ `function resolveExport(name) {`,
3484
+ ` if (name in M) return M[name];`,
3485
+ ` if (M.default && name in M.default) return M.default[name];`,
3486
+ ` if (/^use[A-Z]/.test(name)) return () => M.SAFE_CHAINABLE_PROXY;`,
3487
+ ` if (/^[A-Z]/.test(name)) return createComponentStub(name);`,
3488
+ ` return M.SAFE_CHAINABLE_PROXY;`,
3489
+ `}`
3490
+ ];
3491
+ const unique = Array.from(
3492
+ new Set(
3493
+ [...DEFAULT_MOCK_NAV_EXPORTS, ...requestedNames].map((s) => s.trim()).filter((s) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s) && s !== "default")
3494
+ )
3495
+ );
3496
+ for (const name of unique) {
3497
+ lines.push(`export const ${name} = resolveExport(${JSON.stringify(name)});`);
3498
+ }
3499
+ return lines.join("\n");
3500
+ }
3501
+ async function resolveConnectedProjectName(workspaceRoot) {
3502
+ var _a;
3503
+ const activeRoot = getActiveProjectRoot(workspaceRoot);
3504
+ const dirName = path.basename(activeRoot);
3505
+ try {
3506
+ const appJsonRaw = await fs.readFile(path.join(activeRoot, "app.json"), "utf-8");
3507
+ const appJson = JSON.parse(appJsonRaw);
3508
+ if ((_a = appJson == null ? void 0 : appJson.expo) == null ? void 0 : _a.name) return appJson.expo.name;
3509
+ if (appJson == null ? void 0 : appJson.name) return appJson.name;
3510
+ } catch {
3511
+ }
3512
+ try {
3513
+ const pkgRaw = await fs.readFile(path.join(activeRoot, "package.json"), "utf-8");
3514
+ const pkg = JSON.parse(pkgRaw);
3515
+ if ((pkg == null ? void 0 : pkg.name) && pkg.name.toLowerCase() !== "zelune") {
3516
+ return pkg.name;
3517
+ }
3518
+ } catch {
3519
+ }
3520
+ return dirName;
3521
+ }
3522
+ async function startStudioHttpServer(options) {
3523
+ const { packageRoot, targetProjectRoot, workspaceRoot } = options;
3524
+ const distDir = path.resolve(packageRoot, "dist");
3525
+ const activeProjectRoot = getActiveProjectRoot(targetProjectRoot);
3526
+ const allowedRoots = Array.from(
3527
+ /* @__PURE__ */ new Set([
3528
+ path.resolve(packageRoot),
3529
+ safeRealpath(packageRoot),
3530
+ path.resolve(targetProjectRoot),
3531
+ safeRealpath(targetProjectRoot),
3532
+ path.resolve(activeProjectRoot),
3533
+ safeRealpath(activeProjectRoot),
3534
+ path.resolve(workspaceRoot),
3535
+ safeRealpath(workspaceRoot)
3536
+ ])
3537
+ );
3538
+ function resolveCandidateFileParam(rawParam) {
3539
+ const clean = rawParam.split("?")[0].trim();
3540
+ if (!clean) return null;
3541
+ const candidate = path.isAbsolute(clean) ? path.resolve(clean) : path.resolve(getActiveProjectRoot(targetProjectRoot), clean.replace(/^[/\\]+/, ""));
3542
+ const lexicallyAllowed = allowedRoots.some(
3543
+ (root) => candidate === root || candidate.startsWith(root + path.sep)
3544
+ );
3545
+ if (!lexicallyAllowed || !fs$1.existsSync(candidate)) {
3546
+ return null;
3547
+ }
3548
+ const real = safeRealpath(candidate);
3549
+ const canonicallyAllowed = allowedRoots.some(
3550
+ (root) => real === root || real.startsWith(root + path.sep)
3551
+ );
3552
+ if (!canonicallyAllowed) {
3553
+ return null;
3554
+ }
3555
+ return real;
3556
+ }
3557
+ const requestHandler = async (req, res) => {
3558
+ const rawUrl = req.url ?? "/";
3559
+ const qIdx = rawUrl.indexOf("?");
3560
+ const pathname = qIdx === -1 ? rawUrl : rawUrl.slice(0, qIdx);
3561
+ const searchParams = new URLSearchParams(qIdx === -1 ? "" : rawUrl.slice(qIdx + 1));
3562
+ if (pathname.startsWith("/api/")) {
3563
+ const securityCheck = verifyApiRequestSecurity(req);
3564
+ if (!securityCheck.allowed) {
3565
+ return sendJson(res, 403, { ok: false, error: securityCheck.reason });
3566
+ }
3567
+ const activeRoot = getActiveProjectRoot(targetProjectRoot);
3568
+ const layoutFilePath = path.resolve(activeRoot, ".canvas-layout.json");
3569
+ try {
3570
+ if (req.method === "GET" && pathname === "/api/screens") {
3571
+ const [screens, projectName] = await Promise.all([
3572
+ discoverScreens(targetProjectRoot),
3573
+ resolveConnectedProjectName(targetProjectRoot)
3574
+ ]);
3575
+ const history = getHistoryStatus();
3576
+ return sendJson(res, 200, { ok: true, projectName, screens, history });
3577
+ }
3578
+ if (req.method === "GET" && pathname === "/api/inspect") {
3579
+ const file = searchParams.get("file") ?? "";
3580
+ const astPath = searchParams.get("astPath") ?? "";
3581
+ const lineParam = searchParams.get("line");
3582
+ const line = lineParam ? Number.parseInt(lineParam, 10) : void 0;
3583
+ const element = await inspectElement(targetProjectRoot, { file, astPath, line });
3584
+ const history = getHistoryStatus();
3585
+ return sendJson(res, 200, { ok: true, element, history });
3586
+ }
3587
+ if (req.method === "POST" && pathname === "/api/patch") {
3588
+ const body = await readJsonBody(req);
3589
+ const result = await patchElement(targetProjectRoot, body);
3590
+ return sendJson(res, 200, {
3591
+ ok: true,
3592
+ element: result.element,
3593
+ history: {
3594
+ undoAvailable: result.undoAvailable,
3595
+ redoAvailable: result.redoAvailable
3596
+ }
3597
+ });
3598
+ }
3599
+ if (req.method === "POST" && pathname === "/api/reorder") {
3600
+ const body = await readJsonBody(req);
3601
+ const result = await reorderElement(targetProjectRoot, body);
3602
+ return sendJson(res, 200, {
3603
+ ok: true,
3604
+ element: result.element,
3605
+ history: {
3606
+ undoAvailable: result.undoAvailable,
3607
+ redoAvailable: result.redoAvailable
3608
+ }
3609
+ });
3610
+ }
3611
+ if (req.method === "POST" && pathname === "/api/insert") {
3612
+ const body = await readJsonBody(req);
3613
+ const result = await insertElement(targetProjectRoot, body);
3614
+ return sendJson(res, 200, {
3615
+ ok: true,
3616
+ element: result.element,
3617
+ history: {
3618
+ undoAvailable: result.undoAvailable,
3619
+ redoAvailable: result.redoAvailable
3620
+ }
3621
+ });
3622
+ }
3623
+ if (req.method === "POST" && pathname === "/api/duplicate") {
3624
+ const body = await readJsonBody(req);
3625
+ const result = await duplicateElement(targetProjectRoot, body);
3626
+ return sendJson(res, 200, {
3627
+ ok: true,
3628
+ element: result.element,
3629
+ history: {
3630
+ undoAvailable: result.undoAvailable,
3631
+ redoAvailable: result.redoAvailable
3632
+ }
3633
+ });
3634
+ }
3635
+ if (req.method === "POST" && pathname === "/api/delete") {
3636
+ const body = await readJsonBody(req);
3637
+ const result = await deleteElement(targetProjectRoot, body);
3638
+ return sendJson(res, 200, {
3639
+ ok: true,
3640
+ deletedAstPath: result.deletedAstPath,
3641
+ history: {
3642
+ undoAvailable: result.undoAvailable,
3643
+ redoAvailable: result.redoAvailable
3644
+ }
3645
+ });
3646
+ }
3647
+ if (req.method === "POST" && pathname === "/api/undo") {
3648
+ const result = await undoLastPatch(targetProjectRoot);
3649
+ return sendJson(res, 200, { ok: true, ...result });
3650
+ }
3651
+ if (req.method === "POST" && pathname === "/api/redo") {
3652
+ const result = await redoLastPatch(targetProjectRoot);
3653
+ return sendJson(res, 200, { ok: true, ...result });
3654
+ }
3655
+ if (req.method === "GET" && pathname === "/api/layout") {
3656
+ try {
3657
+ const raw = await fs.readFile(layoutFilePath, "utf-8");
3658
+ const validated = sanitizeLayoutPayload(JSON.parse(raw));
3659
+ return sendJson(res, 200, { ok: true, layout: validated });
3660
+ } catch {
3661
+ return sendJson(res, 200, { ok: true, layout: null });
3662
+ }
3663
+ }
3664
+ if (req.method === "POST" && pathname === "/api/layout") {
3665
+ const body = await readJsonBody(req);
3666
+ const validated = sanitizeLayoutPayload(body);
3667
+ await fs.writeFile(layoutFilePath, JSON.stringify(validated, null, 2), "utf-8");
3668
+ return sendJson(res, 200, { ok: true });
3669
+ }
3670
+ return sendJson(res, 404, { ok: false, error: `Unknown API route: ${pathname}` });
3671
+ } catch (err) {
3672
+ const message = err instanceof Error ? err.message : String(err);
3673
+ return sendJson(res, 400, { ok: false, error: message });
3674
+ }
3675
+ }
3676
+ if (pathname === "/@zelune/shim/react.js") {
3677
+ return sendJs(res, buildReactShimModule());
3678
+ }
3679
+ if (pathname === "/@zelune/shim/react-dom.js") {
3680
+ return sendJs(res, buildReactDomShimModule());
3681
+ }
3682
+ if (pathname === "/@zelune/shim/react-native.js") {
3683
+ return sendJs(res, buildReactNativeShimModule());
3684
+ }
3685
+ if (pathname === "/@zelune/shim/lucide.js") {
3686
+ const exportsParam = searchParams.get("exports") ?? "";
3687
+ return sendJs(res, buildLucideShimModule(exportsParam.split(",")));
3688
+ }
3689
+ if (pathname === "/@zelune/shim/stub.js") {
3690
+ const exportsParam = searchParams.get("exports") ?? "";
3691
+ return sendJs(res, buildUniversalStubModule(exportsParam.split(",")));
3692
+ }
3693
+ if (pathname === "/@zelune/module") {
3694
+ const fileParam = searchParams.get("file") ?? "";
3695
+ const versionTag = searchParams.get("t") ?? void 0;
3696
+ const resolvedFile = resolveCandidateFileParam(fileParam);
3697
+ if (!resolvedFile) {
3698
+ return sendJs(res, "// Module not found\nexport default {};\n");
3699
+ }
3700
+ try {
3701
+ const compiled = compileModuleForBrowser({
3702
+ filePath: resolvedFile,
3703
+ targetProjectRoot: getActiveProjectRoot(targetProjectRoot),
3704
+ workspaceRoot,
3705
+ versionTag
3706
+ });
3707
+ return sendJs(res, compiled);
3708
+ } catch (err) {
3709
+ const msg = err instanceof Error ? err.message : String(err);
3710
+ return sendJs(res, `throw new Error(${JSON.stringify(msg)});
3711
+ `);
3712
+ }
3713
+ }
3714
+ if (pathname === "/@zelune/asset") {
3715
+ const fileParam = searchParams.get("file") ?? "";
3716
+ const resolvedAsset = resolveCandidateFileParam(fileParam);
3717
+ if (!resolvedAsset) {
3718
+ res.statusCode = 404;
3719
+ return res.end("Not found");
3720
+ }
3721
+ const ext = path.extname(resolvedAsset).toLowerCase();
3722
+ res.statusCode = 200;
3723
+ res.setHeader("Content-Type", MIME_TYPES[ext] ?? "application/octet-stream");
3724
+ return fs$1.createReadStream(resolvedAsset).pipe(res);
3725
+ }
3726
+ if (pathname === "/" || pathname === "/index.html") {
3727
+ const indexHtmlPath = path.join(distDir, "index.html");
3728
+ if (!fs$1.existsSync(indexHtmlPath)) {
3729
+ res.statusCode = 500;
3730
+ return res.end("Zelune dist/index.html not found.");
3731
+ }
3732
+ const rawHtml = await fs.readFile(indexHtmlPath, "utf-8");
3733
+ const tailwindTheme = loadProjectTailwindTheme([targetProjectRoot, workspaceRoot]);
3734
+ const discoveredManifest = discoverScreenFilesSync(targetProjectRoot);
3735
+ const safeThemeJson = JSON.stringify(tailwindTheme).replace(/</g, "\\u003c");
3736
+ const safeManifestJson = JSON.stringify(discoveredManifest).replace(/</g, "\\u003c");
3737
+ const runtimeScript = `<script>window.__ZELUNE_STUDIO_SERVER__ = true; window.__ZELUNE_TAILWIND_THEME__ = ${safeThemeJson}; window.__ZELUNE_SCREEN_MANIFEST__ = ${safeManifestJson};<\/script>`;
3738
+ const injectedHtml = rawHtml.replace("<head>", `<head>
3739
+ ${runtimeScript}`);
3740
+ res.statusCode = 200;
3741
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
3742
+ res.setHeader("Cache-Control", "no-store");
3743
+ return res.end(injectedHtml);
3744
+ }
3745
+ const relativeAsset = pathname.replace(/^\/+/, "");
3746
+ const assetCandidate = path.resolve(distDir, relativeAsset);
3747
+ if (assetCandidate.startsWith(distDir + path.sep) && fs$1.existsSync(assetCandidate) && fs$1.statSync(assetCandidate).isFile()) {
3748
+ const ext = path.extname(assetCandidate).toLowerCase();
3749
+ res.statusCode = 200;
3750
+ res.setHeader("Content-Type", MIME_TYPES[ext] ?? "application/octet-stream");
3751
+ return fs$1.createReadStream(assetCandidate).pipe(res);
3752
+ }
3753
+ res.statusCode = 404;
3754
+ res.end("Not found");
3755
+ };
3756
+ const basePort = options.port ?? 5173;
3757
+ for (let offset = 0; offset < 25; offset++) {
3758
+ const candidatePort = basePort + offset;
3759
+ try {
3760
+ const srv = await new Promise((resolve, reject) => {
3761
+ const s = http.createServer(requestHandler);
3762
+ s.once("error", reject);
3763
+ s.listen(candidatePort, "127.0.0.1", () => {
3764
+ s.removeListener("error", reject);
3765
+ resolve(s);
3766
+ });
3767
+ });
3768
+ return { server: srv, port: candidatePort };
3769
+ } catch (err) {
3770
+ const code = err == null ? void 0 : err.code;
3771
+ if (code === "EADDRINUSE" && !options.port) {
3772
+ continue;
3773
+ }
3774
+ throw err;
3775
+ }
3776
+ }
3777
+ throw new Error(`Unable to bind Studio HTTP server starting from port ${basePort}`);
3778
+ }
1906
3779
  const __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
1907
3780
  const DEFAULT_WORKSPACE_ROOT = path.resolve(__dirname$1, "..");
1908
3781
  const MCP_TOOLS = [
@@ -2155,7 +4028,7 @@ async function handleMcpJsonRpcRequest(request, customWorkspaceRoot) {
2155
4028
  },
2156
4029
  serverInfo: {
2157
4030
  name: "zelune",
2158
- version: "1.6.3"
4031
+ version: "1.6.5"
2159
4032
  }
2160
4033
  }
2161
4034
  };
@@ -2254,7 +4127,7 @@ function startMcpServer(customWorkspaceRoot) {
2254
4127
  }
2255
4128
  const isDirectExecution = Boolean(process.argv[1]) && (() => {
2256
4129
  try {
2257
- return import.meta.url === pathToFileURL(fsSync.realpathSync(process.argv[1])).href;
4130
+ return import.meta.url === pathToFileURL(fs$1.realpathSync(process.argv[1])).href;
2258
4131
  } catch {
2259
4132
  return false;
2260
4133
  }
@@ -2265,5 +4138,6 @@ if (isDirectExecution) {
2265
4138
  export {
2266
4139
  MCP_TOOLS,
2267
4140
  handleMcpJsonRpcRequest,
2268
- startMcpServer
4141
+ startMcpServer,
4142
+ startStudioHttpServer
2269
4143
  };