latticesql 4.3.1 → 4.3.3
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/dist/cli.js +200 -86
- package/dist/desktop-entry.js +196 -82
- package/dist/index.cjs +154 -48
- package/dist/index.js +200 -86
- package/package.json +1 -1
package/dist/desktop-entry.js
CHANGED
|
@@ -835,7 +835,12 @@ CREATE TRIGGER "${trg}" AFTER INSERT OR UPDATE OR DELETE ON ${q3}
|
|
|
835
835
|
async function ownPolyfillsByGroup(db) {
|
|
836
836
|
if (!isPg(db)) return;
|
|
837
837
|
const group3 = await memberGroupFor(db);
|
|
838
|
-
for (const sig of [
|
|
838
|
+
for (const sig of [
|
|
839
|
+
"json_extract(text, text)",
|
|
840
|
+
"strftime(text, text)",
|
|
841
|
+
"strftime(text, text, text)",
|
|
842
|
+
"__lattice_strftime_fmt(timestamptz, text)"
|
|
843
|
+
]) {
|
|
839
844
|
try {
|
|
840
845
|
const reg = await getAsyncOrSync(db.adapter, `SELECT to_regprocedure($1) AS reg`, [sig]);
|
|
841
846
|
if (reg?.reg == null) continue;
|
|
@@ -1781,7 +1786,7 @@ async function registerPostgresPolyfills(run) {
|
|
|
1781
1786
|
await run(sql);
|
|
1782
1787
|
} catch (err) {
|
|
1783
1788
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1784
|
-
if (/permission denied/i.test(msg)) {
|
|
1789
|
+
if (/permission denied/i.test(msg) || /must be owner of/i.test(msg)) {
|
|
1785
1790
|
permissionDenied = true;
|
|
1786
1791
|
} else {
|
|
1787
1792
|
console.warn(`[PostgresAdapter] ${warn}`, msg);
|
|
@@ -2299,40 +2304,111 @@ var init_postgres = __esm({
|
|
|
2299
2304
|
SELECT doc::jsonb #>> string_to_array(regexp_replace(path, '^\\$\\.?', ''), '.')
|
|
2300
2305
|
$fn$;
|
|
2301
2306
|
END IF;
|
|
2307
|
+
END $do$;`
|
|
2308
|
+
},
|
|
2309
|
+
{
|
|
2310
|
+
warn: "could not register strftime format helper:",
|
|
2311
|
+
// Shared format translator (SQLite strftime tokens → to_char patterns), in UTC.
|
|
2312
|
+
// Factored out so the 2-arg and 3-arg strftime overloads share one definition.
|
|
2313
|
+
// Each polyfill below is CREATE OR REPLACE (so an existing cloud's prior copy is
|
|
2314
|
+
// UPGRADED when the owner opens), wrapped in a DO block whose EXCEPTION swallows a
|
|
2315
|
+
// scoped member's insufficient-privilege failure IN A SUBTRANSACTION — so a member
|
|
2316
|
+
// that runs registration inside a transaction is NOT aborted. ("must be owner of
|
|
2317
|
+
// function", raised when a non-owner CREATE OR REPLACEs another role's function, is
|
|
2318
|
+
// SQLSTATE 42501 / `insufficient_privilege`, same class as "permission denied".) The
|
|
2319
|
+
// owner already owns + replaced the function; the member simply uses the owner's
|
|
2320
|
+
// copy — and `ownPolyfillsByGroup` re-owns the whole set to the member group so any
|
|
2321
|
+
// member can replace them on a later upgrade.
|
|
2322
|
+
sql: `DO $do$ BEGIN
|
|
2323
|
+
CREATE OR REPLACE FUNCTION __lattice_strftime_fmt(ts timestamptz, format text)
|
|
2324
|
+
RETURNS text
|
|
2325
|
+
LANGUAGE sql
|
|
2326
|
+
IMMUTABLE
|
|
2327
|
+
AS $fn$
|
|
2328
|
+
SELECT to_char(
|
|
2329
|
+
ts AT TIME ZONE 'UTC',
|
|
2330
|
+
replace(replace(replace(replace(replace(replace(replace(replace(
|
|
2331
|
+
format,
|
|
2332
|
+
'%Y', 'YYYY'),
|
|
2333
|
+
'%m', 'MM'),
|
|
2334
|
+
'%d', 'DD'),
|
|
2335
|
+
'%H', 'HH24'),
|
|
2336
|
+
'%M', 'MI'),
|
|
2337
|
+
'%S', 'SS'),
|
|
2338
|
+
'%f', 'MS'),
|
|
2339
|
+
'T', '"T"')
|
|
2340
|
+
);
|
|
2341
|
+
$fn$;
|
|
2342
|
+
EXCEPTION WHEN insufficient_privilege THEN NULL;
|
|
2302
2343
|
END $do$;`
|
|
2303
2344
|
},
|
|
2304
2345
|
{
|
|
2305
2346
|
warn: "could not register strftime polyfill:",
|
|
2347
|
+
// The pre-4.3.3 strftime cast the modifier straight to timestamptz and threw
|
|
2348
|
+
// `invalid input syntax for type timestamp with time zone: ""` on a legacy ''
|
|
2349
|
+
// value (3.x stored nullable TEXT timestamps as ''), bricking the whole workspace
|
|
2350
|
+
// open. Now an empty, whitespace, or unparseable time string returns NULL (SQLite's
|
|
2351
|
+
// strftime semantics) instead of aborting the query.
|
|
2306
2352
|
sql: `DO $do$ BEGIN
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2353
|
+
CREATE OR REPLACE FUNCTION strftime(format text, modifier text)
|
|
2354
|
+
RETURNS text
|
|
2355
|
+
LANGUAGE plpgsql
|
|
2356
|
+
IMMUTABLE
|
|
2357
|
+
AS $fn$
|
|
2358
|
+
DECLARE ts timestamptz;
|
|
2359
|
+
BEGIN
|
|
2360
|
+
IF modifier = 'now' THEN
|
|
2361
|
+
ts := now();
|
|
2362
|
+
ELSIF NULLIF(btrim(modifier), '') IS NULL THEN
|
|
2363
|
+
RETURN NULL;
|
|
2364
|
+
ELSE
|
|
2365
|
+
BEGIN
|
|
2318
2366
|
ts := modifier::timestamptz;
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2367
|
+
EXCEPTION WHEN others THEN
|
|
2368
|
+
RETURN NULL;
|
|
2369
|
+
END;
|
|
2370
|
+
END IF;
|
|
2371
|
+
RETURN __lattice_strftime_fmt(ts, format);
|
|
2372
|
+
END;
|
|
2373
|
+
$fn$;
|
|
2374
|
+
EXCEPTION WHEN insufficient_privilege THEN NULL;
|
|
2375
|
+
END $do$;`
|
|
2376
|
+
},
|
|
2377
|
+
{
|
|
2378
|
+
warn: "could not register 3-arg strftime polyfill:",
|
|
2379
|
+
// SQLite's 3-arg strftime(format, timestring, modifier) — used by the changelog
|
|
2380
|
+
// retention prune (e.g. strftime('%Y-...','now','-30 days')). Postgres had no
|
|
2381
|
+
// 3-arg overload, so that prune threw `function strftime(...) does not exist` on
|
|
2382
|
+
// every PG cloud with retention. Resolve the base time, apply the modifier as an
|
|
2383
|
+
// interval, then reuse the shared formatter. Empty/invalid → NULL, never throws.
|
|
2384
|
+
sql: `DO $do$ BEGIN
|
|
2385
|
+
CREATE OR REPLACE FUNCTION strftime(format text, timestring text, modifier text)
|
|
2386
|
+
RETURNS text
|
|
2387
|
+
LANGUAGE plpgsql
|
|
2388
|
+
IMMUTABLE
|
|
2389
|
+
AS $fn$
|
|
2390
|
+
DECLARE ts timestamptz;
|
|
2391
|
+
BEGIN
|
|
2392
|
+
IF timestring = 'now' THEN
|
|
2393
|
+
ts := now();
|
|
2394
|
+
ELSIF NULLIF(btrim(timestring), '') IS NULL THEN
|
|
2395
|
+
RETURN NULL;
|
|
2396
|
+
ELSE
|
|
2397
|
+
BEGIN
|
|
2398
|
+
ts := timestring::timestamptz;
|
|
2399
|
+
EXCEPTION WHEN others THEN
|
|
2400
|
+
RETURN NULL;
|
|
2401
|
+
END;
|
|
2402
|
+
END IF;
|
|
2403
|
+
BEGIN
|
|
2404
|
+
ts := ts + modifier::interval;
|
|
2405
|
+
EXCEPTION WHEN others THEN
|
|
2406
|
+
RETURN NULL;
|
|
2333
2407
|
END;
|
|
2334
|
-
|
|
2335
|
-
|
|
2408
|
+
RETURN __lattice_strftime_fmt(ts, format);
|
|
2409
|
+
END;
|
|
2410
|
+
$fn$;
|
|
2411
|
+
EXCEPTION WHEN insufficient_privilege THEN NULL;
|
|
2336
2412
|
END $do$;`
|
|
2337
2413
|
}
|
|
2338
2414
|
];
|
|
@@ -29043,12 +29119,12 @@ var getNodeModulesParentDirs;
|
|
|
29043
29119
|
var init_getNodeModulesParentDirs = __esm({
|
|
29044
29120
|
"node_modules/@aws-sdk/core/dist-es/submodules/client/util-user-agent-node/getNodeModulesParentDirs.js"() {
|
|
29045
29121
|
"use strict";
|
|
29046
|
-
getNodeModulesParentDirs = (
|
|
29122
|
+
getNodeModulesParentDirs = (dirname18) => {
|
|
29047
29123
|
const cwd = process.cwd();
|
|
29048
|
-
if (!
|
|
29124
|
+
if (!dirname18) {
|
|
29049
29125
|
return [cwd];
|
|
29050
29126
|
}
|
|
29051
|
-
const normalizedPath = normalize(
|
|
29127
|
+
const normalizedPath = normalize(dirname18);
|
|
29052
29128
|
const parts = normalizedPath.split(sep6);
|
|
29053
29129
|
const nodeModulesIndex = parts.indexOf("node_modules");
|
|
29054
29130
|
const parentDir = nodeModulesIndex !== -1 ? parts.slice(0, nodeModulesIndex).join(sep6) : normalizedPath;
|
|
@@ -29126,8 +29202,8 @@ var init_getTypeScriptUserAgentPair = __esm({
|
|
|
29126
29202
|
tscVersion = null;
|
|
29127
29203
|
return void 0;
|
|
29128
29204
|
}
|
|
29129
|
-
const
|
|
29130
|
-
const nodeModulesParentDirs = getNodeModulesParentDirs(
|
|
29205
|
+
const dirname18 = typeof __dirname !== "undefined" ? __dirname : void 0;
|
|
29206
|
+
const nodeModulesParentDirs = getNodeModulesParentDirs(dirname18);
|
|
29131
29207
|
let versionFromApp;
|
|
29132
29208
|
for (const nodeModulesParentDir of nodeModulesParentDirs) {
|
|
29133
29209
|
try {
|
|
@@ -57916,9 +57992,9 @@ var init_dist_es22 = __esm({
|
|
|
57916
57992
|
init_http();
|
|
57917
57993
|
import { createServer } from "http";
|
|
57918
57994
|
import { spawn as spawn2 } from "child_process";
|
|
57919
|
-
import { existsSync as
|
|
57995
|
+
import { existsSync as existsSync32 } from "fs";
|
|
57920
57996
|
import { WebSocketServer, WebSocket } from "ws";
|
|
57921
|
-
import { dirname as
|
|
57997
|
+
import { dirname as dirname17, resolve as resolve15 } from "path";
|
|
57922
57998
|
|
|
57923
57999
|
// src/gui/active-db.ts
|
|
57924
58000
|
init_adapter();
|
|
@@ -76618,8 +76694,16 @@ async function dispatchIngestRoute(req, res, ctx) {
|
|
|
76618
76694
|
|
|
76619
76695
|
// src/gui/sources-routes.ts
|
|
76620
76696
|
init_user_config();
|
|
76621
|
-
import {
|
|
76622
|
-
|
|
76697
|
+
import {
|
|
76698
|
+
statSync as statSync9,
|
|
76699
|
+
readdirSync as readdirSync8,
|
|
76700
|
+
readFileSync as readFileSync23,
|
|
76701
|
+
writeFileSync as writeFileSync9,
|
|
76702
|
+
existsSync as existsSync26,
|
|
76703
|
+
mkdirSync as mkdirSync11,
|
|
76704
|
+
rmSync
|
|
76705
|
+
} from "fs";
|
|
76706
|
+
import { resolve as resolve11, join as join28, basename as basename12, sep as sep8, dirname as dirname15 } from "path";
|
|
76623
76707
|
import { execFile } from "child_process";
|
|
76624
76708
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
76625
76709
|
init_http();
|
|
@@ -76627,20 +76711,49 @@ var MAX_LIST_ENTRIES = 2e3;
|
|
|
76627
76711
|
var MAX_INGEST_FILES = 500;
|
|
76628
76712
|
var MAX_INGEST_DEPTH = 8;
|
|
76629
76713
|
var SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", ".DS_Store", "__pycache__", ".venv", "venv"]);
|
|
76630
|
-
function rootsFile() {
|
|
76631
|
-
return join28(
|
|
76714
|
+
function rootsFile(configPath) {
|
|
76715
|
+
return join28(dirname15(configPath), "sources.json");
|
|
76716
|
+
}
|
|
76717
|
+
function migrateGlobalRootsIfNeeded(configPath) {
|
|
76718
|
+
const wsFile = rootsFile(configPath);
|
|
76719
|
+
if (existsSync26(wsFile)) return;
|
|
76720
|
+
const globalFile = join28(configDir(), "sources.json");
|
|
76721
|
+
if (globalFile === wsFile || !existsSync26(globalFile)) return;
|
|
76722
|
+
let roots;
|
|
76723
|
+
try {
|
|
76724
|
+
const parsed = JSON.parse(readFileSync23(globalFile, "utf8"));
|
|
76725
|
+
if (!Array.isArray(parsed.roots) || parsed.roots.length === 0) return;
|
|
76726
|
+
roots = parsed.roots;
|
|
76727
|
+
} catch {
|
|
76728
|
+
return;
|
|
76729
|
+
}
|
|
76730
|
+
try {
|
|
76731
|
+
mkdirSync11(dirname15(wsFile), { recursive: true });
|
|
76732
|
+
writeFileSync9(wsFile, JSON.stringify({ roots }, null, 2), "utf8");
|
|
76733
|
+
} catch {
|
|
76734
|
+
return;
|
|
76735
|
+
}
|
|
76736
|
+
try {
|
|
76737
|
+
rmSync(globalFile, { force: true });
|
|
76738
|
+
} catch {
|
|
76739
|
+
try {
|
|
76740
|
+
writeFileSync9(globalFile, JSON.stringify({ roots: [] }, null, 2), "utf8");
|
|
76741
|
+
} catch {
|
|
76742
|
+
}
|
|
76743
|
+
}
|
|
76632
76744
|
}
|
|
76633
|
-
function readRoots() {
|
|
76745
|
+
function readRoots(configPath) {
|
|
76746
|
+
migrateGlobalRootsIfNeeded(configPath);
|
|
76634
76747
|
try {
|
|
76635
|
-
const raw = readFileSync23(rootsFile(), "utf8");
|
|
76748
|
+
const raw = readFileSync23(rootsFile(configPath), "utf8");
|
|
76636
76749
|
const parsed = JSON.parse(raw);
|
|
76637
76750
|
return Array.isArray(parsed.roots) ? parsed.roots : [];
|
|
76638
76751
|
} catch {
|
|
76639
76752
|
return [];
|
|
76640
76753
|
}
|
|
76641
76754
|
}
|
|
76642
|
-
function writeRoots(roots) {
|
|
76643
|
-
writeFileSync9(rootsFile(), JSON.stringify({ roots }, null, 2), "utf8");
|
|
76755
|
+
function writeRoots(configPath, roots) {
|
|
76756
|
+
writeFileSync9(rootsFile(configPath), JSON.stringify({ roots }, null, 2), "utf8");
|
|
76644
76757
|
}
|
|
76645
76758
|
function safeResolveInside2(target, roots) {
|
|
76646
76759
|
const abs = resolve11(target);
|
|
@@ -76730,14 +76843,14 @@ async function ingestFolder(abs, ingestFile) {
|
|
|
76730
76843
|
return { ingested, skipped };
|
|
76731
76844
|
}
|
|
76732
76845
|
async function dispatchSourcesRoute(req, res, deps) {
|
|
76733
|
-
const { pathname, method, ingestFile } = deps;
|
|
76846
|
+
const { pathname, method, ingestFile, configPath } = deps;
|
|
76734
76847
|
if (!pathname.startsWith("/api/sources/")) return false;
|
|
76735
76848
|
if (!localFileOpenEnabled()) {
|
|
76736
76849
|
sendJson(res, { enabled: false });
|
|
76737
76850
|
return true;
|
|
76738
76851
|
}
|
|
76739
76852
|
if (pathname === "/api/sources/roots" && method === "GET") {
|
|
76740
|
-
sendJson(res, { enabled: true, roots: readRoots() });
|
|
76853
|
+
sendJson(res, { enabled: true, roots: readRoots(configPath) });
|
|
76741
76854
|
return true;
|
|
76742
76855
|
}
|
|
76743
76856
|
if (pathname === "/api/sources/roots" && method === "POST") {
|
|
@@ -76763,12 +76876,12 @@ async function dispatchSourcesRoute(req, res, deps) {
|
|
|
76763
76876
|
sendJson(res, { error: `path not found: ${abs}` }, 400);
|
|
76764
76877
|
return true;
|
|
76765
76878
|
}
|
|
76766
|
-
const roots = readRoots();
|
|
76879
|
+
const roots = readRoots(configPath);
|
|
76767
76880
|
let root6 = roots.find((r6) => resolve11(r6.path) === abs);
|
|
76768
76881
|
if (!root6) {
|
|
76769
76882
|
root6 = { id: randomUUID4(), path: abs, kind, name: basename12(abs) || abs };
|
|
76770
76883
|
roots.push(root6);
|
|
76771
|
-
writeRoots(roots);
|
|
76884
|
+
writeRoots(configPath, roots);
|
|
76772
76885
|
}
|
|
76773
76886
|
let result;
|
|
76774
76887
|
if (kind === "folder") result = await ingestFolder(abs, ingestFile);
|
|
@@ -76779,8 +76892,8 @@ async function dispatchSourcesRoute(req, res, deps) {
|
|
|
76779
76892
|
const delMatch = /^\/api\/sources\/roots\/([^/]+)$/.exec(pathname);
|
|
76780
76893
|
if (delMatch && method === "DELETE") {
|
|
76781
76894
|
const id = decodeURIComponent(delMatch[1] ?? "");
|
|
76782
|
-
const roots = readRoots().filter((r6) => r6.id !== id);
|
|
76783
|
-
writeRoots(roots);
|
|
76895
|
+
const roots = readRoots(configPath).filter((r6) => r6.id !== id);
|
|
76896
|
+
writeRoots(configPath, roots);
|
|
76784
76897
|
sendJson(res, { ok: true });
|
|
76785
76898
|
return true;
|
|
76786
76899
|
}
|
|
@@ -76798,7 +76911,7 @@ async function dispatchSourcesRoute(req, res, deps) {
|
|
|
76798
76911
|
sendJson(res, { error: "path is required" }, 400);
|
|
76799
76912
|
return true;
|
|
76800
76913
|
}
|
|
76801
|
-
const abs = safeResolveInside2(target, readRoots());
|
|
76914
|
+
const abs = safeResolveInside2(target, readRoots(configPath));
|
|
76802
76915
|
if (!abs) {
|
|
76803
76916
|
sendJson(res, { error: "path is outside any registered source root" }, 403);
|
|
76804
76917
|
return true;
|
|
@@ -76813,7 +76926,7 @@ async function dispatchSourcesRoute(req, res, deps) {
|
|
|
76813
76926
|
if (pathname === "/api/sources/ingest-folder" && method === "POST") {
|
|
76814
76927
|
const body = await readJson(req).catch(() => ({}));
|
|
76815
76928
|
const target = typeof body.path === "string" ? body.path : "";
|
|
76816
|
-
const abs = safeResolveInside2(target, readRoots());
|
|
76929
|
+
const abs = safeResolveInside2(target, readRoots(configPath));
|
|
76817
76930
|
if (!abs) {
|
|
76818
76931
|
sendJson(res, { error: "path is outside any registered source root" }, 403);
|
|
76819
76932
|
return true;
|
|
@@ -76827,7 +76940,7 @@ async function dispatchSourcesRoute(req, res, deps) {
|
|
|
76827
76940
|
// src/gui/import-routes.ts
|
|
76828
76941
|
init_adapter();
|
|
76829
76942
|
init_http();
|
|
76830
|
-
import { existsSync as
|
|
76943
|
+
import { existsSync as existsSync27, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
|
|
76831
76944
|
import { isAbsolute as isAbsolute4, join as join29 } from "path";
|
|
76832
76945
|
init_native_entities();
|
|
76833
76946
|
function badRequest(message) {
|
|
@@ -76861,7 +76974,7 @@ async function readImportSourceFromFile(db, fileId, latticeRoot) {
|
|
|
76861
76974
|
);
|
|
76862
76975
|
if (!row) throw badRequest("Unknown import file: " + fileId);
|
|
76863
76976
|
const path3 = localPathOf2(row, latticeRoot);
|
|
76864
|
-
if (!path3 || !
|
|
76977
|
+
if (!path3 || !existsSync27(path3)) {
|
|
76865
76978
|
throw badRequest("The import file\u2019s bytes are not available locally.");
|
|
76866
76979
|
}
|
|
76867
76980
|
const sizeBytes = statSync10(path3).size;
|
|
@@ -79002,7 +79115,7 @@ init_dispatch();
|
|
|
79002
79115
|
init_column_descriptions();
|
|
79003
79116
|
init_mutations();
|
|
79004
79117
|
init_native_entities();
|
|
79005
|
-
import { createReadStream as createReadStream3, existsSync as
|
|
79118
|
+
import { createReadStream as createReadStream3, existsSync as existsSync28, realpathSync as realpathSync2, statSync as statSync11 } from "fs";
|
|
79006
79119
|
import { extname as extname3, join as join30, normalize as normalize2, sep as sep9 } from "path";
|
|
79007
79120
|
|
|
79008
79121
|
// src/gui/count-many.ts
|
|
@@ -79210,7 +79323,7 @@ async function handleReadRoutes(req, res, ctx, deps) {
|
|
|
79210
79323
|
const base = deps.guiAssetsDir.replace(/[/\\]+$/, "");
|
|
79211
79324
|
const target = normalize2(join30(base, rel));
|
|
79212
79325
|
const within = target === base || target.startsWith(base + sep9);
|
|
79213
|
-
if (!within || !
|
|
79326
|
+
if (!within || !existsSync28(target) || !statSync11(target).isFile()) {
|
|
79214
79327
|
sendJson(res, { error: "asset not found" }, 404);
|
|
79215
79328
|
return true;
|
|
79216
79329
|
}
|
|
@@ -80418,16 +80531,16 @@ async function handleHistoryRoutes(req, res, ctx, deps) {
|
|
|
80418
80531
|
// src/gui/workspaces-routes.ts
|
|
80419
80532
|
init_http();
|
|
80420
80533
|
import { resolve as resolve12 } from "path";
|
|
80421
|
-
import { existsSync as
|
|
80534
|
+
import { existsSync as existsSync29, rmSync as rmSync2 } from "fs";
|
|
80422
80535
|
init_workspace();
|
|
80423
80536
|
init_lattice_root();
|
|
80424
80537
|
init_user_config();
|
|
80425
80538
|
function cleanupWorkspaceFiles(root6, ws) {
|
|
80426
80539
|
if (!ws.configPath && ws.kind === "local") {
|
|
80427
|
-
|
|
80540
|
+
rmSync2(workspaceDir(root6, ws.dir), { recursive: true, force: true });
|
|
80428
80541
|
} else if (ws.kind === "cloud") {
|
|
80429
|
-
if (ws.configPath &&
|
|
80430
|
-
|
|
80542
|
+
if (ws.configPath && existsSync29(ws.configPath)) {
|
|
80543
|
+
rmSync2(ws.configPath, { force: true });
|
|
80431
80544
|
}
|
|
80432
80545
|
const labelMatch = /^\$\{LATTICE_DB:([A-Za-z0-9._-]+)\}$/.exec(ws.db.trim());
|
|
80433
80546
|
const label = labelMatch?.[1];
|
|
@@ -80630,15 +80743,15 @@ async function handleWorkspacesRoutes(req, res, ctx, deps) {
|
|
|
80630
80743
|
// src/gui/databases-routes.ts
|
|
80631
80744
|
init_http();
|
|
80632
80745
|
import { basename as basename14, resolve as resolve14 } from "path";
|
|
80633
|
-
import { existsSync as
|
|
80746
|
+
import { existsSync as existsSync31 } from "fs";
|
|
80634
80747
|
init_parser();
|
|
80635
80748
|
|
|
80636
80749
|
// src/gui/config-paths.ts
|
|
80637
80750
|
init_parser();
|
|
80638
|
-
import { basename as basename13, dirname as
|
|
80751
|
+
import { basename as basename13, dirname as dirname16, join as join31, resolve as resolve13 } from "path";
|
|
80639
80752
|
import {
|
|
80640
|
-
existsSync as
|
|
80641
|
-
mkdirSync as
|
|
80753
|
+
existsSync as existsSync30,
|
|
80754
|
+
mkdirSync as mkdirSync12,
|
|
80642
80755
|
readFileSync as readFileSync25,
|
|
80643
80756
|
readdirSync as readdirSync9,
|
|
80644
80757
|
unlinkSync as unlinkSync5,
|
|
@@ -80646,10 +80759,10 @@ import {
|
|
|
80646
80759
|
} from "fs";
|
|
80647
80760
|
import { parseDocument as parseDocument7 } from "yaml";
|
|
80648
80761
|
function resolveOutputDirForConfig(configPath) {
|
|
80649
|
-
const base =
|
|
80762
|
+
const base = dirname16(resolve13(configPath));
|
|
80650
80763
|
for (const dir of ["context", ".", "generated"]) {
|
|
80651
80764
|
const abs = resolve13(base, dir);
|
|
80652
|
-
if (
|
|
80765
|
+
if (existsSync30(join31(abs, ".lattice", "manifest.json"))) return abs;
|
|
80653
80766
|
}
|
|
80654
80767
|
return resolve13(base, "context");
|
|
80655
80768
|
}
|
|
@@ -80658,7 +80771,7 @@ function friendlyConfigName(parsedName, configPath) {
|
|
|
80658
80771
|
return basename13(configPath).replace(/\.(ya?ml)$/, "");
|
|
80659
80772
|
}
|
|
80660
80773
|
function listConfigs(activeConfigPath) {
|
|
80661
|
-
const dir =
|
|
80774
|
+
const dir = dirname16(activeConfigPath);
|
|
80662
80775
|
const entries = [];
|
|
80663
80776
|
for (const fname of readdirSync9(dir)) {
|
|
80664
80777
|
if (!fname.endsWith(".yml") && !fname.endsWith(".yaml")) continue;
|
|
@@ -80687,17 +80800,17 @@ function listConfigs(activeConfigPath) {
|
|
|
80687
80800
|
return entries.sort((a6, b6) => a6.label.localeCompare(b6.label));
|
|
80688
80801
|
}
|
|
80689
80802
|
function createBlankConfig(activeConfigPath, dbName) {
|
|
80690
|
-
const dir =
|
|
80803
|
+
const dir = dirname16(activeConfigPath);
|
|
80691
80804
|
const slug = dbName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
80692
80805
|
if (!slug) throw new Error("Workspace name must contain at least one alphanumeric character");
|
|
80693
80806
|
const configPath = join31(dir, `${slug}.config.yml`);
|
|
80694
|
-
if (
|
|
80807
|
+
if (existsSync30(configPath)) throw new Error(`Config already exists: ${slug}.config.yml`);
|
|
80695
80808
|
const yaml = `db: ./data/${slug}.db
|
|
80696
80809
|
|
|
80697
80810
|
entities: {}
|
|
80698
80811
|
`;
|
|
80699
80812
|
writeFileSync10(configPath, yaml, "utf8");
|
|
80700
|
-
|
|
80813
|
+
mkdirSync12(join31(dir, "data"), { recursive: true });
|
|
80701
80814
|
return configPath;
|
|
80702
80815
|
}
|
|
80703
80816
|
function sqliteFileForConfig(configPath) {
|
|
@@ -80706,18 +80819,18 @@ function sqliteFileForConfig(configPath) {
|
|
|
80706
80819
|
if (!raw) return null;
|
|
80707
80820
|
if (isPostgresUrl(raw) || raw.startsWith("${LATTICE_DB:")) return null;
|
|
80708
80821
|
if (raw === ":memory:" || raw.startsWith("file:")) return null;
|
|
80709
|
-
return resolve13(
|
|
80822
|
+
return resolve13(dirname16(configPath), raw);
|
|
80710
80823
|
}
|
|
80711
80824
|
function deleteDatabaseFiles(targetConfigPath) {
|
|
80712
80825
|
const sqliteFile = sqliteFileForConfig(targetConfigPath);
|
|
80713
80826
|
unlinkSync5(targetConfigPath);
|
|
80714
80827
|
let deletedDbFile = null;
|
|
80715
|
-
if (sqliteFile &&
|
|
80828
|
+
if (sqliteFile && existsSync30(sqliteFile)) {
|
|
80716
80829
|
unlinkSync5(sqliteFile);
|
|
80717
80830
|
deletedDbFile = sqliteFile;
|
|
80718
80831
|
for (const suffix of ["-wal", "-shm", "-journal"]) {
|
|
80719
80832
|
const sidecar = sqliteFile + suffix;
|
|
80720
|
-
if (
|
|
80833
|
+
if (existsSync30(sidecar)) unlinkSync5(sidecar);
|
|
80721
80834
|
}
|
|
80722
80835
|
}
|
|
80723
80836
|
return { deletedConfig: basename13(targetConfigPath), deletedDbFile };
|
|
@@ -80751,7 +80864,7 @@ async function handleDatabasesRoutes(req, res, ctx, deps) {
|
|
|
80751
80864
|
return true;
|
|
80752
80865
|
}
|
|
80753
80866
|
const newPath = resolve14(body.path);
|
|
80754
|
-
if (!
|
|
80867
|
+
if (!existsSync31(newPath)) {
|
|
80755
80868
|
sendJson(res, { error: `Config not found: ${newPath}` }, 400);
|
|
80756
80869
|
return true;
|
|
80757
80870
|
}
|
|
@@ -80857,8 +80970,8 @@ async function handleDatabasesRoutes(req, res, ctx, deps) {
|
|
|
80857
80970
|
// src/gui/server.ts
|
|
80858
80971
|
init_user_config();
|
|
80859
80972
|
function resolveDefaultGuiAssetsDir() {
|
|
80860
|
-
const bundleSibling = process.argv[1] ? resolve15(
|
|
80861
|
-
if (bundleSibling &&
|
|
80973
|
+
const bundleSibling = process.argv[1] ? resolve15(dirname17(process.argv[1]), "gui-assets") : null;
|
|
80974
|
+
if (bundleSibling && existsSync32(bundleSibling)) return bundleSibling;
|
|
80862
80975
|
return resolve15(process.cwd(), "dist", "gui-assets");
|
|
80863
80976
|
}
|
|
80864
80977
|
function sendText(res, body, status = 200, contentType = "text/plain; charset=utf-8") {
|
|
@@ -80915,7 +81028,7 @@ async function startGuiServer(options) {
|
|
|
80915
81028
|
const sessionId = crypto.randomUUID();
|
|
80916
81029
|
let updateService = null;
|
|
80917
81030
|
let activeRef = bootConfigPath && bootOutputDir ? await openConfig(bootConfigPath, bootOutputDir, autoRender, options.realtimeWatchdogMs) : null;
|
|
80918
|
-
const latticeRoot = (bootConfigPath ? findLatticeRoot(
|
|
81031
|
+
const latticeRoot = (bootConfigPath ? findLatticeRoot(dirname17(bootConfigPath)) : null) ?? (options.latticeRoot ? resolve15(options.latticeRoot) : null);
|
|
80919
81032
|
let currentWorkspaceId = null;
|
|
80920
81033
|
if (latticeRoot && bootConfigPath) {
|
|
80921
81034
|
const launched = listWorkspaces(latticeRoot).find(
|
|
@@ -81269,7 +81382,7 @@ async function startGuiServer(options) {
|
|
|
81269
81382
|
createJunction: (otherTable) => createFileJunction(active, otherTable, sessionId),
|
|
81270
81383
|
createEntity: (entity, columns) => createUserEntity(active, entity, columns, sessionId),
|
|
81271
81384
|
aggressiveness: getAggressiveness(),
|
|
81272
|
-
latticeRoot:
|
|
81385
|
+
latticeRoot: dirname17(active.configPath),
|
|
81273
81386
|
configPath: active.configPath,
|
|
81274
81387
|
outputDir: active.outputDir,
|
|
81275
81388
|
sessionId,
|
|
@@ -81294,7 +81407,7 @@ async function startGuiServer(options) {
|
|
|
81294
81407
|
createJunction: (otherTable) => createFileJunction(active, otherTable, sessionId),
|
|
81295
81408
|
createEntity: (entity, columns) => createUserEntity(active, entity, columns, sessionId),
|
|
81296
81409
|
aggressiveness: getAggressiveness(),
|
|
81297
|
-
latticeRoot:
|
|
81410
|
+
latticeRoot: dirname17(active.configPath),
|
|
81298
81411
|
configPath: active.configPath,
|
|
81299
81412
|
outputDir: active.outputDir,
|
|
81300
81413
|
sessionId,
|
|
@@ -81305,6 +81418,7 @@ async function startGuiServer(options) {
|
|
|
81305
81418
|
return await dispatchSourcesRoute(req2, res2, {
|
|
81306
81419
|
db: active.db,
|
|
81307
81420
|
ingestFile: (p3) => ingestLocalFile(ingestCtx, mctx, p3, false),
|
|
81421
|
+
configPath: active.configPath,
|
|
81308
81422
|
pathname,
|
|
81309
81423
|
method
|
|
81310
81424
|
});
|
|
@@ -81320,7 +81434,7 @@ async function startGuiServer(options) {
|
|
|
81320
81434
|
return await dispatchImportRoute(req2, res2, {
|
|
81321
81435
|
db: active.db,
|
|
81322
81436
|
configPath: active.configPath,
|
|
81323
|
-
latticeRoot:
|
|
81437
|
+
latticeRoot: dirname17(active.configPath),
|
|
81324
81438
|
validTables: active.validTables,
|
|
81325
81439
|
softDeletable: active.softDeletable
|
|
81326
81440
|
});
|
|
@@ -81349,7 +81463,7 @@ async function startGuiServer(options) {
|
|
|
81349
81463
|
if (!pathname.startsWith("/api/files/")) return false;
|
|
81350
81464
|
return await dispatchFilesRoute(req2, res2, {
|
|
81351
81465
|
db: active.db,
|
|
81352
|
-
latticeRoot:
|
|
81466
|
+
latticeRoot: dirname17(active.configPath),
|
|
81353
81467
|
configPath: active.configPath,
|
|
81354
81468
|
pathname,
|
|
81355
81469
|
method
|
|
@@ -81560,7 +81674,7 @@ ${e6.stack ?? ""}`
|
|
|
81560
81674
|
}
|
|
81561
81675
|
|
|
81562
81676
|
// src/desktop-entry.ts
|
|
81563
|
-
var VERSION2 = true ? "4.3.
|
|
81677
|
+
var VERSION2 = true ? "4.3.3" : "unknown";
|
|
81564
81678
|
export {
|
|
81565
81679
|
VERSION2 as VERSION,
|
|
81566
81680
|
ensureRootForGui,
|