mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-17 05:43:36 +00:00
refactor(db): collapse repository rollout scaffolding into single factory
Repositories are now the only data path. Replaces the 41 current-*-repository wrapper files, the DATABASE_LAYER_REPOSITORY_ROLLOUT flag/alias map and the unused database/runtime adapter with repositories/factory.ts, a plain DatabaseContext type and an in-memory TestSqliteDatabase test harness.
This commit is contained in:
@@ -34,15 +34,16 @@ import { DatabaseFileEncryption } from "../utils/database-file-encryption.js";
|
||||
import { DatabaseMigration } from "../utils/database-migration.js";
|
||||
import { UserDataExport } from "../utils/user-data-export.js";
|
||||
import { AutoSSLSetup } from "../utils/auto-ssl-setup.js";
|
||||
import { createCurrentCredentialRepository } from "./repositories/current-credential-repository.js";
|
||||
import { createCurrentDismissedAlertRepository } from "./repositories/current-dismissed-alert-repository.js";
|
||||
import { createCurrentFileManagerBookmarkRepository } from "./repositories/current-file-manager-bookmark-repository.js";
|
||||
import { createCurrentHostRepository } from "./repositories/current-host-repository.js";
|
||||
import { createCurrentSettingsRepository } from "./repositories/current-settings-repository.js";
|
||||
import { createCurrentSshCredentialUsageRepository } from "./repositories/current-ssh-credential-usage-repository.js";
|
||||
import { createCurrentUserRepository } from "./repositories/current-user-repository.js";
|
||||
import { getRepositoryRolloutStatus } from "./repositories/repository-rollout.js";
|
||||
import { withCurrentSqliteForeignKeysDisabled } from "./runtime/sqlite-foreign-key-boundary.js";
|
||||
import {
|
||||
createCurrentCredentialRepository,
|
||||
createCurrentDismissedAlertRepository,
|
||||
createCurrentFileManagerBookmarkRepository,
|
||||
createCurrentHostRepository,
|
||||
createCurrentSettingsRepository,
|
||||
createCurrentSshCredentialUsageRepository,
|
||||
createCurrentUserRepository,
|
||||
} from "./repositories/factory.js";
|
||||
import { withCurrentSqliteForeignKeysDisabled } from "./repositories/sqlite-foreign-keys.js";
|
||||
import { parseUserAgent } from "../utils/user-agent-parser.js";
|
||||
import { getProxyAgent } from "../utils/proxy-agent.js";
|
||||
import type {
|
||||
@@ -1895,7 +1896,6 @@ app.get(
|
||||
|
||||
res.json({
|
||||
migrationStatus: status,
|
||||
repositoryRollout: getRepositoryRolloutStatus(),
|
||||
files: {
|
||||
unencryptedDbSize: unencryptedSize,
|
||||
encryptedDbSize: encryptedSize,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { AlertRepository } from "./alert-repository.js";
|
||||
|
||||
describe("AlertRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("AlertRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<AlertRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
hosts,
|
||||
notificationChannels,
|
||||
} from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
type AlertRuleRecord = typeof alertRules.$inferSelect;
|
||||
type NotificationChannelRecord = typeof notificationChannels.$inferSelect;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { ApiKeyRepository } from "./api-key-repository.js";
|
||||
|
||||
describe("ApiKeyRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("ApiKeyRepository", () => {
|
||||
async function createRepository(onWrite?: () => void): Promise<{
|
||||
apiKeys: ApiKeyRepository;
|
||||
}> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { apiKeys, users } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type ApiKeyRecord = typeof apiKeys.$inferSelect;
|
||||
export type NewApiKeyRecord = typeof apiKeys.$inferInsert;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { AuditLogRepository } from "./audit-log-repository.js";
|
||||
|
||||
describe("AuditLogRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("AuditLogRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<AuditLogRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, asc, desc, eq, gte, inArray, lte, sql } from "drizzle-orm";
|
||||
import { auditLogs } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type AuditLogRecord = typeof auditLogs.$inferSelect;
|
||||
export type NewAuditLogRecord = typeof auditLogs.$inferInsert;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { C2sTunnelPresetRepository } from "./c2s-tunnel-preset-repository.js";
|
||||
|
||||
describe("C2sTunnelPresetRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("C2sTunnelPresetRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<C2sTunnelPresetRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, asc, eq, sql } from "drizzle-orm";
|
||||
import { c2sTunnelPresets } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type C2sTunnelPresetRecord = typeof c2sTunnelPresets.$inferSelect;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { CommandHistoryRepository } from "./command-history-repository.js";
|
||||
|
||||
describe("CommandHistoryRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("CommandHistoryRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<CommandHistoryRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, desc, eq, inArray, sql } from "drizzle-orm";
|
||||
import { commandHistory } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type CommandHistoryRecord = typeof commandHistory.$inferSelect;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, desc, eq, isNull, or, sql } from "drizzle-orm";
|
||||
import { sshCredentials, sshCredentialUsage } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
import { DataCrypto } from "../../utils/data-crypto.js";
|
||||
import { SystemCrypto } from "../../utils/system-crypto.js";
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { AlertRepository } from "./alert-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentAlertRepository(): AlertRepository {
|
||||
assertRepositoryRolloutDomainEnabled("alerts");
|
||||
|
||||
return new AlertRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("alert_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { ApiKeyRepository } from "./api-key-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentApiKeyRepository(): ApiKeyRepository {
|
||||
assertRepositoryRolloutDomainEnabled("api_keys");
|
||||
|
||||
return new ApiKeyRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("api_key_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { AuditLogRepository } from "./audit-log-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentAuditLogRepository(): AuditLogRepository {
|
||||
assertRepositoryRolloutDomainEnabled("audit_logs");
|
||||
|
||||
return new AuditLogRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("audit_log_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { C2sTunnelPresetRepository } from "./c2s-tunnel-preset-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentC2sTunnelPresetRepository(): C2sTunnelPresetRepository {
|
||||
assertRepositoryRolloutDomainEnabled("c2s_tunnel_presets");
|
||||
|
||||
return new C2sTunnelPresetRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("c2s_tunnel_preset_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { CommandHistoryRepository } from "./command-history-repository.js";
|
||||
|
||||
export function createCurrentCommandHistoryRepository(): CommandHistoryRepository {
|
||||
assertRepositoryRolloutDomainEnabled("command_history");
|
||||
|
||||
return new CommandHistoryRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("command_history_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { CredentialRepository } from "./credential-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentCredentialRepository(): CredentialRepository {
|
||||
assertRepositoryRolloutDomainEnabled("credentials");
|
||||
|
||||
return new CredentialRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("credential_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { DashboardServiceLinkRepository } from "./dashboard-service-link-repository.js";
|
||||
|
||||
export function createCurrentDashboardServiceLinkRepository(): DashboardServiceLinkRepository {
|
||||
assertRepositoryRolloutDomainEnabled("dashboard_service_links");
|
||||
|
||||
return new DashboardServiceLinkRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("dashboard_service_link_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { DismissedAlertRepository } from "./dismissed-alert-repository.js";
|
||||
|
||||
export function createCurrentDismissedAlertRepository(): DismissedAlertRepository {
|
||||
assertRepositoryRolloutDomainEnabled("dismissed_alerts");
|
||||
|
||||
return new DismissedAlertRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("dismissed_alert_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { FileManagerBookmarkRepository } from "./file-manager-bookmark-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentFileManagerBookmarkRepository(): FileManagerBookmarkRepository {
|
||||
assertRepositoryRolloutDomainEnabled("file_manager_bookmarks");
|
||||
|
||||
return new FileManagerBookmarkRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("file_manager_bookmarks_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { HomepageItemRepository } from "./homepage-item-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentHomepageItemRepository(): HomepageItemRepository {
|
||||
assertRepositoryRolloutDomainEnabled("homepage_items");
|
||||
|
||||
return new HomepageItemRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("homepage_item_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { HomepageLayoutRepository } from "./homepage-layout-repository.js";
|
||||
|
||||
export function createCurrentHomepageLayoutRepository(): HomepageLayoutRepository {
|
||||
assertRepositoryRolloutDomainEnabled("homepage_layouts");
|
||||
|
||||
return new HomepageLayoutRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("homepage_layout_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { HostFolderRepository } from "./host-folder-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentHostFolderRepository(): HostFolderRepository {
|
||||
assertRepositoryRolloutDomainEnabled("host_folders");
|
||||
|
||||
return new HostFolderRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_folder_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { HostHealthRepository } from "./host-health-repository.js";
|
||||
|
||||
export function createCurrentHostHealthRepository(): HostHealthRepository {
|
||||
assertRepositoryRolloutDomainEnabled("host_health");
|
||||
|
||||
return new HostHealthRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_health_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { HostMetricsHistoryRepository } from "./host-metrics-history-repository.js";
|
||||
|
||||
export function createCurrentHostMetricsHistoryRepository(): HostMetricsHistoryRepository {
|
||||
assertRepositoryRolloutDomainEnabled("host_metrics_history");
|
||||
|
||||
return new HostMetricsHistoryRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_metrics_history_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { HostMetricsPreferenceRepository } from "./host-metrics-preference-repository.js";
|
||||
|
||||
export function createCurrentHostMetricsPreferenceRepository(): HostMetricsPreferenceRepository {
|
||||
assertRepositoryRolloutDomainEnabled("host_metrics_preferences");
|
||||
|
||||
return new HostMetricsPreferenceRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook(
|
||||
"host_metrics_preference_repository_write",
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { HostRepository } from "./host-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentHostRepository(): HostRepository {
|
||||
assertRepositoryRolloutDomainEnabled("hosts");
|
||||
|
||||
return new HostRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { HostResolutionRepository } from "./host-resolution-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentHostResolutionRepository(): HostResolutionRepository {
|
||||
assertRepositoryRolloutDomainEnabled("host_resolution");
|
||||
|
||||
return new HostResolutionRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_resolution_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { NetworkTopologyRepository } from "./network-topology-repository.js";
|
||||
|
||||
export function createCurrentNetworkTopologyRepository(): NetworkTopologyRepository {
|
||||
assertRepositoryRolloutDomainEnabled("network_topology");
|
||||
|
||||
return new NetworkTopologyRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("network_topology_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { OpenTabRepository } from "./open-tab-repository.js";
|
||||
|
||||
export function createCurrentOpenTabRepository(): OpenTabRepository {
|
||||
assertRepositoryRolloutDomainEnabled("open_tabs");
|
||||
|
||||
return new OpenTabRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("open_tab_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { OpksshTokenRepository } from "./opkssh-token-repository.js";
|
||||
|
||||
export function createCurrentOpksshTokenRepository(): OpksshTokenRepository {
|
||||
assertRepositoryRolloutDomainEnabled("opkssh_tokens");
|
||||
|
||||
return new OpksshTokenRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("opkssh_token_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import { RbacAccessRepository } from "./rbac-access-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
|
||||
export function createCurrentRbacAccessRepository(): RbacAccessRepository {
|
||||
assertRepositoryRolloutDomainEnabled("rbac_access");
|
||||
|
||||
return new RbacAccessRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("rbac_access_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { RecentActivityRepository } from "./recent-activity-repository.js";
|
||||
|
||||
export function createCurrentRecentActivityRepository(): RecentActivityRepository {
|
||||
assertRepositoryRolloutDomainEnabled("recent_activity");
|
||||
|
||||
return new RecentActivityRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("recent_activity_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { DatabaseSaveTrigger } from "../../utils/database-save-trigger.js";
|
||||
import { getDb, getSqlite } from "../db/index.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
|
||||
export function createCurrentRepositoryContext(): DatabaseContext {
|
||||
return {
|
||||
dialect: "sqlite",
|
||||
drizzle: getDb(),
|
||||
sqlite: getSqlite(),
|
||||
};
|
||||
}
|
||||
|
||||
export function createCurrentRepositoryWriteHook(
|
||||
reason: string,
|
||||
): () => Promise<void> {
|
||||
return () => DatabaseSaveTrigger.forceSave(reason);
|
||||
}
|
||||
|
||||
export function getCurrentRepositorySqlite() {
|
||||
return getSqlite();
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { RoleRepository } from "./role-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentRoleRepository(): RoleRepository {
|
||||
assertRepositoryRolloutDomainEnabled("roles");
|
||||
|
||||
return new RoleRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("role_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { SessionRecordingRepository } from "./session-recording-repository.js";
|
||||
|
||||
export function createCurrentSessionRecordingRepository(): SessionRecordingRepository {
|
||||
assertRepositoryRolloutDomainEnabled("session_recordings");
|
||||
|
||||
return new SessionRecordingRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("session_recording_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { SessionRepository } from "./session-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentSessionRepository(): SessionRepository {
|
||||
assertRepositoryRolloutDomainEnabled("sessions");
|
||||
|
||||
return new SessionRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("session_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import { SettingsRepository } from "./settings-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
getCurrentRepositorySqlite,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentSettingsRepository(): SettingsRepository {
|
||||
assertRepositoryRolloutDomainEnabled("settings");
|
||||
|
||||
return new SettingsRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("settings_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function getCurrentSettingValue(key: string): string | null {
|
||||
assertRepositoryRolloutDomainEnabled("settings");
|
||||
|
||||
const row = getCurrentRepositorySqlite()
|
||||
.prepare("SELECT value FROM settings WHERE key = ?")
|
||||
.get(key) as { value?: string } | undefined;
|
||||
|
||||
return row?.value ?? null;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { SharedCredentialRepository } from "./shared-credential-repository.js";
|
||||
|
||||
export function createCurrentSharedCredentialRepository(): SharedCredentialRepository {
|
||||
assertRepositoryRolloutDomainEnabled("shared_credentials");
|
||||
|
||||
return new SharedCredentialRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("shared_credential_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { SnippetRepository } from "./snippet-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentSnippetRepository(): SnippetRepository {
|
||||
assertRepositoryRolloutDomainEnabled("snippets");
|
||||
|
||||
return new SnippetRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("snippet_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { SshCredentialUsageRepository } from "./ssh-credential-usage-repository.js";
|
||||
|
||||
export function createCurrentSshCredentialUsageRepository(): SshCredentialUsageRepository {
|
||||
assertRepositoryRolloutDomainEnabled("ssh_credential_usage");
|
||||
|
||||
return new SshCredentialUsageRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("ssh_credential_usage_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { SsoProviderRepository } from "./sso-provider-repository.js";
|
||||
|
||||
export function createCurrentSsoProviderRepository(): SsoProviderRepository {
|
||||
assertRepositoryRolloutDomainEnabled("sso_providers");
|
||||
|
||||
return new SsoProviderRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("sso_provider_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { TermixIdentityCaRepository } from "./termix-identity-ca-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentTermixIdentityCaRepository(): TermixIdentityCaRepository {
|
||||
assertRepositoryRolloutDomainEnabled("termix_identity_ca");
|
||||
|
||||
return new TermixIdentityCaRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("termix_identity_ca_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { TermixIdentityRepository } from "./termix-identity-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentTermixIdentityRepository(): TermixIdentityRepository {
|
||||
assertRepositoryRolloutDomainEnabled("termix_identity");
|
||||
|
||||
return new TermixIdentityRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("termix_identity_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { TmuxSessionTagRepository } from "./tmux-session-tag-repository.js";
|
||||
|
||||
export function createCurrentTmuxSessionTagRepository(): TmuxSessionTagRepository {
|
||||
assertRepositoryRolloutDomainEnabled("tmux_session_tags");
|
||||
|
||||
return new TmuxSessionTagRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("tmux_session_tag_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { TransferRecentRepository } from "./transfer-recent-repository.js";
|
||||
|
||||
export function createCurrentTransferRecentRepository(): TransferRecentRepository {
|
||||
assertRepositoryRolloutDomainEnabled("transfer_recent");
|
||||
|
||||
return new TransferRecentRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("transfer_recent_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { TrustedDeviceRepository } from "./trusted-device-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentTrustedDeviceRepository(): TrustedDeviceRepository {
|
||||
assertRepositoryRolloutDomainEnabled("trusted_devices");
|
||||
|
||||
return new TrustedDeviceRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("trusted_device_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import { createCurrentRepositoryContext } from "./current-repository-runtime.js";
|
||||
import { UserDataExportRepository } from "./user-data-export-repository.js";
|
||||
|
||||
export function createCurrentUserDataExportRepository(): UserDataExportRepository {
|
||||
assertRepositoryRolloutDomainEnabled("user_data_exports");
|
||||
|
||||
return new UserDataExportRepository(createCurrentRepositoryContext());
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { UserPreferenceRepository } from "./user-preference-repository.js";
|
||||
|
||||
export function createCurrentUserPreferenceRepository(): UserPreferenceRepository {
|
||||
assertRepositoryRolloutDomainEnabled("user_preferences");
|
||||
|
||||
return new UserPreferenceRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("user_preference_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { UserRepository } from "./user-repository.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
|
||||
export function createCurrentUserRepository(): UserRepository {
|
||||
assertRepositoryRolloutDomainEnabled("users");
|
||||
|
||||
return new UserRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("user_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { VaultProfileRepository } from "./vault-profile-repository.js";
|
||||
|
||||
export function createCurrentVaultProfileRepository(): VaultProfileRepository {
|
||||
assertRepositoryRolloutDomainEnabled("vault_profiles");
|
||||
|
||||
return new VaultProfileRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("vault_profile_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { assertRepositoryRolloutDomainEnabled } from "./repository-rollout.js";
|
||||
import {
|
||||
createCurrentRepositoryContext,
|
||||
createCurrentRepositoryWriteHook,
|
||||
} from "./current-repository-runtime.js";
|
||||
import { VaultTokenRepository } from "./vault-token-repository.js";
|
||||
|
||||
export function createCurrentVaultTokenRepository(): VaultTokenRepository {
|
||||
assertRepositoryRolloutDomainEnabled("vault_tokens");
|
||||
|
||||
return new VaultTokenRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("vault_token_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { DashboardServiceLinkRepository } from "./dashboard-service-link-repository.js";
|
||||
|
||||
describe("DashboardServiceLinkRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("DashboardServiceLinkRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<DashboardServiceLinkRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, asc, eq } from "drizzle-orm";
|
||||
import { dashboardServiceLinks } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type DashboardServiceLinkRecord =
|
||||
typeof dashboardServiceLinks.$inferSelect;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
|
||||
import type { Database as BetterSqliteDatabase } from "better-sqlite3";
|
||||
import type * as schema from "../db/schema.js";
|
||||
|
||||
export interface DatabaseContext {
|
||||
dialect: "sqlite";
|
||||
drizzle: BetterSQLite3Database<typeof schema>;
|
||||
sqlite?: BetterSqliteDatabase;
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { DismissedAlertRepository } from "./dismissed-alert-repository.js";
|
||||
|
||||
describe("DismissedAlertRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("DismissedAlertRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<DismissedAlertRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { dismissedAlerts } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type DismissedAlertRecord = typeof dismissedAlerts.$inferSelect;
|
||||
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
import { DatabaseSaveTrigger } from "../../utils/database-save-trigger.js";
|
||||
import { getDb, getSqlite } from "../db/index.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
import { AlertRepository } from "./alert-repository.js";
|
||||
import { ApiKeyRepository } from "./api-key-repository.js";
|
||||
import { AuditLogRepository } from "./audit-log-repository.js";
|
||||
import { C2sTunnelPresetRepository } from "./c2s-tunnel-preset-repository.js";
|
||||
import { CommandHistoryRepository } from "./command-history-repository.js";
|
||||
import { CredentialRepository } from "./credential-repository.js";
|
||||
import { DashboardServiceLinkRepository } from "./dashboard-service-link-repository.js";
|
||||
import { DismissedAlertRepository } from "./dismissed-alert-repository.js";
|
||||
import { FileManagerBookmarkRepository } from "./file-manager-bookmark-repository.js";
|
||||
import { HomepageItemRepository } from "./homepage-item-repository.js";
|
||||
import { HomepageLayoutRepository } from "./homepage-layout-repository.js";
|
||||
import { HostFolderRepository } from "./host-folder-repository.js";
|
||||
import { HostHealthRepository } from "./host-health-repository.js";
|
||||
import { HostMetricsHistoryRepository } from "./host-metrics-history-repository.js";
|
||||
import { HostMetricsPreferenceRepository } from "./host-metrics-preference-repository.js";
|
||||
import { HostRepository } from "./host-repository.js";
|
||||
import { HostResolutionRepository } from "./host-resolution-repository.js";
|
||||
import { NetworkTopologyRepository } from "./network-topology-repository.js";
|
||||
import { OpenTabRepository } from "./open-tab-repository.js";
|
||||
import { OpksshTokenRepository } from "./opkssh-token-repository.js";
|
||||
import { RbacAccessRepository } from "./rbac-access-repository.js";
|
||||
import { RecentActivityRepository } from "./recent-activity-repository.js";
|
||||
import { RoleRepository } from "./role-repository.js";
|
||||
import { SessionRecordingRepository } from "./session-recording-repository.js";
|
||||
import { SessionRepository } from "./session-repository.js";
|
||||
import { SettingsRepository } from "./settings-repository.js";
|
||||
import { SharedCredentialRepository } from "./shared-credential-repository.js";
|
||||
import { SnippetRepository } from "./snippet-repository.js";
|
||||
import { SshCredentialUsageRepository } from "./ssh-credential-usage-repository.js";
|
||||
import { SsoProviderRepository } from "./sso-provider-repository.js";
|
||||
import { TermixIdentityCaRepository } from "./termix-identity-ca-repository.js";
|
||||
import { TermixIdentityRepository } from "./termix-identity-repository.js";
|
||||
import { TmuxSessionTagRepository } from "./tmux-session-tag-repository.js";
|
||||
import { TransferRecentRepository } from "./transfer-recent-repository.js";
|
||||
import { TrustedDeviceRepository } from "./trusted-device-repository.js";
|
||||
import { UserDataExportRepository } from "./user-data-export-repository.js";
|
||||
import { UserPreferenceRepository } from "./user-preference-repository.js";
|
||||
import { UserRepository } from "./user-repository.js";
|
||||
import { VaultProfileRepository } from "./vault-profile-repository.js";
|
||||
import { VaultTokenRepository } from "./vault-token-repository.js";
|
||||
|
||||
export function createCurrentRepositoryContext(): DatabaseContext {
|
||||
return {
|
||||
dialect: "sqlite",
|
||||
drizzle: getDb(),
|
||||
sqlite: getSqlite(),
|
||||
};
|
||||
}
|
||||
|
||||
export function createCurrentRepositoryWriteHook(
|
||||
reason: string,
|
||||
): () => Promise<void> {
|
||||
return () => DatabaseSaveTrigger.forceSave(reason);
|
||||
}
|
||||
|
||||
export function getCurrentRepositorySqlite() {
|
||||
return getSqlite();
|
||||
}
|
||||
|
||||
export function getCurrentSettingValue(key: string): string | null {
|
||||
const row = getCurrentRepositorySqlite()
|
||||
.prepare("SELECT value FROM settings WHERE key = ?")
|
||||
.get(key) as { value?: string } | undefined;
|
||||
|
||||
return row?.value ?? null;
|
||||
}
|
||||
|
||||
export function createCurrentAlertRepository(): AlertRepository {
|
||||
return new AlertRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("alert_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentApiKeyRepository(): ApiKeyRepository {
|
||||
return new ApiKeyRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("api_key_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentAuditLogRepository(): AuditLogRepository {
|
||||
return new AuditLogRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("audit_log_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentC2sTunnelPresetRepository(): C2sTunnelPresetRepository {
|
||||
return new C2sTunnelPresetRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("c2s_tunnel_preset_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentCommandHistoryRepository(): CommandHistoryRepository {
|
||||
return new CommandHistoryRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("command_history_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentCredentialRepository(): CredentialRepository {
|
||||
return new CredentialRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("credential_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentDashboardServiceLinkRepository(): DashboardServiceLinkRepository {
|
||||
return new DashboardServiceLinkRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("dashboard_service_link_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentDismissedAlertRepository(): DismissedAlertRepository {
|
||||
return new DismissedAlertRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("dismissed_alert_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentFileManagerBookmarkRepository(): FileManagerBookmarkRepository {
|
||||
return new FileManagerBookmarkRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("file_manager_bookmarks_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentHomepageItemRepository(): HomepageItemRepository {
|
||||
return new HomepageItemRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("homepage_item_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentHomepageLayoutRepository(): HomepageLayoutRepository {
|
||||
return new HomepageLayoutRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("homepage_layout_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentHostFolderRepository(): HostFolderRepository {
|
||||
return new HostFolderRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_folder_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentHostHealthRepository(): HostHealthRepository {
|
||||
return new HostHealthRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_health_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentHostMetricsHistoryRepository(): HostMetricsHistoryRepository {
|
||||
return new HostMetricsHistoryRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_metrics_history_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentHostMetricsPreferenceRepository(): HostMetricsPreferenceRepository {
|
||||
return new HostMetricsPreferenceRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook(
|
||||
"host_metrics_preference_repository_write",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentHostRepository(): HostRepository {
|
||||
return new HostRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentHostResolutionRepository(): HostResolutionRepository {
|
||||
return new HostResolutionRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("host_resolution_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentNetworkTopologyRepository(): NetworkTopologyRepository {
|
||||
return new NetworkTopologyRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("network_topology_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentOpenTabRepository(): OpenTabRepository {
|
||||
return new OpenTabRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("open_tab_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentOpksshTokenRepository(): OpksshTokenRepository {
|
||||
return new OpksshTokenRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("opkssh_token_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentRbacAccessRepository(): RbacAccessRepository {
|
||||
return new RbacAccessRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("rbac_access_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentRecentActivityRepository(): RecentActivityRepository {
|
||||
return new RecentActivityRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("recent_activity_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentRoleRepository(): RoleRepository {
|
||||
return new RoleRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("role_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentSessionRecordingRepository(): SessionRecordingRepository {
|
||||
return new SessionRecordingRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("session_recording_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentSessionRepository(): SessionRepository {
|
||||
return new SessionRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("session_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentSettingsRepository(): SettingsRepository {
|
||||
return new SettingsRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("settings_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentSharedCredentialRepository(): SharedCredentialRepository {
|
||||
return new SharedCredentialRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("shared_credential_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentSnippetRepository(): SnippetRepository {
|
||||
return new SnippetRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("snippet_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentSshCredentialUsageRepository(): SshCredentialUsageRepository {
|
||||
return new SshCredentialUsageRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("ssh_credential_usage_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentSsoProviderRepository(): SsoProviderRepository {
|
||||
return new SsoProviderRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("sso_provider_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentTermixIdentityCaRepository(): TermixIdentityCaRepository {
|
||||
return new TermixIdentityCaRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("termix_identity_ca_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentTermixIdentityRepository(): TermixIdentityRepository {
|
||||
return new TermixIdentityRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("termix_identity_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentTmuxSessionTagRepository(): TmuxSessionTagRepository {
|
||||
return new TmuxSessionTagRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("tmux_session_tag_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentTransferRecentRepository(): TransferRecentRepository {
|
||||
return new TransferRecentRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("transfer_recent_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentTrustedDeviceRepository(): TrustedDeviceRepository {
|
||||
return new TrustedDeviceRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("trusted_device_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentUserDataExportRepository(): UserDataExportRepository {
|
||||
return new UserDataExportRepository(createCurrentRepositoryContext());
|
||||
}
|
||||
|
||||
export function createCurrentUserPreferenceRepository(): UserPreferenceRepository {
|
||||
return new UserPreferenceRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("user_preference_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentUserRepository(): UserRepository {
|
||||
return new UserRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("user_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentVaultProfileRepository(): VaultProfileRepository {
|
||||
return new VaultProfileRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("vault_profile_repository_write"),
|
||||
);
|
||||
}
|
||||
|
||||
export function createCurrentVaultTokenRepository(): VaultTokenRepository {
|
||||
return new VaultTokenRepository(
|
||||
createCurrentRepositoryContext(),
|
||||
createCurrentRepositoryWriteHook("vault_token_repository_write"),
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { FileManagerBookmarkRepository } from "./file-manager-bookmark-repository.js";
|
||||
|
||||
describe("FileManagerBookmarkRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("FileManagerBookmarkRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<FileManagerBookmarkRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
fileManagerRecent,
|
||||
fileManagerShortcuts,
|
||||
} from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type FileManagerRecentRecord = typeof fileManagerRecent.$inferSelect;
|
||||
export type FileManagerPinnedRecord = typeof fileManagerPinned.$inferSelect;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { HomepageItemRepository } from "./homepage-item-repository.js";
|
||||
|
||||
describe("HomepageItemRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("HomepageItemRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<HomepageItemRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, asc, eq } from "drizzle-orm";
|
||||
import { homepageItems } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type HomepageItemRecord = typeof homepageItems.$inferSelect;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { HomepageLayoutRepository } from "./homepage-layout-repository.js";
|
||||
|
||||
describe("HomepageLayoutRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("HomepageLayoutRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<HomepageLayoutRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { homepageLayouts } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type HomepageLayoutRecord = typeof homepageLayouts.$inferSelect;
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { CredentialRepository } from "./credential-repository.js";
|
||||
import { HostRepository } from "./host-repository.js";
|
||||
import { DataCrypto } from "../../utils/data-crypto.js";
|
||||
import { SystemCrypto } from "../../utils/system-crypto.js";
|
||||
|
||||
describe("HostRepository and CredentialRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
vi.restoreAllMocks();
|
||||
@@ -23,14 +23,10 @@ describe("HostRepository and CredentialRepository", () => {
|
||||
credentials: CredentialRepository;
|
||||
hosts: HostRepository;
|
||||
sqlite: NonNullable<
|
||||
Awaited<ReturnType<SqliteDatabaseAdapter["connect"]>>["sqlite"]
|
||||
Awaited<ReturnType<TestSqliteDatabase["connect"]>>["sqlite"]
|
||||
>;
|
||||
}> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { HostFolderRepository } from "./host-folder-repository.js";
|
||||
|
||||
describe("HostFolderRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -17,14 +17,10 @@ describe("HostFolderRepository", () => {
|
||||
): Promise<{
|
||||
repository: HostFolderRepository;
|
||||
sqlite: NonNullable<
|
||||
Awaited<ReturnType<SqliteDatabaseAdapter["connect"]>>["sqlite"]
|
||||
Awaited<ReturnType<TestSqliteDatabase["connect"]>>["sqlite"]
|
||||
>;
|
||||
}> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { and, eq, like, or, sql } from "drizzle-orm";
|
||||
import type { SQLiteColumn } from "drizzle-orm/sqlite-core";
|
||||
import { hosts, sshCredentials, sshFolders } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type HostFolderRecord = typeof sshFolders.$inferSelect;
|
||||
export type HostFolderHostRecord = typeof hosts.$inferSelect;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { HostHealthRepository } from "./host-health-repository.js";
|
||||
|
||||
describe("HostHealthRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("HostHealthRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<HostHealthRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, desc, eq } from "drizzle-orm";
|
||||
import { hostHealthChecks, hostHealthHistory } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type HostHealthCheckRecord = typeof hostHealthChecks.$inferSelect;
|
||||
export type HostHealthHistoryRecord = typeof hostHealthHistory.$inferSelect;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { HostMetricsHistoryRepository } from "./host-metrics-history-repository.js";
|
||||
|
||||
describe("HostMetricsHistoryRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("HostMetricsHistoryRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<HostMetricsHistoryRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE hosts (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, asc, eq, gte, lte } from "drizzle-orm";
|
||||
import { hostMetricsHistory } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type HostMetricsHistoryRecord = typeof hostMetricsHistory.$inferSelect;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { HostMetricsPreferenceRepository } from "./host-metrics-preference-repository.js";
|
||||
|
||||
describe("HostMetricsPreferenceRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("HostMetricsPreferenceRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<HostMetricsPreferenceRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { hostMetricsPreferences, hosts } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type HostMetricsPreferenceRecord =
|
||||
typeof hostMetricsPreferences.$inferSelect;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq, inArray } from "drizzle-orm";
|
||||
import { hostAccess, hosts } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
import { DataCrypto } from "../../utils/data-crypto.js";
|
||||
|
||||
export type HostRecord = typeof hosts.$inferSelect;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { DataCrypto } from "../../utils/data-crypto.js";
|
||||
import { HostResolutionRepository } from "./host-resolution-repository.js";
|
||||
|
||||
@@ -11,7 +11,7 @@ vi.mock("../../utils/data-crypto.js", () => ({
|
||||
}));
|
||||
|
||||
describe("HostResolutionRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
vi.mocked(DataCrypto.getUserDataKey).mockReset();
|
||||
@@ -25,11 +25,7 @@ describe("HostResolutionRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<HostResolutionRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq, inArray, isNotNull } from "drizzle-orm";
|
||||
import { hostAccess, hosts, sshCredentials } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
import { DataCrypto } from "../../utils/data-crypto.js";
|
||||
|
||||
export type HostResolutionHostRecord = typeof hosts.$inferSelect;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { NetworkTopologyRepository } from "./network-topology-repository.js";
|
||||
|
||||
describe("NetworkTopologyRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("NetworkTopologyRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<NetworkTopologyRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { networkTopology } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type NetworkTopologyRecord = typeof networkTopology.$inferSelect;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { OpenTabRepository } from "./open-tab-repository.js";
|
||||
|
||||
describe("OpenTabRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("OpenTabRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<OpenTabRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq, gt } from "drizzle-orm";
|
||||
import { userOpenTabs } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type OpenTabRecord = typeof userOpenTabs.$inferSelect;
|
||||
export type NewOpenTabRecord = typeof userOpenTabs.$inferInsert;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { OpksshTokenRepository } from "./opkssh-token-repository.js";
|
||||
|
||||
describe("OpksshTokenRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("OpksshTokenRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<OpksshTokenRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { opksshTokens } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type OpksshTokenRecord = typeof opksshTokens.$inferSelect;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { RbacAccessRepository } from "./rbac-access-repository.js";
|
||||
|
||||
describe("RbacAccessRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
const activeAccessTime = "2026-06-26T12:00:00.000Z";
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -16,11 +16,7 @@ describe("RbacAccessRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<RbacAccessRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
snippets,
|
||||
users,
|
||||
} from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type RbacAccessTargetType = "user" | "role";
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { RecentActivityRepository } from "./recent-activity-repository.js";
|
||||
|
||||
describe("RecentActivityRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -17,14 +17,10 @@ describe("RecentActivityRepository", () => {
|
||||
): Promise<{
|
||||
repository: RecentActivityRepository;
|
||||
sqlite: NonNullable<
|
||||
Awaited<ReturnType<SqliteDatabaseAdapter["connect"]>>["sqlite"]
|
||||
Awaited<ReturnType<TestSqliteDatabase["connect"]>>["sqlite"]
|
||||
>;
|
||||
}> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { desc, eq, inArray } from "drizzle-orm";
|
||||
import { recentActivity } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type RecentActivityRecord = typeof recentActivity.$inferSelect;
|
||||
export type NewRecentActivityRecord = typeof recentActivity.$inferInsert;
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
getRepositoryRolloutStatus,
|
||||
getRepositoryRolloutWarnings,
|
||||
isRepositoryRolloutDomainEnabled,
|
||||
parseRepositoryRolloutConfig,
|
||||
REPOSITORY_ROLLOUT_ENV,
|
||||
} from "./repository-rollout.js";
|
||||
|
||||
describe("parseRepositoryRolloutConfig", () => {
|
||||
it("defaults to the current migrated repository slice", () => {
|
||||
const config = parseRepositoryRolloutConfig({});
|
||||
|
||||
expect(config).toEqual({
|
||||
mode: "all",
|
||||
enabledDomains: [
|
||||
"settings",
|
||||
"users",
|
||||
"sessions",
|
||||
"api_keys",
|
||||
"trusted_devices",
|
||||
"credentials",
|
||||
"termix_identity",
|
||||
"termix_identity_ca",
|
||||
"hosts",
|
||||
"snippets",
|
||||
"roles",
|
||||
"rbac_access",
|
||||
"shared_credentials",
|
||||
"sso_providers",
|
||||
"audit_logs",
|
||||
"user_preferences",
|
||||
"open_tabs",
|
||||
"dismissed_alerts",
|
||||
"homepage_layouts",
|
||||
"homepage_items",
|
||||
"network_topology",
|
||||
"dashboard_service_links",
|
||||
"session_recordings",
|
||||
"command_history",
|
||||
"recent_activity",
|
||||
"ssh_credential_usage",
|
||||
"transfer_recent",
|
||||
"file_manager_bookmarks",
|
||||
"c2s_tunnel_presets",
|
||||
"tmux_session_tags",
|
||||
"opkssh_tokens",
|
||||
"vault_tokens",
|
||||
"vault_profiles",
|
||||
"host_metrics_preferences",
|
||||
"host_health",
|
||||
"host_metrics_history",
|
||||
"alerts",
|
||||
"user_data_exports",
|
||||
"host_folders",
|
||||
"host_resolution",
|
||||
],
|
||||
explicit: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("allows explicitly disabling all migrated repository domains", () => {
|
||||
const config = parseRepositoryRolloutConfig({
|
||||
[REPOSITORY_ROLLOUT_ENV]: "off",
|
||||
});
|
||||
|
||||
expect(config).toEqual({
|
||||
mode: "none",
|
||||
enabledDomains: [],
|
||||
explicit: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("accepts a partial domain allowlist with aliases", () => {
|
||||
const config = parseRepositoryRolloutConfig({
|
||||
[REPOSITORY_ROLLOUT_ENV]:
|
||||
"settings,user,api-key,credential,termix-id,termix-ca,host,dismissed,alerts,layout,items,topology,dashboard-link,recordings,history,activity,usage,transfer,user-data-export,ssh-folder,host-resolver,shared-credentials,bookmarks,c2s,tmux,opkssh,vault-token,vault-profile,metrics-preferences,host-health,metrics-history",
|
||||
});
|
||||
|
||||
expect(config).toEqual({
|
||||
mode: "partial",
|
||||
enabledDomains: [
|
||||
"settings",
|
||||
"users",
|
||||
"api_keys",
|
||||
"credentials",
|
||||
"termix_identity",
|
||||
"termix_identity_ca",
|
||||
"hosts",
|
||||
"dismissed_alerts",
|
||||
"alerts",
|
||||
"homepage_layouts",
|
||||
"homepage_items",
|
||||
"network_topology",
|
||||
"dashboard_service_links",
|
||||
"session_recordings",
|
||||
"command_history",
|
||||
"recent_activity",
|
||||
"ssh_credential_usage",
|
||||
"transfer_recent",
|
||||
"user_data_exports",
|
||||
"host_folders",
|
||||
"host_resolution",
|
||||
"shared_credentials",
|
||||
"file_manager_bookmarks",
|
||||
"c2s_tunnel_presets",
|
||||
"tmux_session_tags",
|
||||
"opkssh_tokens",
|
||||
"vault_tokens",
|
||||
"vault_profiles",
|
||||
"host_metrics_preferences",
|
||||
"host_health",
|
||||
"host_metrics_history",
|
||||
],
|
||||
explicit: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("deduplicates allowlisted domains", () => {
|
||||
const config = parseRepositoryRolloutConfig({
|
||||
[REPOSITORY_ROLLOUT_ENV]: "users,user,users",
|
||||
});
|
||||
|
||||
expect(config.enabledDomains).toEqual(["users"]);
|
||||
});
|
||||
|
||||
it("rejects unknown domains", () => {
|
||||
expect(() =>
|
||||
parseRepositoryRolloutConfig({
|
||||
[REPOSITORY_ROLLOUT_ENV]: "settings,unknown-domain",
|
||||
}),
|
||||
).toThrow("Unsupported DATABASE_LAYER_REPOSITORY_ROLLOUT domain");
|
||||
});
|
||||
|
||||
it("checks whether an individual domain is enabled", () => {
|
||||
const env = { [REPOSITORY_ROLLOUT_ENV]: "sessions" };
|
||||
|
||||
expect(isRepositoryRolloutDomainEnabled("sessions", env)).toBe(true);
|
||||
expect(isRepositoryRolloutDomainEnabled("users", env)).toBe(false);
|
||||
});
|
||||
|
||||
it("builds a status payload for admin visibility", () => {
|
||||
const status = getRepositoryRolloutStatus({
|
||||
[REPOSITORY_ROLLOUT_ENV]: "settings,sessions",
|
||||
});
|
||||
|
||||
expect(status).toEqual({
|
||||
mode: "partial",
|
||||
enabledDomains: ["settings", "sessions"],
|
||||
explicit: true,
|
||||
envKey: REPOSITORY_ROLLOUT_ENV,
|
||||
supportedDomains: [
|
||||
"settings",
|
||||
"users",
|
||||
"sessions",
|
||||
"api_keys",
|
||||
"trusted_devices",
|
||||
"credentials",
|
||||
"termix_identity",
|
||||
"termix_identity_ca",
|
||||
"hosts",
|
||||
"snippets",
|
||||
"roles",
|
||||
"rbac_access",
|
||||
"shared_credentials",
|
||||
"sso_providers",
|
||||
"audit_logs",
|
||||
"user_preferences",
|
||||
"open_tabs",
|
||||
"dismissed_alerts",
|
||||
"homepage_layouts",
|
||||
"homepage_items",
|
||||
"network_topology",
|
||||
"dashboard_service_links",
|
||||
"session_recordings",
|
||||
"command_history",
|
||||
"recent_activity",
|
||||
"ssh_credential_usage",
|
||||
"transfer_recent",
|
||||
"file_manager_bookmarks",
|
||||
"c2s_tunnel_presets",
|
||||
"tmux_session_tags",
|
||||
"opkssh_tokens",
|
||||
"vault_tokens",
|
||||
"vault_profiles",
|
||||
"host_metrics_preferences",
|
||||
"host_health",
|
||||
"host_metrics_history",
|
||||
"alerts",
|
||||
"user_data_exports",
|
||||
"host_folders",
|
||||
"host_resolution",
|
||||
],
|
||||
warnings: [
|
||||
"Partial repository rollout enabled for domains: settings, sessions.",
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("warns when gray rollout is implicit", () => {
|
||||
const warnings = getRepositoryRolloutWarnings(
|
||||
parseRepositoryRolloutConfig({}),
|
||||
);
|
||||
|
||||
expect(warnings).toEqual([
|
||||
"DATABASE_LAYER_REPOSITORY_ROLLOUT is not explicitly set; gray targets should set it so rollout state is visible in deployment config.",
|
||||
]);
|
||||
});
|
||||
|
||||
it("warns when migrated repository domains are disabled", () => {
|
||||
const warnings = getRepositoryRolloutWarnings(
|
||||
parseRepositoryRolloutConfig({ [REPOSITORY_ROLLOUT_ENV]: "off" }),
|
||||
);
|
||||
|
||||
expect(warnings).toEqual([
|
||||
"All migrated repository domains are disabled; migrated auth/settings/session paths will fail closed.",
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -1,381 +0,0 @@
|
||||
import { databaseLogger } from "../../utils/logger.js";
|
||||
|
||||
export const REPOSITORY_ROLLOUT_ENV = "DATABASE_LAYER_REPOSITORY_ROLLOUT";
|
||||
|
||||
export const REPOSITORY_ROLLOUT_DOMAINS = [
|
||||
"settings",
|
||||
"users",
|
||||
"sessions",
|
||||
"api_keys",
|
||||
"trusted_devices",
|
||||
"credentials",
|
||||
"termix_identity",
|
||||
"termix_identity_ca",
|
||||
"hosts",
|
||||
"snippets",
|
||||
"roles",
|
||||
"rbac_access",
|
||||
"shared_credentials",
|
||||
"sso_providers",
|
||||
"audit_logs",
|
||||
"user_preferences",
|
||||
"open_tabs",
|
||||
"dismissed_alerts",
|
||||
"homepage_layouts",
|
||||
"homepage_items",
|
||||
"network_topology",
|
||||
"dashboard_service_links",
|
||||
"session_recordings",
|
||||
"command_history",
|
||||
"recent_activity",
|
||||
"ssh_credential_usage",
|
||||
"transfer_recent",
|
||||
"file_manager_bookmarks",
|
||||
"c2s_tunnel_presets",
|
||||
"tmux_session_tags",
|
||||
"opkssh_tokens",
|
||||
"vault_tokens",
|
||||
"vault_profiles",
|
||||
"host_metrics_preferences",
|
||||
"host_health",
|
||||
"host_metrics_history",
|
||||
"alerts",
|
||||
"user_data_exports",
|
||||
"host_folders",
|
||||
"host_resolution",
|
||||
] as const;
|
||||
|
||||
export type RepositoryRolloutDomain =
|
||||
(typeof REPOSITORY_ROLLOUT_DOMAINS)[number];
|
||||
|
||||
export interface RepositoryRolloutConfig {
|
||||
mode: "all" | "none" | "partial";
|
||||
enabledDomains: RepositoryRolloutDomain[];
|
||||
explicit: boolean;
|
||||
}
|
||||
|
||||
export interface RepositoryRolloutStatus extends RepositoryRolloutConfig {
|
||||
envKey: typeof REPOSITORY_ROLLOUT_ENV;
|
||||
supportedDomains: RepositoryRolloutDomain[];
|
||||
warnings: string[];
|
||||
}
|
||||
|
||||
type EnvLike = Record<string, string | undefined>;
|
||||
|
||||
const DOMAIN_ALIASES: Record<string, RepositoryRolloutDomain> = {
|
||||
api: "api_keys",
|
||||
api_key: "api_keys",
|
||||
api_keys: "api_keys",
|
||||
apikey: "api_keys",
|
||||
apikeys: "api_keys",
|
||||
audit: "audit_logs",
|
||||
audit_log: "audit_logs",
|
||||
audit_logs: "audit_logs",
|
||||
auditlog: "audit_logs",
|
||||
auditlogs: "audit_logs",
|
||||
alert: "alerts",
|
||||
alerts: "alerts",
|
||||
dashboard_link: "dashboard_service_links",
|
||||
dashboard_links: "dashboard_service_links",
|
||||
dashboard_service_link: "dashboard_service_links",
|
||||
dashboard_service_links: "dashboard_service_links",
|
||||
dashboardlink: "dashboard_service_links",
|
||||
dashboardlinks: "dashboard_service_links",
|
||||
command_history: "command_history",
|
||||
commandhistory: "command_history",
|
||||
credential: "credentials",
|
||||
credentials: "credentials",
|
||||
ca: "termix_identity_ca",
|
||||
history: "command_history",
|
||||
ssh_credential: "credentials",
|
||||
ssh_credentials: "credentials",
|
||||
sshcredential: "credentials",
|
||||
sshcredentials: "credentials",
|
||||
terminal_history: "command_history",
|
||||
termix_ca: "termix_identity_ca",
|
||||
termix_id: "termix_identity",
|
||||
termix_id_ca: "termix_identity_ca",
|
||||
termix_identity: "termix_identity",
|
||||
termix_identity_ca: "termix_identity_ca",
|
||||
termix_identity_cas: "termix_identity_ca",
|
||||
termix_identity_key: "termix_identity",
|
||||
termix_identity_keys: "termix_identity",
|
||||
termix_identity_public_keys: "termix_identity",
|
||||
termix_identities: "termix_identity",
|
||||
termixidca: "termix_identity_ca",
|
||||
termixidentity: "termix_identity",
|
||||
dismissed_alert: "dismissed_alerts",
|
||||
dismissed_alerts: "dismissed_alerts",
|
||||
dismissedalert: "dismissed_alerts",
|
||||
dismissedalerts: "dismissed_alerts",
|
||||
dismissed: "dismissed_alerts",
|
||||
homepage_layout: "homepage_layouts",
|
||||
homepage_layouts: "homepage_layouts",
|
||||
homepagelayout: "homepage_layouts",
|
||||
homepagelayouts: "homepage_layouts",
|
||||
layout: "homepage_layouts",
|
||||
layouts: "homepage_layouts",
|
||||
homepage_item: "homepage_items",
|
||||
homepage_items: "homepage_items",
|
||||
homepageitem: "homepage_items",
|
||||
homepageitems: "homepage_items",
|
||||
host_folder: "host_folders",
|
||||
host_folders: "host_folders",
|
||||
hostfolder: "host_folders",
|
||||
hostfolders: "host_folders",
|
||||
host: "hosts",
|
||||
hosts: "hosts",
|
||||
snippet: "snippets",
|
||||
snippets: "snippets",
|
||||
host_resolution: "host_resolution",
|
||||
host_resolver: "host_resolution",
|
||||
hostresolution: "host_resolution",
|
||||
hostresolver: "host_resolution",
|
||||
resolver: "host_resolution",
|
||||
ssh_folder: "host_folders",
|
||||
ssh_folders: "host_folders",
|
||||
sshfolder: "host_folders",
|
||||
sshfolders: "host_folders",
|
||||
item: "homepage_items",
|
||||
items: "homepage_items",
|
||||
recording: "session_recordings",
|
||||
recordings: "session_recordings",
|
||||
session_recording: "session_recordings",
|
||||
session_recordings: "session_recordings",
|
||||
sessionrecording: "session_recordings",
|
||||
sessionrecordings: "session_recordings",
|
||||
network_topologies: "network_topology",
|
||||
network_topology: "network_topology",
|
||||
networktopologies: "network_topology",
|
||||
networktopology: "network_topology",
|
||||
topology: "network_topology",
|
||||
activity: "recent_activity",
|
||||
recent_activities: "recent_activity",
|
||||
recent_activity: "recent_activity",
|
||||
recentactivity: "recent_activity",
|
||||
credential_usage: "ssh_credential_usage",
|
||||
ssh_credential_usage: "ssh_credential_usage",
|
||||
sshcredentialusage: "ssh_credential_usage",
|
||||
usage: "ssh_credential_usage",
|
||||
transfer: "transfer_recent",
|
||||
transfer_recent: "transfer_recent",
|
||||
transferrecent: "transfer_recent",
|
||||
export: "user_data_exports",
|
||||
exports: "user_data_exports",
|
||||
user_data_export: "user_data_exports",
|
||||
user_data_exports: "user_data_exports",
|
||||
userdataexport: "user_data_exports",
|
||||
userdataexports: "user_data_exports",
|
||||
bookmark: "file_manager_bookmarks",
|
||||
bookmarks: "file_manager_bookmarks",
|
||||
file_bookmarks: "file_manager_bookmarks",
|
||||
file_manager_bookmark: "file_manager_bookmarks",
|
||||
file_manager_bookmarks: "file_manager_bookmarks",
|
||||
filemanagerbookmarks: "file_manager_bookmarks",
|
||||
c2s: "c2s_tunnel_presets",
|
||||
c2s_preset: "c2s_tunnel_presets",
|
||||
c2s_presets: "c2s_tunnel_presets",
|
||||
c2s_tunnel_preset: "c2s_tunnel_presets",
|
||||
c2s_tunnel_presets: "c2s_tunnel_presets",
|
||||
c2stunnelpresets: "c2s_tunnel_presets",
|
||||
tmux: "tmux_session_tags",
|
||||
tmux_tag: "tmux_session_tags",
|
||||
tmux_tags: "tmux_session_tags",
|
||||
tmux_session_tag: "tmux_session_tags",
|
||||
tmux_session_tags: "tmux_session_tags",
|
||||
tmuxsessiontags: "tmux_session_tags",
|
||||
opkssh: "opkssh_tokens",
|
||||
opkssh_token: "opkssh_tokens",
|
||||
opkssh_tokens: "opkssh_tokens",
|
||||
opksshtoken: "opkssh_tokens",
|
||||
opksshtokens: "opkssh_tokens",
|
||||
vault_token: "vault_tokens",
|
||||
vault_tokens: "vault_tokens",
|
||||
vaulttoken: "vault_tokens",
|
||||
vaulttokens: "vault_tokens",
|
||||
vault_profile: "vault_profiles",
|
||||
vault_profiles: "vault_profiles",
|
||||
vaultprofile: "vault_profiles",
|
||||
vaultprofiles: "vault_profiles",
|
||||
host_metrics_preference: "host_metrics_preferences",
|
||||
host_metrics_preferences: "host_metrics_preferences",
|
||||
hostmetricspreference: "host_metrics_preferences",
|
||||
hostmetricspreferences: "host_metrics_preferences",
|
||||
metrics_preferences: "host_metrics_preferences",
|
||||
health: "host_health",
|
||||
host_health: "host_health",
|
||||
host_health_checks: "host_health",
|
||||
host_health_history: "host_health",
|
||||
hosthealth: "host_health",
|
||||
host_metrics_history: "host_metrics_history",
|
||||
hostmetricshistory: "host_metrics_history",
|
||||
metrics_history: "host_metrics_history",
|
||||
open_tab: "open_tabs",
|
||||
open_tabs: "open_tabs",
|
||||
opentab: "open_tabs",
|
||||
opentabs: "open_tabs",
|
||||
setting: "settings",
|
||||
settings: "settings",
|
||||
session: "sessions",
|
||||
sessions: "sessions",
|
||||
trusted_device: "trusted_devices",
|
||||
trusted_devices: "trusted_devices",
|
||||
trusteddevice: "trusted_devices",
|
||||
trusteddevices: "trusted_devices",
|
||||
preference: "user_preferences",
|
||||
preferences: "user_preferences",
|
||||
user_preference: "user_preferences",
|
||||
user_preferences: "user_preferences",
|
||||
userpreference: "user_preferences",
|
||||
userpreferences: "user_preferences",
|
||||
role: "roles",
|
||||
roles: "roles",
|
||||
rbac: "rbac_access",
|
||||
rbac_access: "rbac_access",
|
||||
rbacaccess: "rbac_access",
|
||||
shared_credential: "shared_credentials",
|
||||
shared_credentials: "shared_credentials",
|
||||
sharedcredential: "shared_credentials",
|
||||
sharedcredentials: "shared_credentials",
|
||||
sso: "sso_providers",
|
||||
sso_provider: "sso_providers",
|
||||
sso_providers: "sso_providers",
|
||||
ssoprovider: "sso_providers",
|
||||
ssoproviders: "sso_providers",
|
||||
user: "users",
|
||||
users: "users",
|
||||
};
|
||||
|
||||
const DISABLED_VALUES = new Set(["0", "false", "none", "off", "disabled"]);
|
||||
const ENABLED_VALUES = new Set(["1", "true", "all", "on", "enabled"]);
|
||||
|
||||
function parseDomainList(value: string): RepositoryRolloutDomain[] {
|
||||
const domains = value
|
||||
.split(",")
|
||||
.map((part) => part.trim().toLowerCase().replaceAll("-", "_"))
|
||||
.filter(Boolean)
|
||||
.map((part) => {
|
||||
const domain = DOMAIN_ALIASES[part];
|
||||
if (!domain) {
|
||||
throw new Error(
|
||||
`Unsupported ${REPOSITORY_ROLLOUT_ENV} domain '${part}'. Expected one of: ${REPOSITORY_ROLLOUT_DOMAINS.join(", ")}.`,
|
||||
);
|
||||
}
|
||||
return domain;
|
||||
});
|
||||
|
||||
return Array.from(new Set(domains));
|
||||
}
|
||||
|
||||
export function parseRepositoryRolloutConfig(
|
||||
env: EnvLike = process.env,
|
||||
): RepositoryRolloutConfig {
|
||||
const raw = env[REPOSITORY_ROLLOUT_ENV];
|
||||
const normalized = raw?.trim().toLowerCase();
|
||||
|
||||
if (!normalized) {
|
||||
return {
|
||||
mode: "all",
|
||||
enabledDomains: [...REPOSITORY_ROLLOUT_DOMAINS],
|
||||
explicit: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (ENABLED_VALUES.has(normalized)) {
|
||||
return {
|
||||
mode: "all",
|
||||
enabledDomains: [...REPOSITORY_ROLLOUT_DOMAINS],
|
||||
explicit: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (DISABLED_VALUES.has(normalized)) {
|
||||
return { mode: "none", enabledDomains: [], explicit: true };
|
||||
}
|
||||
|
||||
const enabledDomains = parseDomainList(normalized);
|
||||
return {
|
||||
mode:
|
||||
enabledDomains.length === REPOSITORY_ROLLOUT_DOMAINS.length
|
||||
? "all"
|
||||
: "partial",
|
||||
enabledDomains,
|
||||
explicit: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function isRepositoryRolloutDomainEnabled(
|
||||
domain: RepositoryRolloutDomain,
|
||||
env: EnvLike = process.env,
|
||||
): boolean {
|
||||
return parseRepositoryRolloutConfig(env).enabledDomains.includes(domain);
|
||||
}
|
||||
|
||||
export function getRepositoryRolloutStatus(
|
||||
env: EnvLike = process.env,
|
||||
): RepositoryRolloutStatus {
|
||||
const config = parseRepositoryRolloutConfig(env);
|
||||
return {
|
||||
...config,
|
||||
envKey: REPOSITORY_ROLLOUT_ENV,
|
||||
supportedDomains: [...REPOSITORY_ROLLOUT_DOMAINS],
|
||||
warnings: getRepositoryRolloutWarnings(config),
|
||||
};
|
||||
}
|
||||
|
||||
export function getRepositoryRolloutWarnings(
|
||||
config: RepositoryRolloutConfig,
|
||||
): string[] {
|
||||
const warnings: string[] = [];
|
||||
|
||||
if (!config.explicit) {
|
||||
warnings.push(
|
||||
`${REPOSITORY_ROLLOUT_ENV} is not explicitly set; gray targets should set it so rollout state is visible in deployment config.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (config.mode === "none") {
|
||||
warnings.push(
|
||||
"All migrated repository domains are disabled; migrated auth/settings/session paths will fail closed.",
|
||||
);
|
||||
}
|
||||
|
||||
if (config.mode === "partial") {
|
||||
warnings.push(
|
||||
`Partial repository rollout enabled for domains: ${config.enabledDomains.join(", ")}.`,
|
||||
);
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
export function assertRepositoryRolloutDomainEnabled(
|
||||
domain: RepositoryRolloutDomain,
|
||||
): void {
|
||||
if (isRepositoryRolloutDomainEnabled(domain)) return;
|
||||
|
||||
throw new Error(
|
||||
`Repository domain '${domain}' is disabled by ${REPOSITORY_ROLLOUT_ENV}.`,
|
||||
);
|
||||
}
|
||||
|
||||
export function logRepositoryRolloutConfig(env: EnvLike = process.env): void {
|
||||
const config = getRepositoryRolloutStatus(env);
|
||||
databaseLogger.info("Database repository rollout configuration loaded", {
|
||||
operation: "repository_rollout_config",
|
||||
mode: config.mode,
|
||||
enabledDomains: config.enabledDomains,
|
||||
explicit: config.explicit,
|
||||
envKey: REPOSITORY_ROLLOUT_ENV,
|
||||
});
|
||||
|
||||
for (const warning of config.warnings) {
|
||||
databaseLogger.warn(warning, {
|
||||
operation: "repository_rollout_warning",
|
||||
mode: config.mode,
|
||||
enabledDomains: config.enabledDomains,
|
||||
explicit: config.explicit,
|
||||
envKey: REPOSITORY_ROLLOUT_ENV,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { RoleRepository } from "./role-repository.js";
|
||||
|
||||
describe("RoleRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("RoleRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<RoleRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq, inArray } from "drizzle-orm";
|
||||
import { hostAccess, roles, userRoles } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type RoleRecord = typeof roles.$inferSelect;
|
||||
export type NewRoleRecord = typeof roles.$inferInsert;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { SessionRecordingRepository } from "./session-recording-repository.js";
|
||||
|
||||
describe("SessionRecordingRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,11 +15,7 @@ describe("SessionRecordingRepository", () => {
|
||||
async function createRepository(
|
||||
onWrite?: () => void | Promise<void>,
|
||||
): Promise<SessionRecordingRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE users (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, desc, eq, inArray, lt } from "drizzle-orm";
|
||||
import { hosts, sessionRecordings } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type SessionRecordingRecord = typeof sessionRecordings.$inferSelect;
|
||||
|
||||
@@ -74,9 +74,7 @@ export class SessionRecordingRepository {
|
||||
return rows[0] ?? null;
|
||||
}
|
||||
|
||||
async findPathById(
|
||||
id: number,
|
||||
): Promise<
|
||||
async findPathById(id: number): Promise<
|
||||
| (SessionRecordingPathRecord & {
|
||||
userId: string;
|
||||
format?: string | null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq, lte, ne } from "drizzle-orm";
|
||||
import { sessions } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type SessionRecord = typeof sessions.$inferSelect;
|
||||
export type NewSessionRecord = typeof sessions.$inferInsert;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { SettingsRepository } from "./settings-repository.js";
|
||||
|
||||
describe("SettingsRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -13,11 +13,7 @@ describe("SettingsRepository", () => {
|
||||
});
|
||||
|
||||
async function createRepository(): Promise<SettingsRepository> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE settings (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { eq, like } from "drizzle-orm";
|
||||
import { settings } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export class SettingsRepository {
|
||||
constructor(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { SharedCredentialRepository } from "./shared-credential-repository.js";
|
||||
|
||||
describe("SharedCredentialRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -17,14 +17,10 @@ describe("SharedCredentialRepository", () => {
|
||||
): Promise<{
|
||||
repository: SharedCredentialRepository;
|
||||
sqlite: NonNullable<
|
||||
Awaited<ReturnType<SqliteDatabaseAdapter["connect"]>>["sqlite"]
|
||||
Awaited<ReturnType<TestSqliteDatabase["connect"]>>["sqlite"]
|
||||
>;
|
||||
}> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE shared_credentials (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { sharedCredentials } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type SharedCredentialRecord = typeof sharedCredentials.$inferSelect;
|
||||
export type NewSharedCredentialRecord = typeof sharedCredentials.$inferInsert;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { SqliteDatabaseAdapter } from "../runtime/sqlite-adapter.js";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { SnippetRepository } from "./snippet-repository.js";
|
||||
|
||||
describe("SnippetRepository", () => {
|
||||
let adapter: SqliteDatabaseAdapter | null = null;
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
@@ -15,14 +15,10 @@ describe("SnippetRepository", () => {
|
||||
async function createRepository(onWrite?: () => void): Promise<{
|
||||
repository: SnippetRepository;
|
||||
sqlite: NonNullable<
|
||||
Awaited<ReturnType<SqliteDatabaseAdapter["connect"]>>["sqlite"]
|
||||
Awaited<ReturnType<TestSqliteDatabase["connect"]>>["sqlite"]
|
||||
>;
|
||||
}> {
|
||||
adapter = new SqliteDatabaseAdapter({
|
||||
dialect: "sqlite",
|
||||
url: ":memory:",
|
||||
sqlitePath: ":memory:",
|
||||
});
|
||||
adapter = new TestSqliteDatabase();
|
||||
const context = await adapter.connect();
|
||||
context.sqlite?.exec(`
|
||||
CREATE TABLE snippets (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, asc, eq, sql } from "drizzle-orm";
|
||||
import { snippetFolders, snippets } from "../db/schema.js";
|
||||
import type { DatabaseContext } from "../runtime/adapter.js";
|
||||
import type { DatabaseContext } from "./database-context.js";
|
||||
|
||||
export type SnippetRecord = typeof snippets.$inferSelect;
|
||||
export type SnippetFolderRecord = typeof snippetFolders.$inferSelect;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user