sqlite-hub 0.3.2 → 0.4.0
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 -5
- package/changelog.md +7 -0
- package/{js → frontend/js}/app.js +75 -3
- package/{js → frontend/js}/components/connectionCard.js +8 -9
- package/frontend/js/components/connectionLogo.js +33 -0
- package/{js → frontend/js}/components/emptyState.js +25 -11
- package/{js → frontend/js}/components/modal.js +57 -0
- package/{js → frontend/js}/components/sidebar.js +8 -3
- package/{js → frontend/js}/store.js +32 -0
- package/{js → frontend/js}/views/data.js +102 -9
- package/{js → frontend/js}/views/structure.js +10 -12
- package/{styles → frontend/styles}/structure-graph.css +5 -10
- package/package.json +2 -2
- package/{publish_brew.sh → scripts/publish_brew.sh} +2 -2
- package/{publish_npm.sh → scripts/publish_npm.sh} +2 -2
- package/server/data/db_logos/.gitkeep +0 -0
- package/server/routes/connections.js +2 -0
- package/server/server.js +7 -5
- package/server/services/sqlite/connectionManager.js +68 -33
- package/server/services/storage/appStateStore.js +159 -20
- package/server/utils/appPaths.js +42 -18
- /package/{assets → frontend/assets}/images/logo.webp +0 -0
- /package/{assets → frontend/assets}/images/logo_extrasmall.webp +0 -0
- /package/{assets → frontend/assets}/images/logo_raw.png +0 -0
- /package/{assets → frontend/assets}/images/logo_small.webp +0 -0
- /package/{assets → frontend/assets}/mockups/connections.png +0 -0
- /package/{assets → frontend/assets}/mockups/data.png +0 -0
- /package/{assets → frontend/assets}/mockups/data_edit.png +0 -0
- /package/{assets → frontend/assets}/mockups/graph_visualize.png +0 -0
- /package/{assets → frontend/assets}/mockups/home.png +0 -0
- /package/{assets → frontend/assets}/mockups/overview.png +0 -0
- /package/{assets → frontend/assets}/mockups/sql_editor.png +0 -0
- /package/{assets → frontend/assets}/mockups/structure.png +0 -0
- /package/{index.html → frontend/index.html} +0 -0
- /package/{js → frontend/js}/api.js +0 -0
- /package/{js → frontend/js}/components/actionBar.js +0 -0
- /package/{js → frontend/js}/components/appShell.js +0 -0
- /package/{js → frontend/js}/components/badges.js +0 -0
- /package/{js → frontend/js}/components/bottomTabs.js +0 -0
- /package/{js → frontend/js}/components/dataGrid.js +0 -0
- /package/{js → frontend/js}/components/metricCard.js +0 -0
- /package/{js → frontend/js}/components/pageHeader.js +0 -0
- /package/{js → frontend/js}/components/queryEditor.js +0 -0
- /package/{js → frontend/js}/components/queryResults.js +0 -0
- /package/{js → frontend/js}/components/rowEditorPanel.js +0 -0
- /package/{js → frontend/js}/components/statusBar.js +0 -0
- /package/{js → frontend/js}/components/structureGraph.js +0 -0
- /package/{js → frontend/js}/components/toast.js +0 -0
- /package/{js → frontend/js}/components/topNav.js +0 -0
- /package/{js → frontend/js}/lib/cytoscapeRuntime.js +0 -0
- /package/{js → frontend/js}/router.js +0 -0
- /package/{js → frontend/js}/utils/format.js +0 -0
- /package/{js → frontend/js}/views/connections.js +0 -0
- /package/{js → frontend/js}/views/editor.js +0 -0
- /package/{js → frontend/js}/views/landing.js +0 -0
- /package/{js → frontend/js}/views/overview.js +0 -0
- /package/{js → frontend/js}/views/settings.js +0 -0
- /package/{styles → frontend/styles}/base.css +0 -0
- /package/{styles → frontend/styles}/components.css +0 -0
- /package/{styles → frontend/styles}/layout.css +0 -0
- /package/{styles → frontend/styles}/tokens.css +0 -0
- /package/{styles → frontend/styles}/views.css +0 -0
- /package/{data → server/data}/.gitkeep +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
2
|
const path = require("node:path");
|
|
3
3
|
const Database = require("better-sqlite3");
|
|
4
|
+
const { ValidationError } = require("../../utils/errors");
|
|
4
5
|
|
|
5
6
|
const DEFAULT_STATE = {
|
|
6
7
|
recentConnections: [],
|
|
@@ -16,9 +17,24 @@ const DEFAULT_STATE = {
|
|
|
16
17
|
},
|
|
17
18
|
};
|
|
18
19
|
|
|
20
|
+
const CONNECTION_LOGO_DIRECTORY = "db_logos";
|
|
21
|
+
const MAX_CONNECTION_LOGO_SIZE_BYTES = 5 * 1024 * 1024;
|
|
22
|
+
const CONNECTION_LOGO_EXTENSION_BY_MIME_TYPE = {
|
|
23
|
+
"image/jpeg": "jpg",
|
|
24
|
+
"image/png": "png",
|
|
25
|
+
"image/webp": "webp",
|
|
26
|
+
};
|
|
27
|
+
const CONNECTION_LOGO_EXTENSION_BY_FILE_EXTENSION = {
|
|
28
|
+
".jpeg": "jpg",
|
|
29
|
+
".jpg": "jpg",
|
|
30
|
+
".png": "png",
|
|
31
|
+
".webp": "webp",
|
|
32
|
+
};
|
|
33
|
+
|
|
19
34
|
class AppStateStore {
|
|
20
35
|
constructor(filePath, options = {}) {
|
|
21
36
|
this.filePath = filePath;
|
|
37
|
+
this.logoDirectory = path.join(path.dirname(this.filePath), CONNECTION_LOGO_DIRECTORY);
|
|
22
38
|
this.legacyFilePath = options.legacyFilePath ?? null;
|
|
23
39
|
this.legacyDatabasePaths = Array.isArray(options.legacyDatabasePaths)
|
|
24
40
|
? options.legacyDatabasePaths
|
|
@@ -26,6 +42,7 @@ class AppStateStore {
|
|
|
26
42
|
this.isFreshDatabase = !fs.existsSync(filePath);
|
|
27
43
|
|
|
28
44
|
fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
|
|
45
|
+
fs.mkdirSync(this.logoDirectory, { recursive: true });
|
|
29
46
|
|
|
30
47
|
this.db = new Database(this.filePath);
|
|
31
48
|
this.configureDatabase();
|
|
@@ -64,7 +81,8 @@ class AppStateStore {
|
|
|
64
81
|
lastOpenedAt TEXT NOT NULL,
|
|
65
82
|
lastModifiedAt TEXT,
|
|
66
83
|
sizeBytes INTEGER,
|
|
67
|
-
readOnly INTEGER NOT NULL DEFAULT 0
|
|
84
|
+
readOnly INTEGER NOT NULL DEFAULT 0,
|
|
85
|
+
logoPath TEXT
|
|
68
86
|
);
|
|
69
87
|
|
|
70
88
|
CREATE TABLE IF NOT EXISTS sql_history (
|
|
@@ -86,6 +104,17 @@ class AppStateStore {
|
|
|
86
104
|
CREATE INDEX IF NOT EXISTS idx_sql_history_executed_at
|
|
87
105
|
ON sql_history(executedAt DESC, id ASC);
|
|
88
106
|
`);
|
|
107
|
+
|
|
108
|
+
const recentConnectionColumns = new Set(
|
|
109
|
+
this.db
|
|
110
|
+
.prepare("PRAGMA table_info(recent_connections)")
|
|
111
|
+
.all()
|
|
112
|
+
.map((column) => column.name)
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (!recentConnectionColumns.has("logoPath")) {
|
|
116
|
+
this.db.exec("ALTER TABLE recent_connections ADD COLUMN logoPath TEXT");
|
|
117
|
+
}
|
|
89
118
|
}
|
|
90
119
|
|
|
91
120
|
seedDefaultSettings() {
|
|
@@ -153,6 +182,14 @@ class AppStateStore {
|
|
|
153
182
|
.all()
|
|
154
183
|
.map((row) => row.name)
|
|
155
184
|
);
|
|
185
|
+
const recentConnectionColumns = tables.has("recent_connections")
|
|
186
|
+
? new Set(
|
|
187
|
+
legacyDb
|
|
188
|
+
.prepare("PRAGMA table_info(recent_connections)")
|
|
189
|
+
.all()
|
|
190
|
+
.map((column) => column.name)
|
|
191
|
+
)
|
|
192
|
+
: new Set();
|
|
156
193
|
|
|
157
194
|
return {
|
|
158
195
|
settings: tables.has("settings")
|
|
@@ -173,7 +210,8 @@ class AppStateStore {
|
|
|
173
210
|
lastOpenedAt,
|
|
174
211
|
lastModifiedAt,
|
|
175
212
|
sizeBytes,
|
|
176
|
-
readOnly
|
|
213
|
+
readOnly,
|
|
214
|
+
${recentConnectionColumns.has("logoPath") ? "logoPath" : "NULL AS logoPath"}
|
|
177
215
|
FROM recent_connections
|
|
178
216
|
ORDER BY lastOpenedAt DESC, id ASC
|
|
179
217
|
`)
|
|
@@ -223,16 +261,18 @@ class AppStateStore {
|
|
|
223
261
|
lastOpenedAt,
|
|
224
262
|
lastModifiedAt,
|
|
225
263
|
sizeBytes,
|
|
226
|
-
readOnly
|
|
264
|
+
readOnly,
|
|
265
|
+
logoPath
|
|
227
266
|
)
|
|
228
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
267
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
229
268
|
ON CONFLICT(id) DO UPDATE SET
|
|
230
269
|
label = excluded.label,
|
|
231
270
|
path = excluded.path,
|
|
232
271
|
lastOpenedAt = excluded.lastOpenedAt,
|
|
233
272
|
lastModifiedAt = excluded.lastModifiedAt,
|
|
234
273
|
sizeBytes = excluded.sizeBytes,
|
|
235
|
-
readOnly = excluded.readOnly
|
|
274
|
+
readOnly = excluded.readOnly,
|
|
275
|
+
logoPath = excluded.logoPath
|
|
236
276
|
`);
|
|
237
277
|
const insertHistory = this.db.prepare(`
|
|
238
278
|
INSERT INTO sql_history (
|
|
@@ -276,7 +316,8 @@ class AppStateStore {
|
|
|
276
316
|
connection.lastOpenedAt ?? new Date().toISOString(),
|
|
277
317
|
connection.lastModifiedAt ?? null,
|
|
278
318
|
connection.sizeBytes ?? null,
|
|
279
|
-
connection.readOnly ? 1 : 0
|
|
319
|
+
connection.readOnly ? 1 : 0,
|
|
320
|
+
this.normalizeLogoPath(connection.logoPath)
|
|
280
321
|
);
|
|
281
322
|
}
|
|
282
323
|
|
|
@@ -373,7 +414,7 @@ class AppStateStore {
|
|
|
373
414
|
|
|
374
415
|
const staleRows = this.db
|
|
375
416
|
.prepare(`
|
|
376
|
-
SELECT id
|
|
417
|
+
SELECT id, logoPath
|
|
377
418
|
FROM recent_connections
|
|
378
419
|
ORDER BY lastOpenedAt DESC, id ASC
|
|
379
420
|
LIMIT -1 OFFSET ?
|
|
@@ -393,6 +434,10 @@ class AppStateStore {
|
|
|
393
434
|
if (activeConnectionId && staleRows.some((row) => row.id === activeConnectionId)) {
|
|
394
435
|
this.setMetaValue("activeConnectionId", null);
|
|
395
436
|
}
|
|
437
|
+
|
|
438
|
+
staleRows.forEach((row) => {
|
|
439
|
+
this.deleteConnectionLogo(row.logoPath);
|
|
440
|
+
});
|
|
396
441
|
}
|
|
397
442
|
|
|
398
443
|
trimSqlHistory() {
|
|
@@ -433,19 +478,19 @@ class AppStateStore {
|
|
|
433
478
|
lastOpenedAt,
|
|
434
479
|
lastModifiedAt,
|
|
435
480
|
sizeBytes,
|
|
436
|
-
readOnly
|
|
481
|
+
readOnly,
|
|
482
|
+
logoPath
|
|
437
483
|
FROM recent_connections
|
|
438
484
|
ORDER BY lastOpenedAt DESC, id ASC
|
|
439
485
|
`)
|
|
440
486
|
.all()
|
|
441
|
-
.map((connection) => (
|
|
442
|
-
...connection,
|
|
443
|
-
readOnly: Boolean(connection.readOnly),
|
|
444
|
-
}));
|
|
487
|
+
.map((connection) => this.decorateConnection(connection));
|
|
445
488
|
}
|
|
446
489
|
|
|
447
490
|
upsertRecentConnection(connection, options = {}) {
|
|
448
491
|
const makeActive = options.makeActive !== false;
|
|
492
|
+
const existing = this.getRecentConnections().find((entry) => entry.id === connection.id);
|
|
493
|
+
const nextLogoPath = this.normalizeLogoPath(connection.logoPath);
|
|
449
494
|
|
|
450
495
|
this.db.transaction(() => {
|
|
451
496
|
this.db
|
|
@@ -457,16 +502,18 @@ class AppStateStore {
|
|
|
457
502
|
lastOpenedAt,
|
|
458
503
|
lastModifiedAt,
|
|
459
504
|
sizeBytes,
|
|
460
|
-
readOnly
|
|
505
|
+
readOnly,
|
|
506
|
+
logoPath
|
|
461
507
|
)
|
|
462
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
508
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
463
509
|
ON CONFLICT(id) DO UPDATE SET
|
|
464
510
|
label = excluded.label,
|
|
465
511
|
path = excluded.path,
|
|
466
512
|
lastOpenedAt = excluded.lastOpenedAt,
|
|
467
513
|
lastModifiedAt = excluded.lastModifiedAt,
|
|
468
514
|
sizeBytes = excluded.sizeBytes,
|
|
469
|
-
readOnly = excluded.readOnly
|
|
515
|
+
readOnly = excluded.readOnly,
|
|
516
|
+
logoPath = excluded.logoPath
|
|
470
517
|
`)
|
|
471
518
|
.run(
|
|
472
519
|
connection.id,
|
|
@@ -475,7 +522,8 @@ class AppStateStore {
|
|
|
475
522
|
connection.lastOpenedAt,
|
|
476
523
|
connection.lastModifiedAt ?? null,
|
|
477
524
|
connection.sizeBytes ?? null,
|
|
478
|
-
connection.readOnly ? 1 : 0
|
|
525
|
+
connection.readOnly ? 1 : 0,
|
|
526
|
+
nextLogoPath
|
|
479
527
|
);
|
|
480
528
|
|
|
481
529
|
if (makeActive) {
|
|
@@ -485,10 +533,16 @@ class AppStateStore {
|
|
|
485
533
|
this.trimRecentConnections();
|
|
486
534
|
})();
|
|
487
535
|
|
|
536
|
+
if (this.normalizeLogoPath(existing?.logoPath) !== nextLogoPath) {
|
|
537
|
+
this.deleteConnectionLogo(existing?.logoPath);
|
|
538
|
+
}
|
|
539
|
+
|
|
488
540
|
return this.getRecentConnections();
|
|
489
541
|
}
|
|
490
542
|
|
|
491
543
|
removeRecentConnection(id) {
|
|
544
|
+
const existing = this.getRecentConnections().find((connection) => connection.id === id);
|
|
545
|
+
|
|
492
546
|
this.db.transaction(() => {
|
|
493
547
|
this.db.prepare("DELETE FROM recent_connections WHERE id = ?").run(id);
|
|
494
548
|
|
|
@@ -497,6 +551,8 @@ class AppStateStore {
|
|
|
497
551
|
}
|
|
498
552
|
})();
|
|
499
553
|
|
|
554
|
+
this.deleteConnectionLogo(existing?.logoPath);
|
|
555
|
+
|
|
500
556
|
return this.getState();
|
|
501
557
|
}
|
|
502
558
|
|
|
@@ -518,16 +574,18 @@ class AppStateStore {
|
|
|
518
574
|
lastOpenedAt,
|
|
519
575
|
lastModifiedAt,
|
|
520
576
|
sizeBytes,
|
|
521
|
-
readOnly
|
|
577
|
+
readOnly,
|
|
578
|
+
logoPath
|
|
522
579
|
)
|
|
523
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
580
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
524
581
|
ON CONFLICT(id) DO UPDATE SET
|
|
525
582
|
label = excluded.label,
|
|
526
583
|
path = excluded.path,
|
|
527
584
|
lastOpenedAt = excluded.lastOpenedAt,
|
|
528
585
|
lastModifiedAt = excluded.lastModifiedAt,
|
|
529
586
|
sizeBytes = excluded.sizeBytes,
|
|
530
|
-
readOnly = excluded.readOnly
|
|
587
|
+
readOnly = excluded.readOnly,
|
|
588
|
+
logoPath = excluded.logoPath
|
|
531
589
|
`)
|
|
532
590
|
.run(
|
|
533
591
|
nextConnection.id,
|
|
@@ -536,12 +594,93 @@ class AppStateStore {
|
|
|
536
594
|
nextConnection.lastOpenedAt ?? existing.lastOpenedAt,
|
|
537
595
|
nextConnection.lastModifiedAt ?? null,
|
|
538
596
|
nextConnection.sizeBytes ?? null,
|
|
539
|
-
nextConnection.readOnly ? 1 : 0
|
|
597
|
+
nextConnection.readOnly ? 1 : 0,
|
|
598
|
+
this.normalizeLogoPath(nextConnection.logoPath)
|
|
540
599
|
);
|
|
541
600
|
|
|
601
|
+
if (this.normalizeLogoPath(nextConnection.logoPath) !== this.normalizeLogoPath(existing.logoPath)) {
|
|
602
|
+
this.deleteConnectionLogo(existing.logoPath);
|
|
603
|
+
}
|
|
604
|
+
|
|
542
605
|
return this.getRecentConnections();
|
|
543
606
|
}
|
|
544
607
|
|
|
608
|
+
getConnectionLogoUrl(logoPath) {
|
|
609
|
+
const normalizedLogoPath = this.normalizeLogoPath(logoPath);
|
|
610
|
+
|
|
611
|
+
if (!normalizedLogoPath) {
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return `/${CONNECTION_LOGO_DIRECTORY}/${encodeURIComponent(normalizedLogoPath)}`;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
saveConnectionLogo(connectionId, logoUpload = {}) {
|
|
619
|
+
const fileName = String(logoUpload.fileName ?? "").trim();
|
|
620
|
+
const mimeType = String(logoUpload.mimeType ?? "").trim().toLowerCase();
|
|
621
|
+
const base64 = String(logoUpload.base64 ?? "").trim();
|
|
622
|
+
const extension =
|
|
623
|
+
CONNECTION_LOGO_EXTENSION_BY_MIME_TYPE[mimeType] ??
|
|
624
|
+
CONNECTION_LOGO_EXTENSION_BY_FILE_EXTENSION[path.extname(fileName).toLowerCase()] ??
|
|
625
|
+
null;
|
|
626
|
+
|
|
627
|
+
if (!extension) {
|
|
628
|
+
throw new ValidationError("Connection logos must be one of: .png, .jpg, .jpeg, .webp");
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (!base64) {
|
|
632
|
+
throw new ValidationError("Connection logo upload is empty.");
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const buffer = Buffer.from(base64, "base64");
|
|
636
|
+
|
|
637
|
+
if (!buffer.length) {
|
|
638
|
+
throw new ValidationError("Connection logo upload is empty.");
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (buffer.length > MAX_CONNECTION_LOGO_SIZE_BYTES) {
|
|
642
|
+
throw new ValidationError("Connection logo must be 5 MB or smaller.");
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const safeConnectionId = String(connectionId ?? "connection").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
646
|
+
const storedFileName = `${safeConnectionId}-${Date.now()}.${extension}`;
|
|
647
|
+
|
|
648
|
+
fs.writeFileSync(path.join(this.logoDirectory, storedFileName), buffer);
|
|
649
|
+
|
|
650
|
+
return storedFileName;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
deleteConnectionLogo(logoPath) {
|
|
654
|
+
const normalizedLogoPath = this.normalizeLogoPath(logoPath);
|
|
655
|
+
|
|
656
|
+
if (!normalizedLogoPath) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
fs.rmSync(path.join(this.logoDirectory, normalizedLogoPath), { force: true });
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
decorateConnection(connection = {}) {
|
|
664
|
+
const logoPath = this.normalizeLogoPath(connection.logoPath);
|
|
665
|
+
|
|
666
|
+
return {
|
|
667
|
+
...connection,
|
|
668
|
+
readOnly: Boolean(connection.readOnly),
|
|
669
|
+
logoPath,
|
|
670
|
+
logoUrl: this.getConnectionLogoUrl(logoPath),
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
normalizeLogoPath(logoPath) {
|
|
675
|
+
const trimmedLogoPath = String(logoPath ?? "").trim();
|
|
676
|
+
|
|
677
|
+
if (!trimmedLogoPath) {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
return path.basename(trimmedLogoPath);
|
|
682
|
+
}
|
|
683
|
+
|
|
545
684
|
setActiveConnectionId(id) {
|
|
546
685
|
this.setMetaValue("activeConnectionId", id ?? null);
|
|
547
686
|
return this.getActiveConnectionId();
|
package/server/utils/appPaths.js
CHANGED
|
@@ -6,6 +6,13 @@ const APP_NAME = "sqlite-hub";
|
|
|
6
6
|
const APP_STATE_DB_FILENAME = "sqlite-hub-state.db";
|
|
7
7
|
const LEGACY_STATE_FILENAME = "app-state.json";
|
|
8
8
|
|
|
9
|
+
function resolvePackagedDataDirectories(packageRoot) {
|
|
10
|
+
return [
|
|
11
|
+
path.resolve(packageRoot, "server", "data"),
|
|
12
|
+
path.resolve(packageRoot, "data"),
|
|
13
|
+
].filter((candidatePath, index, candidates) => candidates.indexOf(candidatePath) === index);
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
function resolveAppStateDirectory() {
|
|
10
17
|
const homeDirectory = os.homedir();
|
|
11
18
|
|
|
@@ -28,7 +35,7 @@ function resolveAppStateDirectory() {
|
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
function resolvePackagedDataDirectory(packageRoot) {
|
|
31
|
-
return
|
|
38
|
+
return resolvePackagedDataDirectories(packageRoot)[0];
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
function resolvePackagedAppStateDbPath(packageRoot) {
|
|
@@ -36,7 +43,11 @@ function resolvePackagedAppStateDbPath(packageRoot) {
|
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
function resolvePackagedLegacyStatePath(packageRoot) {
|
|
39
|
-
|
|
46
|
+
const candidates = resolvePackagedDataDirectories(packageRoot).map((directoryPath) =>
|
|
47
|
+
path.join(directoryPath, LEGACY_STATE_FILENAME)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return candidates.find((candidatePath) => fs.existsSync(candidatePath)) ?? candidates[0];
|
|
40
51
|
}
|
|
41
52
|
|
|
42
53
|
function resolveHomebrewCellarInfo(packageRoot) {
|
|
@@ -83,23 +94,34 @@ function collectHomebrewLegacyStateDbPaths(packageRoot) {
|
|
|
83
94
|
return fs
|
|
84
95
|
.readdirSync(cellarInfo.cellarRoot, { withFileTypes: true })
|
|
85
96
|
.filter((entry) => entry.isDirectory() && entry.name !== cellarInfo.currentVersion)
|
|
86
|
-
.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
.flatMap((entry) =>
|
|
98
|
+
[
|
|
99
|
+
path.join(
|
|
100
|
+
cellarInfo.cellarRoot,
|
|
101
|
+
entry.name,
|
|
102
|
+
"libexec",
|
|
103
|
+
"lib",
|
|
104
|
+
"node_modules",
|
|
105
|
+
APP_NAME,
|
|
106
|
+
"server",
|
|
107
|
+
"data",
|
|
108
|
+
APP_STATE_DB_FILENAME
|
|
109
|
+
),
|
|
110
|
+
path.join(
|
|
111
|
+
cellarInfo.cellarRoot,
|
|
112
|
+
entry.name,
|
|
113
|
+
"libexec",
|
|
114
|
+
"lib",
|
|
115
|
+
"node_modules",
|
|
116
|
+
APP_NAME,
|
|
117
|
+
"data",
|
|
118
|
+
APP_STATE_DB_FILENAME
|
|
119
|
+
),
|
|
120
|
+
].map((candidatePath) => ({
|
|
99
121
|
path: candidatePath,
|
|
100
122
|
mtimeMs: safeStatMtimeMs(candidatePath),
|
|
101
|
-
}
|
|
102
|
-
|
|
123
|
+
}))
|
|
124
|
+
)
|
|
103
125
|
.filter((candidate) => candidate.mtimeMs >= 0)
|
|
104
126
|
.sort((left, right) => right.mtimeMs - left.mtimeMs)
|
|
105
127
|
.map((candidate) => candidate.path);
|
|
@@ -107,7 +129,9 @@ function collectHomebrewLegacyStateDbPaths(packageRoot) {
|
|
|
107
129
|
|
|
108
130
|
function collectLegacyDatabasePaths(packageRoot) {
|
|
109
131
|
return [
|
|
110
|
-
|
|
132
|
+
...resolvePackagedDataDirectories(packageRoot).map((directoryPath) =>
|
|
133
|
+
path.join(directoryPath, APP_STATE_DB_FILENAME)
|
|
134
|
+
),
|
|
111
135
|
...collectHomebrewLegacyStateDbPaths(packageRoot),
|
|
112
136
|
].filter((candidatePath, index, candidates) => candidates.indexOf(candidatePath) === index);
|
|
113
137
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|