test: prove 2.8 to 2.9.0 upgrade is lossless and fix what it caught

This commit is contained in:
LukeGus committed 2026-09-25 09:58:45 -05:00
1 parent 2ee9b3592c
commit f779d6a08e
37 files changed
+5184 -377

No files matched your search

+3 -9
View File
@@ -19,6 +19,7 @@ import type {
} from "@termix/plugin-sdk/backend";
import type { PluginManifest } from "@termix/plugin-sdk/manifest";
import { assertCapability } from "./permissions.js";
import { getPluginDataDir } from "./paths.js";
import type { DisposableBag } from "./disposables.js";
type AuditFn = (
@@ -31,7 +32,7 @@ interface Deps {
manifest: PluginManifest;
bag: DisposableBag;
audit: AuditFn;
/** Where downloaded binaries go. Defaults to <DATA_DIR>/plugins/<id>/bin. */
/** Where downloaded binaries go. Defaults to <DATA_DIR>/plugin-data/<id>/bin. */
binDir?: () => string;
/** Test seam for the download. */
fetch?: typeof fetch;
@@ -58,14 +59,7 @@ export function createPluginProcess(deps: Deps): PluginProcess {
const pluginId = deps.manifest.id;
const declared = deps.manifest.capabilities;
const binDir =
deps.binDir ??
(() =>
path.join(
process.env.DATA_DIR ?? "./db/data",
"plugins",
pluginId,
"bin",
));
deps.binDir ?? (() => path.join(getPluginDataDir(pluginId), "bin"));
const doFetch = deps.fetch ?? fetch;
const audited = async <T>(
+2 -3
View File
@@ -300,9 +300,8 @@ export function createPluginContext(
"files:own",
async () => {
const fs = await import("node:fs/promises");
const path = await import("node:path");
const base = process.env.DATA_DIR ?? "./db/data";
const dir = path.join(base, "plugins", pluginId);
const { getPluginDataDir } = await import("./paths.js");
const dir = getPluginDataDir(pluginId);
await fs.mkdir(dir, { recursive: true });
return dir;
},
+4 -3
View File
@@ -78,10 +78,11 @@ export function resetPluginData(): void {
}
async function execute(statements: string[]): Promise<void> {
const { getDb } = await import("../database/db/index.js");
const db = getDb();
// getDb() has run() only on SQLite; runStatement picks execute() elsewhere.
const { runStatement } =
await import("../utils/crypto-migration/raw-rows.js");
for (const statement of statements) {
await db.run(sql.raw(statement));
await runStatement(sql.raw(statement));
}
}
+13
View File
@@ -15,6 +15,19 @@ export function getPluginsDir(): string {
return path.join(process.env.DATA_DIR || "./db/data", "plugins");
}
/**
* A plugin's own files (ctx.files.dataDir(), downloaded binaries). Kept out of
* getPluginsDir(), where the loader would read every data folder as a user
* plugin that clashes with the bundled one of the same name.
*/
export function getPluginDataDir(pluginId: string): string {
return path.join(
process.env.DATA_DIR || "./db/data",
"plugin-data",
pluginId,
);
}
/**
* Where user .tmxplug files are unpacked. A dot directory inside the user
* plugins dir, which the loader's directory scan skips.
+7 -6
View File
@@ -10,7 +10,10 @@ import { sql } from "drizzle-orm";
import { columnName, createTableSql } from "@termix/plugin-sdk/ddl";
import { prefixedTableName } from "@termix/plugin-sdk/db";
import type { PluginTableDefinition } from "@termix/plugin-sdk/db";
import { getDb } from "../database/db/index.js";
import {
runStatement,
selectRows,
} from "../utils/crypto-migration/raw-rows.js";
import { listAllTables } from "./data.js";
export interface UserOwnedTable {
@@ -56,11 +59,10 @@ type Row = Record<string, unknown>;
export async function readUserPluginRows(
userId: string,
): Promise<Record<string, Row[]>> {
const db = getDb();
const result: Record<string, Row[]> = {};
for (const owned of listUserOwnedTables()) {
try {
const rows = await db.all<Row>(
const rows = await selectRows<Row>(
sql`SELECT ${sql.join(
owned.columns.map((column) => sql.identifier(column)),
sql`, `,
@@ -137,7 +139,6 @@ export async function importUserPluginRows(
importDb: SqliteLike,
userId: string,
): Promise<PluginRowsImport> {
const db = getDb();
const summary: PluginRowsImport = { imported: 0, skipped: 0, errors: [] };
for (const owned of listUserOwnedTables()) {
@@ -160,7 +161,7 @@ export async function importUserPluginRows(
column === owned.userColumn ? userId : source[column],
);
try {
const existing = await db.all(
const existing = await selectRows(
sql`SELECT 1 FROM ${sql.identifier(owned.table)} WHERE ${sql.join(
columns.map((column, index) =>
values[index] === null
@@ -174,7 +175,7 @@ export async function importUserPluginRows(
summary.skipped++;
continue;
}
await db.run(
await runStatement(
sql`INSERT INTO ${sql.identifier(owned.table)} (${sql.join(
columns.map((column) => sql.identifier(column)),
sql`, `,