style: format server and shared with prettier

A mechanical prettier --write over server/src, server/tests, server/scripts
and shared/src with the workspaces' .prettierrc; nothing but layout and
import order changes, and every file keeps the same set of imports. shared
is formatted throughout and its format baseline is empty. The server
baseline keeps the 35 files that Prettier would grow past their lint:size
limit (they need a split first, which is not a formatting change), and the
generated entity files stay as their generator writes them.
This commit is contained in:
Maurice
2026-10-10 21:23:37 +02:00
parent f4e518b2df
commit 724c88c201
1978 changed files with 78448 additions and 39347 deletions
@@ -13,40 +13,40 @@
* so every one of the 14 repositories this task injects reads/writes real columns,
* not a hand-slimmed fixture table.
*/
import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest';
import { AuditLog } from '../../../src/db/entities/AuditLog.entity';
import { NotificationChannelPreferences } from '../../../src/db/entities/NotificationChannelPreferences.entity';
import { PluginActions } from '../../../src/db/entities/PluginActions.entity';
import { PluginCapabilityAudit } from '../../../src/db/entities/PluginCapabilityAudit.entity';
import { PluginEgressHosts } from '../../../src/db/entities/PluginEgressHosts.entity';
import { PluginEntityMetadata } from '../../../src/db/entities/PluginEntityMetadata.entity';
import { PluginErrorLog } from '../../../src/db/entities/PluginErrorLog.entity';
import { PluginMetaMigrations } from '../../../src/db/entities/PluginMetaMigrations.entity';
import { PluginOauthState } from '../../../src/db/entities/PluginOauthState.entity';
import { PluginOauthTokens } from '../../../src/db/entities/PluginOauthTokens.entity';
import { PluginScheduledTasks } from '../../../src/db/entities/PluginScheduledTasks.entity';
import { PluginSettingsFields } from '../../../src/db/entities/PluginSettingsFields.entity';
import { PluginUserConfig } from '../../../src/db/entities/PluginUserConfig.entity';
import { PluginUserErasureQueue } from '../../../src/db/entities/PluginUserErasureQueue.entity';
import { Plugins } from '../../../src/db/entities/Plugins.entity';
import { Settings } from '../../../src/db/entities/Settings.entity';
import { Users } from '../../../src/db/entities/Users.entity';
import type { RuntimeEnvService } from '../../../src/nest/app-config/runtime-env.service';
import { AuditService } from '../../../src/nest/audit/audit.service';
import { UnitOfWork } from '../../../src/nest/database/unit-of-work';
import { PluginRuntimeService, PluginDependencyError } from '../../../src/nest/plugins/plugin-runtime.service';
import { PluginUserSettingsService } from '../../../src/nest/plugins/plugin-user-settings.service';
import { PluginsService } from '../../../src/nest/plugins/plugins.service';
import { CronRegistrarService } from '../../../src/nest/scheduling/cron-registrar.service';
import { createSnapshotTestDb } from '../../helpers/db-mock';
import { countRows, findRow, insertRow, updateRows } from '../../helpers/factories/rows';
import { createTestAddonsService } from '../../helpers/test-addons';
import { createTestOrm, type TestOrm } from '../../helpers/test-orm';
import { SchedulerRegistry } from '@nestjs/schedule';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { SchedulerRegistry } from '@nestjs/schedule';
import { CronRegistrarService } from '../../../src/nest/scheduling/cron-registrar.service';
import { PluginRuntimeService, PluginDependencyError } from '../../../src/nest/plugins/plugin-runtime.service';
import { PluginsService } from '../../../src/nest/plugins/plugins.service';
import { AuditService } from '../../../src/nest/audit/audit.service';
import { PluginUserSettingsService } from '../../../src/nest/plugins/plugin-user-settings.service';
import { UnitOfWork } from '../../../src/nest/database/unit-of-work';
import { createTestAddonsService } from '../../helpers/test-addons';
import { createSnapshotTestDb } from '../../helpers/db-mock';
import { createTestOrm, type TestOrm } from '../../helpers/test-orm';
import { countRows, findRow, insertRow, updateRows } from '../../helpers/factories/rows';
import { AuditLog } from '../../../src/db/entities/AuditLog.entity';
import { Users } from '../../../src/db/entities/Users.entity';
import { Plugins } from '../../../src/db/entities/Plugins.entity';
import { PluginErrorLog } from '../../../src/db/entities/PluginErrorLog.entity';
import { PluginScheduledTasks } from '../../../src/db/entities/PluginScheduledTasks.entity';
import { PluginUserErasureQueue } from '../../../src/db/entities/PluginUserErasureQueue.entity';
import { PluginEgressHosts } from '../../../src/db/entities/PluginEgressHosts.entity';
import { PluginSettingsFields } from '../../../src/db/entities/PluginSettingsFields.entity';
import { PluginActions } from '../../../src/db/entities/PluginActions.entity';
import { PluginUserConfig } from '../../../src/db/entities/PluginUserConfig.entity';
import { PluginEntityMetadata } from '../../../src/db/entities/PluginEntityMetadata.entity';
import { PluginOauthTokens } from '../../../src/db/entities/PluginOauthTokens.entity';
import { PluginOauthState } from '../../../src/db/entities/PluginOauthState.entity';
import { PluginMetaMigrations } from '../../../src/db/entities/PluginMetaMigrations.entity';
import { PluginCapabilityAudit } from '../../../src/db/entities/PluginCapabilityAudit.entity';
import { Settings } from '../../../src/db/entities/Settings.entity';
import { NotificationChannelPreferences } from '../../../src/db/entities/NotificationChannelPreferences.entity';
import type { RuntimeEnvService } from '../../../src/nest/app-config/runtime-env.service';
import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest';
const testDb = createSnapshotTestDb();
let t: TestOrm;
@@ -78,14 +78,31 @@ async function buildRuntime(registrar?: CronRegistrarService): Promise<PluginRun
const userSettings = new PluginUserSettingsService(t.repo(PluginSettingsFields), t.repo(PluginUserConfig));
const uow = new UnitOfWork(t.em);
return new PluginRuntimeService(
audit, addons, userSettings,
t.repo(Plugins), t.repo(PluginErrorLog), t.repo(PluginScheduledTasks), t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts), t.repo(PluginSettingsFields), t.repo(PluginActions), t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata), t.repo(PluginOauthTokens), t.repo(PluginOauthState), t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit), t.repo(Settings), t.repo(NotificationChannelPreferences),
audit,
addons,
userSettings,
t.repo(Plugins),
t.repo(PluginErrorLog),
t.repo(PluginScheduledTasks),
t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts),
t.repo(PluginSettingsFields),
t.repo(PluginActions),
t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata),
t.repo(PluginOauthTokens),
t.repo(PluginOauthState),
t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit),
t.repo(Settings),
t.repo(NotificationChannelPreferences),
// Plan 4 Task 4: `uow` is no longer `@Optional()` — ordered ahead of
// `registry?`/`hostFactory?`, matching the real constructor's own order.
uow, undefined, undefined, t.orm, registrar,
uow,
undefined,
undefined,
t.orm,
registrar,
);
}
@@ -93,12 +110,28 @@ function buildPluginsService(): PluginsService {
return new PluginsService(
// A real AddonsService is not needed by any method this file calls.
{ isAddonEnabled: async () => true } as never,
t.repo(Plugins), t.repo(PluginEgressHosts), t.repo(PluginSettingsFields), t.repo(PluginActions),
t.repo(PluginUserConfig), t.repo(PluginErrorLog), t.repo(PluginCapabilityAudit),
t.repo(Plugins),
t.repo(PluginEgressHosts),
t.repo(PluginSettingsFields),
t.repo(PluginActions),
t.repo(PluginUserConfig),
t.repo(PluginErrorLog),
t.repo(PluginCapabilityAudit),
);
}
async function seedPlugin(id: string, overrides: Partial<{ enabled: number; granted_permissions: string; permissions: string; trek_range: string; api_version: number; version: string; author_pubkey: string }> = {}): Promise<void> {
async function seedPlugin(
id: string,
overrides: Partial<{
enabled: number;
granted_permissions: string;
permissions: string;
trek_range: string;
api_version: number;
version: string;
author_pubkey: string;
}> = {},
): Promise<void> {
await insertRow(t, Plugins, {
id,
name: id,
@@ -124,7 +157,9 @@ async function pluginRow(id: string) {
describe('Plan 3j Task 2 — R-install-gates named accept+refuse pairs (PR17/PR26/PR28)', () => {
let rt: PluginRuntimeService;
beforeAll(async () => { rt = await buildRuntime(); });
beforeAll(async () => {
rt = await buildRuntime();
});
describe('PR17 — version-range + permission-grant gate (assertActivatable)', () => {
it('INSTALL-GATE-PR17-ACCEPT: a plugin whose declared range admits this host, with no permission widening, passes the gate (activate resolves, never PluginDependencyError)', async () => {
@@ -149,7 +184,7 @@ describe('Plan 3j Task 2 — R-install-gates named accept+refuse pairs (PR17/PR2
});
});
describe('PR26 — update()\'s pre-update snapshot feeding the permission-widening diff', () => {
describe("PR26 — update()'s pre-update snapshot feeding the permission-widening diff", () => {
const fakeRegistry = (perms: string[]) =>
({
resolveVersion: vi.fn(async () => ({ version: '2.0.0' })),
@@ -165,11 +200,25 @@ describe('Plan 3j Task 2 — R-install-gates named accept+refuse pairs (PR17/PR2
const addons = await createTestAddonsService(testDb);
const userSettings = new PluginUserSettingsService(t.repo(PluginSettingsFields), t.repo(PluginUserConfig));
const rtU = new PluginRuntimeService(
audit, addons, userSettings,
t.repo(Plugins), t.repo(PluginErrorLog), t.repo(PluginScheduledTasks), t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts), t.repo(PluginSettingsFields), t.repo(PluginActions), t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata), t.repo(PluginOauthTokens), t.repo(PluginOauthState), t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit), t.repo(Settings), t.repo(NotificationChannelPreferences), new UnitOfWork(t.em),
audit,
addons,
userSettings,
t.repo(Plugins),
t.repo(PluginErrorLog),
t.repo(PluginScheduledTasks),
t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts),
t.repo(PluginSettingsFields),
t.repo(PluginActions),
t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata),
t.repo(PluginOauthTokens),
t.repo(PluginOauthState),
t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit),
t.repo(Settings),
t.repo(NotificationChannelPreferences),
new UnitOfWork(t.em),
fakeRegistry(['db:own']),
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -187,11 +236,25 @@ describe('Plan 3j Task 2 — R-install-gates named accept+refuse pairs (PR17/PR2
const addons = await createTestAddonsService(testDb);
const userSettings = new PluginUserSettingsService(t.repo(PluginSettingsFields), t.repo(PluginUserConfig));
const rtU = new PluginRuntimeService(
audit, addons, userSettings,
t.repo(Plugins), t.repo(PluginErrorLog), t.repo(PluginScheduledTasks), t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts), t.repo(PluginSettingsFields), t.repo(PluginActions), t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata), t.repo(PluginOauthTokens), t.repo(PluginOauthState), t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit), t.repo(Settings), t.repo(NotificationChannelPreferences), new UnitOfWork(t.em),
audit,
addons,
userSettings,
t.repo(Plugins),
t.repo(PluginErrorLog),
t.repo(PluginScheduledTasks),
t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts),
t.repo(PluginSettingsFields),
t.repo(PluginActions),
t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata),
t.repo(PluginOauthTokens),
t.repo(PluginOauthState),
t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit),
t.repo(Settings),
t.repo(NotificationChannelPreferences),
new UnitOfWork(t.em),
fakeRegistry(['db:own', 'db:read:trips']),
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -205,7 +268,7 @@ describe('Plan 3j Task 2 — R-install-gates named accept+refuse pairs (PR17/PR2
});
});
describe('PR28 — retrust()\'s signing-key TOFU comparison', () => {
describe("PR28 — retrust()'s signing-key TOFU comparison", () => {
const registryFor = (id: string) =>
({
assertRetrustable: vi.fn(async (_id: string, key: string) => ({ authorPublicKey: key })),
@@ -222,11 +285,25 @@ describe('Plan 3j Task 2 — R-install-gates named accept+refuse pairs (PR17/PR2
const userSettings = new PluginUserSettingsService(t.repo(PluginSettingsFields), t.repo(PluginUserConfig));
const registry = registryFor('pr28-accept');
const rtR = new PluginRuntimeService(
audit, addons, userSettings,
t.repo(Plugins), t.repo(PluginErrorLog), t.repo(PluginScheduledTasks), t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts), t.repo(PluginSettingsFields), t.repo(PluginActions), t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata), t.repo(PluginOauthTokens), t.repo(PluginOauthState), t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit), t.repo(Settings), t.repo(NotificationChannelPreferences), new UnitOfWork(t.em),
audit,
addons,
userSettings,
t.repo(Plugins),
t.repo(PluginErrorLog),
t.repo(PluginScheduledTasks),
t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts),
t.repo(PluginSettingsFields),
t.repo(PluginActions),
t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata),
t.repo(PluginOauthTokens),
t.repo(PluginOauthState),
t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit),
t.repo(Settings),
t.repo(NotificationChannelPreferences),
new UnitOfWork(t.em),
registry,
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -247,11 +324,25 @@ describe('Plan 3j Task 2 — R-install-gates named accept+refuse pairs (PR17/PR2
const registry = registryFor('pr28-refuse');
vi.mocked(registry.assertRetrustable).mockRejectedValue(new Error('nothing to re-trust'));
const rtR = new PluginRuntimeService(
audit, addons, userSettings,
t.repo(Plugins), t.repo(PluginErrorLog), t.repo(PluginScheduledTasks), t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts), t.repo(PluginSettingsFields), t.repo(PluginActions), t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata), t.repo(PluginOauthTokens), t.repo(PluginOauthState), t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit), t.repo(Settings), t.repo(NotificationChannelPreferences), new UnitOfWork(t.em),
audit,
addons,
userSettings,
t.repo(Plugins),
t.repo(PluginErrorLog),
t.repo(PluginScheduledTasks),
t.repo(PluginUserErasureQueue),
t.repo(PluginEgressHosts),
t.repo(PluginSettingsFields),
t.repo(PluginActions),
t.repo(PluginUserConfig),
t.repo(PluginEntityMetadata),
t.repo(PluginOauthTokens),
t.repo(PluginOauthState),
t.repo(PluginMetaMigrations),
t.repo(PluginCapabilityAudit),
t.repo(Settings),
t.repo(NotificationChannelPreferences),
new UnitOfWork(t.em),
registry,
);
await expect(rtR.retrust('pr28-refuse', '2.0.0', 'NEWKEY', { userId: 1 })).rejects.toThrow(/nothing to re-trust/);
@@ -270,14 +361,22 @@ describe('R-uninstall: the cascade is one transaction', () => {
await insertRow(t, PluginSettingsFields, { plugin_id: id, field_key: 'k', scope: 'instance' });
await insertRow(t, PluginScheduledTasks, { plugin_id: id, name: 'poll', due_at: 0 });
await insertRow(t, PluginErrorLog, { plugin_id: id, level: 'error', message: 'x' });
await insertRow(t, PluginEntityMetadata, { plugin_id: id, entity_type: 'place', entity_id: 1, key: 'k', value: 'v' });
await insertRow(t, PluginEntityMetadata, {
plugin_id: id,
entity_type: 'place',
entity_id: 1,
key: 'k',
value: 'v',
});
// Simulate a crash INSIDE the cascade, between plugin_scheduled_tasks (deletes
// cleanly, unconditional, no try/catch) and plugin_error_log (the next
// unconditional delete, inside the deleteData branch).
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const errorLogRepo = (rt as any).pluginErrorLog;
const spy = vi.spyOn(errorLogRepo, 'deleteAllForPlugin').mockRejectedValueOnce(new Error('simulated mid-cascade crash'));
const spy = vi
.spyOn(errorLogRepo, 'deleteAllForPlugin')
.mockRejectedValueOnce(new Error('simulated mid-cascade crash'));
const dataDir = path.join(dataRoot, id);
fs.mkdirSync(dataDir, { recursive: true });
@@ -285,20 +384,20 @@ describe('R-uninstall: the cascade is one transaction', () => {
await expect(rt.uninstall(id, true)).rejects.toThrow(/simulated mid-cascade crash/);
spy.mockRestore();
// Everything before the simulated crash point was rolled back with it: a half
// uninstall used to leave settings, tasks and metadata for a later plugin that
// reuses the id to inherit.
expect(await countRows(t, PluginSettingsFields, { plugin_id: id })).toBe(1);
expect(await countRows(t, PluginScheduledTasks, { plugin_id: id })).toBe(1);
expect(await countRows(t, PluginErrorLog, { plugin_id: id })).toBe(1);
expect(await countRows(t, PluginEntityMetadata, { plugin_id: id })).toBe(1);
expect(await countRows(t, Plugins, { id })).toBe(1);
// The data directory goes only after the rows commit.
expect(fs.existsSync(dataDir)).toBe(true);
// Everything before the simulated crash point was rolled back with it: a half
// uninstall used to leave settings, tasks and metadata for a later plugin that
// reuses the id to inherit.
expect(await countRows(t, PluginSettingsFields, { plugin_id: id })).toBe(1);
expect(await countRows(t, PluginScheduledTasks, { plugin_id: id })).toBe(1);
expect(await countRows(t, PluginErrorLog, { plugin_id: id })).toBe(1);
expect(await countRows(t, PluginEntityMetadata, { plugin_id: id })).toBe(1);
expect(await countRows(t, Plugins, { id })).toBe(1);
// The data directory goes only after the rows commit.
expect(fs.existsSync(dataDir)).toBe(true);
});
});
describe('Plan 3j Task 2 — R-uninstall\'s ONE named transaction: PR22/PR23 egress-host replace', () => {
describe("Plan 3j Task 2 — R-uninstall's ONE named transaction: PR22/PR23 egress-host replace", () => {
it('EGRESS-TX-ROLLBACK-001: a simulated failure mid-write leaves the OLD egress-host set intact, not partially cleared', async () => {
const rt = await buildRuntime();
const id = 'egress-tx';
@@ -318,12 +417,16 @@ describe('Plan 3j Task 2 — R-uninstall\'s ONE named transaction: PR22/PR23 egr
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const egressRepo = (rt as any).pluginEgressHosts;
const originalUpsert = egressRepo.upsert.bind(egressRepo);
const spy = vi.spyOn(egressRepo, 'upsert').mockImplementation(async (data: { plugin_id: string; host: string }, ...rest: unknown[]) => {
if (data.host === 'boom') throw new Error('simulated mid-write failure');
return originalUpsert(data, ...rest);
});
const spy = vi
.spyOn(egressRepo, 'upsert')
.mockImplementation(async (data: { plugin_id: string; host: string }, ...rest: unknown[]) => {
if (data.host === 'boom') throw new Error('simulated mid-write failure');
return originalUpsert(data, ...rest);
});
await expect(rt.setOperatorEgressHosts(id, ['new-a.example.com', 'boom'])).rejects.toThrow(/simulated mid-write failure/);
await expect(rt.setOperatorEgressHosts(id, ['new-a.example.com', 'boom'])).rejects.toThrow(
/simulated mid-write failure/,
);
spy.mockRestore();
// The OLD set survives untouched — the transaction rolled the DELETE AND the
@@ -334,7 +437,7 @@ describe('Plan 3j Task 2 — R-uninstall\'s ONE named transaction: PR22/PR23 egr
});
describe('Plan 3j Task 2 — PS7/PS9/PS11: the triple-duplicate SELECT collapses onto ONE PluginUserConfigRepository.findConfig call', () => {
it('PS-USERCONFIG-PARITY-001: getUserConfig, setUserConfig\'s pre-write check and getUserConfigDecrypted all read the SAME stored row identically', async () => {
it("PS-USERCONFIG-PARITY-001: getUserConfig, setUserConfig's pre-write check and getUserConfigDecrypted all read the SAME stored row identically", async () => {
const svc = buildPluginsService();
const id = 'ps-parity';
await seedPlugin(id);
@@ -366,7 +469,9 @@ describe('Plan 3j Task 2 — two racing ticks (scheduler claim/re-arm + erasure
rt = await buildRuntime(registrar);
await rt.onApplicationBootstrap();
});
afterAll(async () => { await rt.onModuleDestroy(); });
afterAll(async () => {
await rt.onModuleDestroy();
});
it('RACE-SCHED-001: two concurrent fireDueScheduled passes deliver a due one-shot task exactly once', async () => {
const pluginId = 'race-sched';
@@ -405,7 +510,12 @@ describe('Plan 3j Task 2 — two racing ticks (scheduler claim/re-arm + erasure
const pluginId = 'race-sched-recur';
await seedPlugin(pluginId, { enabled: 1 });
const everyMs = 60_000;
await insertRow(t, PluginScheduledTasks, { plugin_id: pluginId, name: 'recurring', due_at: Date.now() - 1000, every_ms: everyMs });
await insertRow(t, PluginScheduledTasks, {
plugin_id: pluginId,
name: 'recurring',
due_at: Date.now() - 1000,
every_ms: everyMs,
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const supervisor = (rt as any).supervisor;
@@ -436,7 +546,7 @@ describe('Plan 3j Task 2 — two racing ticks (scheduler claim/re-arm + erasure
}
});
it('RACE-ERASURE-001: two concurrent drains coalesce onto the SAME in-flight pass (drainUserErasures\' own promise-sharing) — one ACK, one drop', async () => {
it("RACE-ERASURE-001: two concurrent drains coalesce onto the SAME in-flight pass (drainUserErasures' own promise-sharing) — one ACK, one drop", async () => {
const pluginId = 'race-erasure';
await seedPlugin(pluginId, { enabled: 1 });
await insertRow(t, PluginUserErasureQueue, { plugin_id: pluginId, user_id: 99 });