leglas 0.4.0 → 0.4.1
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/README.md +5 -2
- package/dist/bin.js +71 -7
- package/dist/index.js +71 -7
- package/dist/shell/assets/index-B1hUXNY3.js +14 -0
- package/dist/shell/assets/index-DCg7pmCj.css +1 -0
- package/dist/shell/index.html +2 -2
- package/package.json +3 -3
- package/dist/shell/assets/index-BQHDjn0q.css +0 -1
- package/dist/shell/assets/index-T-uR7kT7.js +0 -14
package/README.md
CHANGED
|
@@ -286,8 +286,11 @@ trace.
|
|
|
286
286
|
## The interface
|
|
287
287
|
|
|
288
288
|
Directions live in a rail on the left. The stage shows the active one in
|
|
289
|
-
a framed viewport at Full, 1440, 834
|
|
290
|
-
and tag directions from the rail
|
|
289
|
+
a framed viewport at Full, 1440, 834 or 390 wide. Rename, reorder, hide
|
|
290
|
+
and tag directions from the rail. Open the removed list to restore a
|
|
291
|
+
direction, delete one permanently or clear the full list. Machine-local
|
|
292
|
+
directions are removed from `.leglas/previews.json`; shared project config
|
|
293
|
+
and preview source files stay untouched. Layout is saved per project and
|
|
291
294
|
survives restarts and port changes.
|
|
292
295
|
|
|
293
296
|
Flipping shows a difference over time. A split shows it at once, which is
|
package/dist/bin.js
CHANGED
|
@@ -973,8 +973,17 @@ async function readLocalPreviews(cwd) {
|
|
|
973
973
|
let raw;
|
|
974
974
|
try {
|
|
975
975
|
raw = await readFile3(path, "utf8");
|
|
976
|
-
} catch {
|
|
977
|
-
|
|
976
|
+
} catch (error) {
|
|
977
|
+
const code = error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : null;
|
|
978
|
+
if (code === "ENOENT") {
|
|
979
|
+
return { previews: [], errors: [] };
|
|
980
|
+
}
|
|
981
|
+
return {
|
|
982
|
+
previews: [],
|
|
983
|
+
errors: [
|
|
984
|
+
`${LOCAL_PREVIEWS_PATH} could not be read (${code ?? "unknown error"}). Check its permissions and file type; nothing shared is lost.`
|
|
985
|
+
]
|
|
986
|
+
};
|
|
978
987
|
}
|
|
979
988
|
let parsed2;
|
|
980
989
|
try {
|
|
@@ -1859,13 +1868,23 @@ async function startServer(options) {
|
|
|
1859
1868
|
const notice = configStalenessNotice(cwd, bootConfigSnapshot, snapshotConfig(cwd));
|
|
1860
1869
|
if (notice !== null)
|
|
1861
1870
|
errors.push(notice);
|
|
1862
|
-
return void readLocalPreviews(cwd).then(({ previews: local }) => {
|
|
1863
|
-
|
|
1871
|
+
return void readLocalPreviews(cwd).then(({ previews: local, errors: localErrors }) => {
|
|
1872
|
+
if (localErrors.length > 0) {
|
|
1873
|
+
return sendJson(res, 200, {
|
|
1874
|
+
project,
|
|
1875
|
+
devServer: target,
|
|
1876
|
+
previews: boot,
|
|
1877
|
+
errors
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
const localTitles = new Set(local.map((preview) => preview.title));
|
|
1881
|
+
const currentBoot = boot.filter((preview) => preview.local !== true || localTitles.has(preview.title));
|
|
1882
|
+
const known = new Set(currentBoot.map((preview) => preview.title));
|
|
1864
1883
|
const fresh = local.filter((preview) => !known.has(preview.title) && preview.branch === void 0 && preview.file === void 0);
|
|
1865
1884
|
sendJson(res, 200, {
|
|
1866
1885
|
project,
|
|
1867
1886
|
devServer: target,
|
|
1868
|
-
previews: [...
|
|
1887
|
+
previews: [...currentBoot, ...fresh],
|
|
1869
1888
|
errors
|
|
1870
1889
|
});
|
|
1871
1890
|
}).catch(() => sendJson(res, 200, {
|
|
@@ -1875,6 +1894,47 @@ async function startServer(options) {
|
|
|
1875
1894
|
errors
|
|
1876
1895
|
}));
|
|
1877
1896
|
}
|
|
1897
|
+
if (path === `${LEGLAS_PREFIX}/api/previews/delete` && req.method === "POST") {
|
|
1898
|
+
let body = "";
|
|
1899
|
+
req.on("data", (chunk) => body += chunk);
|
|
1900
|
+
return void req.on("end", async () => {
|
|
1901
|
+
let parsed2;
|
|
1902
|
+
try {
|
|
1903
|
+
parsed2 = JSON.parse(body || "{}");
|
|
1904
|
+
} catch {
|
|
1905
|
+
return sendJson(res, 400, { ok: false, error: "Body must be JSON." });
|
|
1906
|
+
}
|
|
1907
|
+
const titles = parsed2.titles;
|
|
1908
|
+
if (!Array.isArray(titles) || titles.length === 0 || titles.some((title) => typeof title !== "string" || title.trim() === "")) {
|
|
1909
|
+
return sendJson(res, 400, {
|
|
1910
|
+
ok: false,
|
|
1911
|
+
error: "Body needs a non-empty array of direction titles."
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
const unique = [...new Set(titles)];
|
|
1915
|
+
try {
|
|
1916
|
+
const local = await readLocalPreviews(cwd);
|
|
1917
|
+
if (local.errors.length > 0) {
|
|
1918
|
+
return sendJson(res, 409, { ok: false, error: local.errors.join(" ") });
|
|
1919
|
+
}
|
|
1920
|
+
const localTitles = new Set(local.previews.map((preview) => preview.title));
|
|
1921
|
+
const unknown = unique.filter((title) => !localTitles.has(title));
|
|
1922
|
+
if (unknown.length > 0) {
|
|
1923
|
+
return sendJson(res, 400, {
|
|
1924
|
+
ok: false,
|
|
1925
|
+
error: "Only machine-local directions can be deleted from the registry."
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
const deleted = await dropLocalPreviews(cwd, unique);
|
|
1929
|
+
return sendJson(res, 200, { ok: true, deleted });
|
|
1930
|
+
} catch {
|
|
1931
|
+
return sendJson(res, 500, {
|
|
1932
|
+
ok: false,
|
|
1933
|
+
error: "The directions could not be deleted from Leglas."
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1878
1938
|
if (path === `${LEGLAS_PREFIX}/api/request` && req.method === "POST") {
|
|
1879
1939
|
let body = "";
|
|
1880
1940
|
req.on("data", (chunk) => body += chunk);
|
|
@@ -1885,8 +1945,12 @@ async function startServer(options) {
|
|
|
1885
1945
|
} catch {
|
|
1886
1946
|
return sendJson(res, 400, { ok: false, error: "Body must be JSON." });
|
|
1887
1947
|
}
|
|
1888
|
-
const
|
|
1889
|
-
const
|
|
1948
|
+
const localRead = await readLocalPreviews(cwd).catch(() => null);
|
|
1949
|
+
const local = localRead?.errors.length === 0 ? localRead.previews : [];
|
|
1950
|
+
const localTitles = new Set(local.map((entry) => entry.title));
|
|
1951
|
+
const bootConfig = config?.previews ?? [];
|
|
1952
|
+
const boot = localRead === null || localRead.errors.length > 0 ? bootConfig : bootConfig.filter((entry) => entry.local !== true || localTitles.has(entry.title));
|
|
1953
|
+
const preview = [...boot, ...local].find((entry) => entry.title === parsed2.title);
|
|
1890
1954
|
if (!preview || !parsed2.intent?.trim()) {
|
|
1891
1955
|
return sendJson(res, 400, { ok: false, error: "Unknown preview, or empty request." });
|
|
1892
1956
|
}
|
package/dist/index.js
CHANGED
|
@@ -1333,8 +1333,17 @@ async function readLocalPreviews(cwd) {
|
|
|
1333
1333
|
let raw;
|
|
1334
1334
|
try {
|
|
1335
1335
|
raw = await readFile3(path, "utf8");
|
|
1336
|
-
} catch {
|
|
1337
|
-
|
|
1336
|
+
} catch (error) {
|
|
1337
|
+
const code = error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : null;
|
|
1338
|
+
if (code === "ENOENT") {
|
|
1339
|
+
return { previews: [], errors: [] };
|
|
1340
|
+
}
|
|
1341
|
+
return {
|
|
1342
|
+
previews: [],
|
|
1343
|
+
errors: [
|
|
1344
|
+
`${LOCAL_PREVIEWS_PATH} could not be read (${code ?? "unknown error"}). Check its permissions and file type; nothing shared is lost.`
|
|
1345
|
+
]
|
|
1346
|
+
};
|
|
1338
1347
|
}
|
|
1339
1348
|
let parsed;
|
|
1340
1349
|
try {
|
|
@@ -2219,13 +2228,23 @@ async function startServer(options) {
|
|
|
2219
2228
|
const notice = configStalenessNotice(cwd, bootConfigSnapshot, snapshotConfig(cwd));
|
|
2220
2229
|
if (notice !== null)
|
|
2221
2230
|
errors.push(notice);
|
|
2222
|
-
return void readLocalPreviews(cwd).then(({ previews: local }) => {
|
|
2223
|
-
|
|
2231
|
+
return void readLocalPreviews(cwd).then(({ previews: local, errors: localErrors }) => {
|
|
2232
|
+
if (localErrors.length > 0) {
|
|
2233
|
+
return sendJson(res, 200, {
|
|
2234
|
+
project,
|
|
2235
|
+
devServer: target,
|
|
2236
|
+
previews: boot,
|
|
2237
|
+
errors
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
const localTitles = new Set(local.map((preview) => preview.title));
|
|
2241
|
+
const currentBoot = boot.filter((preview) => preview.local !== true || localTitles.has(preview.title));
|
|
2242
|
+
const known = new Set(currentBoot.map((preview) => preview.title));
|
|
2224
2243
|
const fresh = local.filter((preview) => !known.has(preview.title) && preview.branch === void 0 && preview.file === void 0);
|
|
2225
2244
|
sendJson(res, 200, {
|
|
2226
2245
|
project,
|
|
2227
2246
|
devServer: target,
|
|
2228
|
-
previews: [...
|
|
2247
|
+
previews: [...currentBoot, ...fresh],
|
|
2229
2248
|
errors
|
|
2230
2249
|
});
|
|
2231
2250
|
}).catch(() => sendJson(res, 200, {
|
|
@@ -2235,6 +2254,47 @@ async function startServer(options) {
|
|
|
2235
2254
|
errors
|
|
2236
2255
|
}));
|
|
2237
2256
|
}
|
|
2257
|
+
if (path === `${LEGLAS_PREFIX}/api/previews/delete` && req.method === "POST") {
|
|
2258
|
+
let body = "";
|
|
2259
|
+
req.on("data", (chunk) => body += chunk);
|
|
2260
|
+
return void req.on("end", async () => {
|
|
2261
|
+
let parsed;
|
|
2262
|
+
try {
|
|
2263
|
+
parsed = JSON.parse(body || "{}");
|
|
2264
|
+
} catch {
|
|
2265
|
+
return sendJson(res, 400, { ok: false, error: "Body must be JSON." });
|
|
2266
|
+
}
|
|
2267
|
+
const titles = parsed.titles;
|
|
2268
|
+
if (!Array.isArray(titles) || titles.length === 0 || titles.some((title) => typeof title !== "string" || title.trim() === "")) {
|
|
2269
|
+
return sendJson(res, 400, {
|
|
2270
|
+
ok: false,
|
|
2271
|
+
error: "Body needs a non-empty array of direction titles."
|
|
2272
|
+
});
|
|
2273
|
+
}
|
|
2274
|
+
const unique = [...new Set(titles)];
|
|
2275
|
+
try {
|
|
2276
|
+
const local = await readLocalPreviews(cwd);
|
|
2277
|
+
if (local.errors.length > 0) {
|
|
2278
|
+
return sendJson(res, 409, { ok: false, error: local.errors.join(" ") });
|
|
2279
|
+
}
|
|
2280
|
+
const localTitles = new Set(local.previews.map((preview) => preview.title));
|
|
2281
|
+
const unknown = unique.filter((title) => !localTitles.has(title));
|
|
2282
|
+
if (unknown.length > 0) {
|
|
2283
|
+
return sendJson(res, 400, {
|
|
2284
|
+
ok: false,
|
|
2285
|
+
error: "Only machine-local directions can be deleted from the registry."
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
const deleted = await dropLocalPreviews(cwd, unique);
|
|
2289
|
+
return sendJson(res, 200, { ok: true, deleted });
|
|
2290
|
+
} catch {
|
|
2291
|
+
return sendJson(res, 500, {
|
|
2292
|
+
ok: false,
|
|
2293
|
+
error: "The directions could not be deleted from Leglas."
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
});
|
|
2297
|
+
}
|
|
2238
2298
|
if (path === `${LEGLAS_PREFIX}/api/request` && req.method === "POST") {
|
|
2239
2299
|
let body = "";
|
|
2240
2300
|
req.on("data", (chunk) => body += chunk);
|
|
@@ -2245,8 +2305,12 @@ async function startServer(options) {
|
|
|
2245
2305
|
} catch {
|
|
2246
2306
|
return sendJson(res, 400, { ok: false, error: "Body must be JSON." });
|
|
2247
2307
|
}
|
|
2248
|
-
const
|
|
2249
|
-
const
|
|
2308
|
+
const localRead = await readLocalPreviews(cwd).catch(() => null);
|
|
2309
|
+
const local = localRead?.errors.length === 0 ? localRead.previews : [];
|
|
2310
|
+
const localTitles = new Set(local.map((entry) => entry.title));
|
|
2311
|
+
const bootConfig = config?.previews ?? [];
|
|
2312
|
+
const boot = localRead === null || localRead.errors.length > 0 ? bootConfig : bootConfig.filter((entry) => entry.local !== true || localTitles.has(entry.title));
|
|
2313
|
+
const preview = [...boot, ...local].find((entry) => entry.title === parsed.title);
|
|
2250
2314
|
if (!preview || !parsed.intent?.trim()) {
|
|
2251
2315
|
return sendJson(res, 400, { ok: false, error: "Unknown preview, or empty request." });
|
|
2252
2316
|
}
|