@creeperhost/modlens-mcp 1.6.0 → 1.6.4

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 (135) hide show
  1. package/README.md +950 -938
  2. package/dist/cli.js +267 -267
  3. package/dist/db-backend.d.ts +14 -1
  4. package/dist/db-backend.d.ts.map +1 -1
  5. package/dist/db-backend.js +13 -0
  6. package/dist/db-backend.js.map +1 -1
  7. package/dist/generated/sqlite/internal/class.d.ts.map +1 -1
  8. package/dist/generated/sqlite/internal/class.js +5 -4
  9. package/dist/generated/sqlite/internal/class.js.map +1 -1
  10. package/dist/launcher.js +4 -1
  11. package/dist/launcher.js.map +1 -1
  12. package/dist/platform.d.ts.map +1 -1
  13. package/dist/platform.js +6 -2
  14. package/dist/platform.js.map +1 -1
  15. package/dist/repositories/embeddings-sqlite.js +21 -21
  16. package/dist/repositories/embeddings.js +28 -28
  17. package/dist/repositories/mod.d.ts +7 -0
  18. package/dist/repositories/mod.d.ts.map +1 -1
  19. package/dist/repositories/mod.js +56 -15
  20. package/dist/repositories/mod.js.map +1 -1
  21. package/dist/search-adapter.js +51 -51
  22. package/dist/security.d.ts +9 -0
  23. package/dist/security.d.ts.map +1 -1
  24. package/dist/security.js +19 -0
  25. package/dist/security.js.map +1 -1
  26. package/dist/server.js +1248 -1217
  27. package/dist/server.js.map +1 -1
  28. package/dist/tools/compat-check.js +9 -9
  29. package/dist/tools/docs.d.ts.map +1 -1
  30. package/dist/tools/docs.js +4 -3
  31. package/dist/tools/docs.js.map +1 -1
  32. package/dist/tools/embed-registry.js +9 -9
  33. package/dist/tools/graphify.js +14 -14
  34. package/dist/tools/ingest.d.ts.map +1 -1
  35. package/dist/tools/ingest.js +4 -3
  36. package/dist/tools/ingest.js.map +1 -1
  37. package/dist/tools/kubejs.d.ts.map +1 -1
  38. package/dist/tools/kubejs.js +2 -0
  39. package/dist/tools/kubejs.js.map +1 -1
  40. package/dist/tools/mappings.d.ts.map +1 -1
  41. package/dist/tools/mappings.js +2 -1
  42. package/dist/tools/mappings.js.map +1 -1
  43. package/dist/tools/mc-fts.js +2 -2
  44. package/dist/tools/mcmeta.js +2 -2
  45. package/dist/tools/mcmeta.js.map +1 -1
  46. package/dist/tools/mixin-scan.d.ts +1 -1
  47. package/dist/tools/mixin-scan.d.ts.map +1 -1
  48. package/dist/tools/mixin-scan.js +29 -35
  49. package/dist/tools/mixin-scan.js.map +1 -1
  50. package/dist/tools/mod-data.js +2 -2
  51. package/dist/tools/mod-data.js.map +1 -1
  52. package/dist/tools/modpacks-ch.js +2 -2
  53. package/dist/tools/modpacks-ch.js.map +1 -1
  54. package/dist/tools/packtools.js +4 -4
  55. package/dist/tools/packtools.js.map +1 -1
  56. package/dist/tools/primers.d.ts.map +1 -1
  57. package/dist/tools/primers.js +4 -3
  58. package/dist/tools/primers.js.map +1 -1
  59. package/dist/tools/reports.d.ts.map +1 -1
  60. package/dist/tools/reports.js +8 -4
  61. package/dist/tools/reports.js.map +1 -1
  62. package/dist/tools/vanilla-data.js +2 -2
  63. package/dist/tools/vanilla-data.js.map +1 -1
  64. package/dist/tools/version-diff.js +3 -3
  65. package/package.json +70 -62
  66. package/prisma/backends/schema.sqlite.prisma +215 -215
  67. package/prisma/schema.prisma +303 -303
  68. package/scripts/backup.mjs +151 -151
  69. package/scripts/check-atm10.mjs +27 -27
  70. package/scripts/check-sync.mjs +13 -13
  71. package/scripts/create-fts-index.mjs +50 -50
  72. package/scripts/enable-pgvector.mjs +90 -90
  73. package/scripts/enable-sqlite-vec.mjs +158 -158
  74. package/scripts/migrate-backend.mjs +188 -188
  75. package/scripts/migrate-embed-provenance.mjs +80 -80
  76. package/scripts/migrate-metadata-source.mjs +62 -62
  77. package/scripts/migrate-mod-source-files.mjs +67 -67
  78. package/scripts/post-update.mjs +77 -77
  79. package/scripts/verify-atm10.mjs +63 -63
  80. package/dist/access-flags.test.d.ts +0 -2
  81. package/dist/access-flags.test.d.ts.map +0 -1
  82. package/dist/access-flags.test.js +0 -189
  83. package/dist/access-flags.test.js.map +0 -1
  84. package/dist/fetch-utils.test.d.ts +0 -2
  85. package/dist/fetch-utils.test.d.ts.map +0 -1
  86. package/dist/fetch-utils.test.js +0 -133
  87. package/dist/fetch-utils.test.js.map +0 -1
  88. package/dist/mappings.test.d.ts +0 -2
  89. package/dist/mappings.test.d.ts.map +0 -1
  90. package/dist/mappings.test.js +0 -161
  91. package/dist/mappings.test.js.map +0 -1
  92. package/dist/processor.test.d.ts +0 -2
  93. package/dist/processor.test.d.ts.map +0 -1
  94. package/dist/processor.test.js +0 -629
  95. package/dist/processor.test.js.map +0 -1
  96. package/dist/search.test.d.ts +0 -2
  97. package/dist/search.test.d.ts.map +0 -1
  98. package/dist/search.test.js +0 -71
  99. package/dist/search.test.js.map +0 -1
  100. package/dist/security.test.d.ts +0 -2
  101. package/dist/security.test.d.ts.map +0 -1
  102. package/dist/security.test.js +0 -687
  103. package/dist/security.test.js.map +0 -1
  104. package/dist/tools/compat-check.test.d.ts +0 -2
  105. package/dist/tools/compat-check.test.d.ts.map +0 -1
  106. package/dist/tools/compat-check.test.js +0 -179
  107. package/dist/tools/compat-check.test.js.map +0 -1
  108. package/dist/tools/diagnostics.test.d.ts +0 -2
  109. package/dist/tools/diagnostics.test.d.ts.map +0 -1
  110. package/dist/tools/diagnostics.test.js +0 -168
  111. package/dist/tools/diagnostics.test.js.map +0 -1
  112. package/dist/tools/graphify.test.d.ts +0 -2
  113. package/dist/tools/graphify.test.d.ts.map +0 -1
  114. package/dist/tools/graphify.test.js +0 -39
  115. package/dist/tools/graphify.test.js.map +0 -1
  116. package/dist/tools/ingest.test.d.ts +0 -2
  117. package/dist/tools/ingest.test.d.ts.map +0 -1
  118. package/dist/tools/ingest.test.js +0 -340
  119. package/dist/tools/ingest.test.js.map +0 -1
  120. package/dist/tools/mod-tags.test.d.ts +0 -2
  121. package/dist/tools/mod-tags.test.d.ts.map +0 -1
  122. package/dist/tools/mod-tags.test.js +0 -75
  123. package/dist/tools/mod-tags.test.js.map +0 -1
  124. package/dist/tools/packtools.test.d.ts +0 -2
  125. package/dist/tools/packtools.test.d.ts.map +0 -1
  126. package/dist/tools/packtools.test.js +0 -99
  127. package/dist/tools/packtools.test.js.map +0 -1
  128. package/dist/tools/version-diff.test.d.ts +0 -2
  129. package/dist/tools/version-diff.test.d.ts.map +0 -1
  130. package/dist/tools/version-diff.test.js +0 -102
  131. package/dist/tools/version-diff.test.js.map +0 -1
  132. package/dist/validate.test.d.ts +0 -2
  133. package/dist/validate.test.d.ts.map +0 -1
  134. package/dist/validate.test.js +0 -73
  135. package/dist/validate.test.js.map +0 -1
@@ -1,188 +1,188 @@
1
- // scripts/migrate-backend.mjs
2
- /**
3
- * Migrate core modlens data between backends.
4
- *
5
- * Usage:
6
- * SOURCE_DATABASE_URL=postgresql://... DATABASE_URL=pglite:///path node scripts/migrate-backend.mjs
7
- *
8
- * Migrates: mods, mod_classes, mod_tags, doc_entries, primers.
9
- * Skips: mc_versions, mc_source_files (too large — user re-indexes).
10
- * Safe: uses INSERT OR IGNORE (SQLite) / ON CONFLICT DO NOTHING (Postgres/PGlite).
11
- */
12
- import { createRequire } from "module";
13
- const require = createRequire(import.meta.url);
14
-
15
- try { require("dotenv").config(); } catch { /* optional */ }
16
-
17
- const TABLES = ["mods", "mod_classes", "mod_tags", "doc_entries", "primers"];
18
-
19
- function detectBackend(url) {
20
- if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
21
- if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
22
- return "postgres";
23
- }
24
-
25
- // ── Source readers ────────────────────────────────────────────────────────────
26
-
27
- async function readSourceSqlite(url, table) {
28
- const Database = require("better-sqlite3");
29
- const path = url.replace(/^file:\/\//, "").replace(/^file:/, "");
30
- const db = new Database(path, { readonly: true });
31
- const rows = db.prepare(`SELECT * FROM "${table}"`).all();
32
- db.close();
33
- return rows;
34
- }
35
-
36
- async function readSourcePglite(url, table) {
37
- const { PGlite } = require("@electric-sql/pglite");
38
- const dataDir = url.replace(/^pglite:\/\//, "");
39
- const pg = await PGlite.create(dataDir);
40
- const result = await pg.query(`SELECT * FROM "${table}"`);
41
- await pg.close();
42
- return result.rows;
43
- }
44
-
45
- async function readSourcePostgres(url, table) {
46
- const pg = (await import("pg")).default;
47
- const client = new pg.Client({ connectionString: url });
48
- await client.connect();
49
- const result = await client.query(`SELECT * FROM "${table}"`);
50
- await client.end();
51
- return result.rows;
52
- }
53
-
54
- async function readFromSource(backend, url, table) {
55
- if (backend === "sqlite") return readSourceSqlite(url, table);
56
- if (backend === "pglite") return readSourcePglite(url, table);
57
- return readSourcePostgres(url, table);
58
- }
59
-
60
- // ── Target writers ────────────────────────────────────────────────────────────
61
-
62
- async function writeTargetSqlite(url, table, rows) {
63
- const Database = require("better-sqlite3");
64
- const path = url.replace(/^file:\/\//, "").replace(/^file:/, "");
65
- const db = new Database(path);
66
- const cols = Object.keys(rows[0]);
67
- const placeholders = cols.map(() => "?").join(", ");
68
- const stmt = db.prepare(
69
- `INSERT OR IGNORE INTO "${table}" (${cols.map(c => `"${c}"`).join(", ")}) VALUES (${placeholders})`,
70
- );
71
- let inserted = 0;
72
- let skipped = 0;
73
- const insertMany = db.transaction((allRows) => {
74
- for (const row of allRows) {
75
- const vals = cols.map((c) => {
76
- const v = row[c];
77
- // Postgres arrays → JSON strings for SQLite column type
78
- return Array.isArray(v) ? JSON.stringify(v) : v;
79
- });
80
- const info = stmt.run(...vals);
81
- if (info.changes > 0) inserted++; else skipped++;
82
- }
83
- });
84
- insertMany(rows);
85
- db.close();
86
- return { inserted, skipped };
87
- }
88
-
89
- async function writeTargetPg(url, table, rows, isPglite) {
90
- let client;
91
- let needsClose = false;
92
- if (isPglite) {
93
- const { PGlite } = require("@electric-sql/pglite");
94
- const dataDir = url.replace(/^pglite:\/\//, "");
95
- client = await PGlite.create(dataDir);
96
- needsClose = true;
97
- } else {
98
- const pg = (await import("pg")).default;
99
- client = new pg.Client({ connectionString: url });
100
- await client.connect();
101
- needsClose = true;
102
- }
103
-
104
- const cols = Object.keys(rows[0]);
105
- const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
106
- const sql = `INSERT INTO "${table}" (${cols.map(c => `"${c}"`).join(", ")}) VALUES (${placeholders}) ON CONFLICT DO NOTHING`;
107
-
108
- let inserted = 0;
109
- let skipped = 0;
110
-
111
- for (const row of rows) {
112
- const vals = cols.map((c) => row[c]);
113
- try {
114
- const result = await client.query(sql, vals);
115
- if ((result.rowCount ?? 0) > 0) inserted++; else skipped++;
116
- } catch {
117
- skipped++;
118
- }
119
- }
120
-
121
- if (needsClose) {
122
- await (client.end?.() ?? client.close?.());
123
- }
124
-
125
- return { inserted, skipped };
126
- }
127
-
128
- // ── Migration runner ──────────────────────────────────────────────────────────
129
-
130
- /**
131
- * Migrate core data from sourceUrl to targetUrl.
132
- * @param {string} sourceUrl
133
- * @param {string} targetUrl
134
- * @returns {Promise<number>} total rows inserted
135
- */
136
- export async function migrate(sourceUrl, targetUrl) {
137
- const srcBackend = detectBackend(sourceUrl);
138
- const tgtBackend = detectBackend(targetUrl);
139
- console.log(`Migrating ${srcBackend} → ${tgtBackend}`);
140
-
141
- let total = 0;
142
-
143
- for (const table of TABLES) {
144
- process.stdout.write(` Reading ${table}...`);
145
- let rows;
146
- try {
147
- rows = await readFromSource(srcBackend, sourceUrl, table);
148
- process.stdout.write(` ${rows.length} rows\n`);
149
- } catch (e) {
150
- process.stdout.write(` SKIP (${e.message})\n`);
151
- continue;
152
- }
153
- if (!rows.length) { console.log(` ${table}: 0 rows`); continue; }
154
-
155
- let stats;
156
- try {
157
- if (tgtBackend === "sqlite") {
158
- stats = await writeTargetSqlite(targetUrl, table, rows);
159
- } else {
160
- stats = await writeTargetPg(targetUrl, table, rows, tgtBackend === "pglite");
161
- }
162
- } catch (e) {
163
- console.error(` ${table}: write failed — ${e.message}`);
164
- continue;
165
- }
166
- console.log(` ${table}: ${stats.inserted} inserted, ${stats.skipped} skipped`);
167
- total += stats.inserted;
168
- }
169
-
170
- console.log(`\nMigration complete. ${total} total rows inserted.`);
171
- console.log(
172
- "Note: mc_versions / mc_source_files were not migrated — re-run index after setup.",
173
- );
174
- return total;
175
- }
176
-
177
- // ── CLI entry point ───────────────────────────────────────────────────────────
178
-
179
- const isCli = process.argv[1]?.replace(/\\/g, "/").endsWith("migrate-backend.mjs");
180
- if (isCli) {
181
- const sourceUrl = process.env.SOURCE_DATABASE_URL ?? "";
182
- const targetUrl = process.env.DATABASE_URL ?? "";
183
- if (!sourceUrl || !targetUrl) {
184
- console.error("Set SOURCE_DATABASE_URL (old backend) and DATABASE_URL (new backend).");
185
- process.exit(1);
186
- }
187
- await migrate(sourceUrl, targetUrl);
188
- }
1
+ // scripts/migrate-backend.mjs
2
+ /**
3
+ * Migrate core modlens data between backends.
4
+ *
5
+ * Usage:
6
+ * SOURCE_DATABASE_URL=postgresql://... DATABASE_URL=pglite:///path node scripts/migrate-backend.mjs
7
+ *
8
+ * Migrates: mods, mod_classes, mod_tags, doc_entries, primers.
9
+ * Skips: mc_versions, mc_source_files (too large — user re-indexes).
10
+ * Safe: uses INSERT OR IGNORE (SQLite) / ON CONFLICT DO NOTHING (Postgres/PGlite).
11
+ */
12
+ import { createRequire } from "module";
13
+ const require = createRequire(import.meta.url);
14
+
15
+ try { require("dotenv").config(); } catch { /* optional */ }
16
+
17
+ const TABLES = ["mods", "mod_classes", "mod_tags", "doc_entries", "primers"];
18
+
19
+ function detectBackend(url) {
20
+ if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
21
+ if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
22
+ return "postgres";
23
+ }
24
+
25
+ // ── Source readers ────────────────────────────────────────────────────────────
26
+
27
+ async function readSourceSqlite(url, table) {
28
+ const Database = require("better-sqlite3");
29
+ const path = url.replace(/^file:\/\//, "").replace(/^file:/, "");
30
+ const db = new Database(path, { readonly: true });
31
+ const rows = db.prepare(`SELECT * FROM "${table}"`).all();
32
+ db.close();
33
+ return rows;
34
+ }
35
+
36
+ async function readSourcePglite(url, table) {
37
+ const { PGlite } = require("@electric-sql/pglite");
38
+ const dataDir = url.replace(/^pglite:\/\//, "");
39
+ const pg = await PGlite.create(dataDir);
40
+ const result = await pg.query(`SELECT * FROM "${table}"`);
41
+ await pg.close();
42
+ return result.rows;
43
+ }
44
+
45
+ async function readSourcePostgres(url, table) {
46
+ const pg = (await import("pg")).default;
47
+ const client = new pg.Client({ connectionString: url });
48
+ await client.connect();
49
+ const result = await client.query(`SELECT * FROM "${table}"`);
50
+ await client.end();
51
+ return result.rows;
52
+ }
53
+
54
+ async function readFromSource(backend, url, table) {
55
+ if (backend === "sqlite") return readSourceSqlite(url, table);
56
+ if (backend === "pglite") return readSourcePglite(url, table);
57
+ return readSourcePostgres(url, table);
58
+ }
59
+
60
+ // ── Target writers ────────────────────────────────────────────────────────────
61
+
62
+ async function writeTargetSqlite(url, table, rows) {
63
+ const Database = require("better-sqlite3");
64
+ const path = url.replace(/^file:\/\//, "").replace(/^file:/, "");
65
+ const db = new Database(path);
66
+ const cols = Object.keys(rows[0]);
67
+ const placeholders = cols.map(() => "?").join(", ");
68
+ const stmt = db.prepare(
69
+ `INSERT OR IGNORE INTO "${table}" (${cols.map(c => `"${c}"`).join(", ")}) VALUES (${placeholders})`,
70
+ );
71
+ let inserted = 0;
72
+ let skipped = 0;
73
+ const insertMany = db.transaction((allRows) => {
74
+ for (const row of allRows) {
75
+ const vals = cols.map((c) => {
76
+ const v = row[c];
77
+ // Postgres arrays → JSON strings for SQLite column type
78
+ return Array.isArray(v) ? JSON.stringify(v) : v;
79
+ });
80
+ const info = stmt.run(...vals);
81
+ if (info.changes > 0) inserted++; else skipped++;
82
+ }
83
+ });
84
+ insertMany(rows);
85
+ db.close();
86
+ return { inserted, skipped };
87
+ }
88
+
89
+ async function writeTargetPg(url, table, rows, isPglite) {
90
+ let client;
91
+ let needsClose = false;
92
+ if (isPglite) {
93
+ const { PGlite } = require("@electric-sql/pglite");
94
+ const dataDir = url.replace(/^pglite:\/\//, "");
95
+ client = await PGlite.create(dataDir);
96
+ needsClose = true;
97
+ } else {
98
+ const pg = (await import("pg")).default;
99
+ client = new pg.Client({ connectionString: url });
100
+ await client.connect();
101
+ needsClose = true;
102
+ }
103
+
104
+ const cols = Object.keys(rows[0]);
105
+ const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
106
+ const sql = `INSERT INTO "${table}" (${cols.map(c => `"${c}"`).join(", ")}) VALUES (${placeholders}) ON CONFLICT DO NOTHING`;
107
+
108
+ let inserted = 0;
109
+ let skipped = 0;
110
+
111
+ for (const row of rows) {
112
+ const vals = cols.map((c) => row[c]);
113
+ try {
114
+ const result = await client.query(sql, vals);
115
+ if ((result.rowCount ?? 0) > 0) inserted++; else skipped++;
116
+ } catch {
117
+ skipped++;
118
+ }
119
+ }
120
+
121
+ if (needsClose) {
122
+ await (client.end?.() ?? client.close?.());
123
+ }
124
+
125
+ return { inserted, skipped };
126
+ }
127
+
128
+ // ── Migration runner ──────────────────────────────────────────────────────────
129
+
130
+ /**
131
+ * Migrate core data from sourceUrl to targetUrl.
132
+ * @param {string} sourceUrl
133
+ * @param {string} targetUrl
134
+ * @returns {Promise<number>} total rows inserted
135
+ */
136
+ export async function migrate(sourceUrl, targetUrl) {
137
+ const srcBackend = detectBackend(sourceUrl);
138
+ const tgtBackend = detectBackend(targetUrl);
139
+ console.log(`Migrating ${srcBackend} → ${tgtBackend}`);
140
+
141
+ let total = 0;
142
+
143
+ for (const table of TABLES) {
144
+ process.stdout.write(` Reading ${table}...`);
145
+ let rows;
146
+ try {
147
+ rows = await readFromSource(srcBackend, sourceUrl, table);
148
+ process.stdout.write(` ${rows.length} rows\n`);
149
+ } catch (e) {
150
+ process.stdout.write(` SKIP (${e.message})\n`);
151
+ continue;
152
+ }
153
+ if (!rows.length) { console.log(` ${table}: 0 rows`); continue; }
154
+
155
+ let stats;
156
+ try {
157
+ if (tgtBackend === "sqlite") {
158
+ stats = await writeTargetSqlite(targetUrl, table, rows);
159
+ } else {
160
+ stats = await writeTargetPg(targetUrl, table, rows, tgtBackend === "pglite");
161
+ }
162
+ } catch (e) {
163
+ console.error(` ${table}: write failed — ${e.message}`);
164
+ continue;
165
+ }
166
+ console.log(` ${table}: ${stats.inserted} inserted, ${stats.skipped} skipped`);
167
+ total += stats.inserted;
168
+ }
169
+
170
+ console.log(`\nMigration complete. ${total} total rows inserted.`);
171
+ console.log(
172
+ "Note: mc_versions / mc_source_files were not migrated — re-run index after setup.",
173
+ );
174
+ return total;
175
+ }
176
+
177
+ // ── CLI entry point ───────────────────────────────────────────────────────────
178
+
179
+ const isCli = process.argv[1]?.replace(/\\/g, "/").endsWith("migrate-backend.mjs");
180
+ if (isCli) {
181
+ const sourceUrl = process.env.SOURCE_DATABASE_URL ?? "";
182
+ const targetUrl = process.env.DATABASE_URL ?? "";
183
+ if (!sourceUrl || !targetUrl) {
184
+ console.error("Set SOURCE_DATABASE_URL (old backend) and DATABASE_URL (new backend).");
185
+ process.exit(1);
186
+ }
187
+ await migrate(sourceUrl, targetUrl);
188
+ }
@@ -1,80 +1,80 @@
1
- /**
2
- * Add embed_source and embed_updated_at columns to mc_source_files and mod_source_files.
3
- * Safe to re-run — uses IF NOT EXISTS / ADD COLUMN IF NOT EXISTS guards.
4
- *
5
- * Usage: node scripts/migrate-embed-provenance.mjs
6
- */
7
- import { createRequire } from "module";
8
- const require = createRequire(import.meta.url);
9
-
10
- try { require("dotenv").config(); } catch { /* optional */ }
11
-
12
- const dbUrl = process.env.DATABASE_URL ?? "";
13
-
14
- function detectBackend(url) {
15
- if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
16
- if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
17
- return "postgres";
18
- }
19
-
20
- const TABLES = ["mc_source_files", "mod_source_files"];
21
- const COLUMNS = [
22
- { name: "embed_source", pgType: "TEXT", sqliteType: "TEXT" },
23
- { name: "embed_updated_at", pgType: "TIMESTAMPTZ", sqliteType: "DATETIME" },
24
- ];
25
-
26
- async function migrateSqlite() {
27
- const Database = require("better-sqlite3");
28
- const path = dbUrl.replace(/^file:\/\//, "").replace(/^file:/, "");
29
- const db = new Database(path);
30
- for (const table of TABLES) {
31
- for (const col of COLUMNS) {
32
- try {
33
- db.exec(`ALTER TABLE ${table} ADD COLUMN ${col.name} ${col.sqliteType}`);
34
- console.log(` + ${table}.${col.name}`);
35
- } catch (e) {
36
- if (e.message?.includes("duplicate column")) {
37
- console.log(` = ${table}.${col.name} (already exists)`);
38
- } else {
39
- throw e;
40
- }
41
- }
42
- }
43
- }
44
- db.close();
45
- }
46
-
47
- async function migratePostgres() {
48
- const { Client } = require("pg");
49
- const client = new Client({ connectionString: dbUrl });
50
- await client.connect();
51
- for (const table of TABLES) {
52
- for (const col of COLUMNS) {
53
- await client.query(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${col.name} ${col.pgType}`);
54
- console.log(` + ${table}.${col.name}`);
55
- }
56
- }
57
- await client.end();
58
- }
59
-
60
- async function migratePglite() {
61
- const { PGlite } = await import("@electric-sql/pglite");
62
- const dataDir = dbUrl.replace(/^pglite:\/\//, "").replace(/^pglite:/, "");
63
- const db = new PGlite(dataDir);
64
- for (const table of TABLES) {
65
- for (const col of COLUMNS) {
66
- await db.exec(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${col.name} ${col.pgType}`);
67
- console.log(` + ${table}.${col.name}`);
68
- }
69
- }
70
- await db.close();
71
- }
72
-
73
- const backend = detectBackend(dbUrl);
74
- console.log(`Migrating embed provenance columns (${backend})...`);
75
-
76
- if (backend === "sqlite") await migrateSqlite();
77
- else if (backend === "pglite") await migratePglite();
78
- else await migratePostgres();
79
-
80
- console.log("Done.");
1
+ /**
2
+ * Add embed_source and embed_updated_at columns to mc_source_files and mod_source_files.
3
+ * Safe to re-run — uses IF NOT EXISTS / ADD COLUMN IF NOT EXISTS guards.
4
+ *
5
+ * Usage: node scripts/migrate-embed-provenance.mjs
6
+ */
7
+ import { createRequire } from "module";
8
+ const require = createRequire(import.meta.url);
9
+
10
+ try { require("dotenv").config(); } catch { /* optional */ }
11
+
12
+ const dbUrl = process.env.DATABASE_URL ?? "";
13
+
14
+ function detectBackend(url) {
15
+ if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
16
+ if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
17
+ return "postgres";
18
+ }
19
+
20
+ const TABLES = ["mc_source_files", "mod_source_files"];
21
+ const COLUMNS = [
22
+ { name: "embed_source", pgType: "TEXT", sqliteType: "TEXT" },
23
+ { name: "embed_updated_at", pgType: "TIMESTAMPTZ", sqliteType: "DATETIME" },
24
+ ];
25
+
26
+ async function migrateSqlite() {
27
+ const Database = require("better-sqlite3");
28
+ const path = dbUrl.replace(/^file:\/\//, "").replace(/^file:/, "");
29
+ const db = new Database(path);
30
+ for (const table of TABLES) {
31
+ for (const col of COLUMNS) {
32
+ try {
33
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${col.name} ${col.sqliteType}`);
34
+ console.log(` + ${table}.${col.name}`);
35
+ } catch (e) {
36
+ if (e.message?.includes("duplicate column")) {
37
+ console.log(` = ${table}.${col.name} (already exists)`);
38
+ } else {
39
+ throw e;
40
+ }
41
+ }
42
+ }
43
+ }
44
+ db.close();
45
+ }
46
+
47
+ async function migratePostgres() {
48
+ const { Client } = require("pg");
49
+ const client = new Client({ connectionString: dbUrl });
50
+ await client.connect();
51
+ for (const table of TABLES) {
52
+ for (const col of COLUMNS) {
53
+ await client.query(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${col.name} ${col.pgType}`);
54
+ console.log(` + ${table}.${col.name}`);
55
+ }
56
+ }
57
+ await client.end();
58
+ }
59
+
60
+ async function migratePglite() {
61
+ const { PGlite } = await import("@electric-sql/pglite");
62
+ const dataDir = dbUrl.replace(/^pglite:\/\//, "").replace(/^pglite:/, "");
63
+ const db = new PGlite(dataDir);
64
+ for (const table of TABLES) {
65
+ for (const col of COLUMNS) {
66
+ await db.exec(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${col.name} ${col.pgType}`);
67
+ console.log(` + ${table}.${col.name}`);
68
+ }
69
+ }
70
+ await db.close();
71
+ }
72
+
73
+ const backend = detectBackend(dbUrl);
74
+ console.log(`Migrating embed provenance columns (${backend})...`);
75
+
76
+ if (backend === "sqlite") await migrateSqlite();
77
+ else if (backend === "pglite") await migratePglite();
78
+ else await migratePostgres();
79
+
80
+ console.log("Done.");
@@ -1,62 +1,62 @@
1
- /**
2
- * Add metadata_source column to the mods table.
3
- * Safe to re-run — uses IF NOT EXISTS / duplicate column guards.
4
- *
5
- * Usage: node scripts/migrate-metadata-source.mjs
6
- */
7
- import { createRequire } from "module";
8
- const require = createRequire(import.meta.url);
9
-
10
- try { require("dotenv").config(); } catch { /* optional */ }
11
-
12
- const dbUrl = process.env.DATABASE_URL ?? "";
13
-
14
- function detectBackend(url) {
15
- if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
16
- if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
17
- return "postgres";
18
- }
19
-
20
- async function migrateSqlite() {
21
- const Database = require("better-sqlite3");
22
- const path = dbUrl.replace(/^file:\/\//, "").replace(/^file:/, "");
23
- const db = new Database(path);
24
- try {
25
- db.exec(`ALTER TABLE mods ADD COLUMN metadata_source TEXT`);
26
- console.log(" + mods.metadata_source");
27
- } catch (e) {
28
- if (e.message?.includes("duplicate column")) {
29
- console.log(" = mods.metadata_source (already exists)");
30
- } else {
31
- throw e;
32
- }
33
- }
34
- db.close();
35
- }
36
-
37
- async function migratePostgres() {
38
- const { Client } = require("pg");
39
- const client = new Client({ connectionString: dbUrl });
40
- await client.connect();
41
- await client.query(`ALTER TABLE mods ADD COLUMN IF NOT EXISTS metadata_source TEXT`);
42
- console.log(" + mods.metadata_source");
43
- await client.end();
44
- }
45
-
46
- async function migratePglite() {
47
- const { PGlite } = await import("@electric-sql/pglite");
48
- const dataDir = dbUrl.replace(/^pglite:\/\//, "").replace(/^pglite:/, "");
49
- const db = new PGlite(dataDir);
50
- await db.exec(`ALTER TABLE mods ADD COLUMN IF NOT EXISTS metadata_source TEXT`);
51
- console.log(" + mods.metadata_source");
52
- await db.close();
53
- }
54
-
55
- const backend = detectBackend(dbUrl);
56
- console.log(`Migrating metadata_source column (${backend})...`);
57
-
58
- if (backend === "sqlite") await migrateSqlite();
59
- else if (backend === "pglite") await migratePglite();
60
- else await migratePostgres();
61
-
62
- console.log("Done.");
1
+ /**
2
+ * Add metadata_source column to the mods table.
3
+ * Safe to re-run — uses IF NOT EXISTS / duplicate column guards.
4
+ *
5
+ * Usage: node scripts/migrate-metadata-source.mjs
6
+ */
7
+ import { createRequire } from "module";
8
+ const require = createRequire(import.meta.url);
9
+
10
+ try { require("dotenv").config(); } catch { /* optional */ }
11
+
12
+ const dbUrl = process.env.DATABASE_URL ?? "";
13
+
14
+ function detectBackend(url) {
15
+ if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
16
+ if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
17
+ return "postgres";
18
+ }
19
+
20
+ async function migrateSqlite() {
21
+ const Database = require("better-sqlite3");
22
+ const path = dbUrl.replace(/^file:\/\//, "").replace(/^file:/, "");
23
+ const db = new Database(path);
24
+ try {
25
+ db.exec(`ALTER TABLE mods ADD COLUMN metadata_source TEXT`);
26
+ console.log(" + mods.metadata_source");
27
+ } catch (e) {
28
+ if (e.message?.includes("duplicate column")) {
29
+ console.log(" = mods.metadata_source (already exists)");
30
+ } else {
31
+ throw e;
32
+ }
33
+ }
34
+ db.close();
35
+ }
36
+
37
+ async function migratePostgres() {
38
+ const { Client } = require("pg");
39
+ const client = new Client({ connectionString: dbUrl });
40
+ await client.connect();
41
+ await client.query(`ALTER TABLE mods ADD COLUMN IF NOT EXISTS metadata_source TEXT`);
42
+ console.log(" + mods.metadata_source");
43
+ await client.end();
44
+ }
45
+
46
+ async function migratePglite() {
47
+ const { PGlite } = await import("@electric-sql/pglite");
48
+ const dataDir = dbUrl.replace(/^pglite:\/\//, "").replace(/^pglite:/, "");
49
+ const db = new PGlite(dataDir);
50
+ await db.exec(`ALTER TABLE mods ADD COLUMN IF NOT EXISTS metadata_source TEXT`);
51
+ console.log(" + mods.metadata_source");
52
+ await db.close();
53
+ }
54
+
55
+ const backend = detectBackend(dbUrl);
56
+ console.log(`Migrating metadata_source column (${backend})...`);
57
+
58
+ if (backend === "sqlite") await migrateSqlite();
59
+ else if (backend === "pglite") await migratePglite();
60
+ else await migratePostgres();
61
+
62
+ console.log("Done.");