Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions apps/desktop/src/store/tinybase/persister/human/load.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { HumanStorage } from "@hypr/store";

import { cleanupOrphanFiles, loadAllEntities } from "../markdown-utils";
import { loadAllEntities } from "../markdown-utils";
import { frontmatterToHuman } from "./utils";

const LABEL = "HumanPersister";
Expand All @@ -11,10 +11,3 @@ export async function loadAllHumans(
): Promise<Record<string, HumanStorage>> {
return loadAllEntities(dataDir, DIR_NAME, LABEL, frontmatterToHuman);
}

export async function cleanupOrphanHumanFiles(
dataDir: string,
validHumanIds: Set<string>,
): Promise<void> {
return cleanupOrphanFiles(dataDir, DIR_NAME, validHumanIds, LABEL);
}
12 changes: 9 additions & 3 deletions apps/desktop/src/store/tinybase/persister/human/persister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import type {
OptionalSchemas,
} from "tinybase/with-schemas";

import { commands as folderCommands } from "@hypr/plugin-folder";

import { createSessionDirPersister, getDataDir } from "../utils";
import { collectHumanWriteOps, type HumanCollectorResult } from "./collect";
import { cleanupOrphanHumanFiles, loadAllHumans } from "./load";
import { loadAllHumans } from "./load";
import { migrateHumansJsonIfNeeded } from "./migrate";

export function createHumanPersister<Schemas extends OptionalSchemas>(
Expand All @@ -24,9 +26,13 @@ export function createHumanPersister<Schemas extends OptionalSchemas>(
}
return [{ humans }, {}] as unknown as Content<Schemas>;
},
postSave: async (dataDir, result) => {
postSave: async (_dataDir, result) => {
const { validHumanIds } = result as HumanCollectorResult;
await cleanupOrphanHumanFiles(dataDir, validHumanIds);
await folderCommands.cleanupOrphanFiles(
"humans",
"md",
Array.from(validHumanIds),
);
},
});
}
42 changes: 0 additions & 42 deletions apps/desktop/src/store/tinybase/persister/markdown-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,48 +91,6 @@ export async function loadAllEntities<T>(
return result;
}

export async function cleanupOrphanFiles(
dataDir: string,
dirName: string,
validIds: Set<string>,
label: string,
): Promise<void> {
const paths = createEntityPaths(dirName);
const entityDir = paths.getDir(dataDir);

let entries: { name: string; isDirectory: boolean }[];
try {
entries = await readDir(entityDir);
} catch (error) {
if (isFileNotFoundError(error)) {
return;
}
throw error;
}

for (const entry of entries) {
if (entry.isDirectory) continue;
if (!entry.name.endsWith(".md")) continue;

const entityId = entry.name.replace(/\.md$/, "");
if (!isUUID(entityId)) continue;

if (!validIds.has(entityId)) {
try {
const filePath = paths.getFilePath(dataDir, entityId);
await remove(filePath);
} catch (error) {
if (!isFileNotFoundError(error)) {
console.error(
`[${label}] Failed to remove orphan file ${entry.name}:`,
error,
);
}
}
}
}
}

export async function migrateJsonToMarkdown<T>(
dataDir: string,
jsonFilename: string,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OrganizationStorage } from "@hypr/store";

import { cleanupOrphanFiles, loadAllEntities } from "../markdown-utils";
import { loadAllEntities } from "../markdown-utils";
import { frontmatterToOrganization } from "./utils";

const LABEL = "OrganizationPersister";
Expand All @@ -11,10 +11,3 @@ export async function loadAllOrganizations(
): Promise<Record<string, OrganizationStorage>> {
return loadAllEntities(dataDir, DIR_NAME, LABEL, frontmatterToOrganization);
}

export async function cleanupOrphanOrganizationFiles(
dataDir: string,
validOrgIds: Set<string>,
): Promise<void> {
return cleanupOrphanFiles(dataDir, DIR_NAME, validOrgIds, LABEL);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import type {
OptionalSchemas,
} from "tinybase/with-schemas";

import { commands as folderCommands } from "@hypr/plugin-folder";

import { createSessionDirPersister, getDataDir } from "../utils";
import {
collectOrganizationWriteOps,
type OrganizationCollectorResult,
} from "./collect";
import { cleanupOrphanOrganizationFiles, loadAllOrganizations } from "./load";
import { loadAllOrganizations } from "./load";
import { migrateOrganizationsJsonIfNeeded } from "./migrate";

export function createOrganizationPersister<Schemas extends OptionalSchemas>(
Expand All @@ -27,9 +29,13 @@ export function createOrganizationPersister<Schemas extends OptionalSchemas>(
}
return [{ organizations }, {}] as unknown as Content<Schemas>;
},
postSave: async (dataDir, result) => {
postSave: async (_dataDir, result) => {
const { validOrgIds } = result as OrganizationCollectorResult;
await cleanupOrphanOrganizationFiles(dataDir, validOrgIds);
await folderCommands.cleanupOrphanFiles(
"organizations",
"md",
Array.from(validOrgIds),
);
},
});
}
9 changes: 1 addition & 8 deletions apps/desktop/src/store/tinybase/persister/prompts/load.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { PromptStorage } from "@hypr/store";

import { cleanupOrphanFiles, loadAllEntities } from "../markdown-utils";
import { loadAllEntities } from "../markdown-utils";
import { frontmatterToPrompt } from "./utils";

const LABEL = "PromptPersister";
Expand All @@ -11,10 +11,3 @@ export async function loadAllPrompts(
): Promise<Record<string, PromptStorage>> {
return loadAllEntities(dataDir, DIR_NAME, LABEL, frontmatterToPrompt);
}

export async function cleanupOrphanPromptFiles(
dataDir: string,
validPromptIds: Set<string>,
): Promise<void> {
return cleanupOrphanFiles(dataDir, DIR_NAME, validPromptIds, LABEL);
}
12 changes: 9 additions & 3 deletions apps/desktop/src/store/tinybase/persister/prompts/persister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import type {
OptionalSchemas,
} from "tinybase/with-schemas";

import { commands as folderCommands } from "@hypr/plugin-folder";

import { createSessionDirPersister, getDataDir } from "../utils";
import { collectPromptWriteOps, type PromptCollectorResult } from "./collect";
import { cleanupOrphanPromptFiles, loadAllPrompts } from "./load";
import { loadAllPrompts } from "./load";
import { migratePromptsJsonIfNeeded } from "./migrate";

export function createPromptPersister<Schemas extends OptionalSchemas>(
Expand All @@ -24,9 +26,13 @@ export function createPromptPersister<Schemas extends OptionalSchemas>(
}
return [{ prompts }, {}] as unknown as Content<Schemas>;
},
postSave: async (dataDir, result) => {
postSave: async (_dataDir, result) => {
const { validPromptIds } = result as PromptCollectorResult;
await cleanupOrphanPromptFiles(dataDir, validPromptIds);
await folderCommands.cleanupOrphanFiles(
"prompts",
"md",
Array.from(validPromptIds),
);
},
});
}
66 changes: 1 addition & 65 deletions apps/desktop/src/store/tinybase/persister/session/load.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { sep } from "@tauri-apps/api/path";
import { exists, readDir, readTextFile, remove } from "@tauri-apps/plugin-fs";
import { exists, readDir, readTextFile } from "@tauri-apps/plugin-fs";

import type {
MappingSessionParticipantStorage,
Expand All @@ -8,7 +8,6 @@ import type {
Tag,
} from "@hypr/store";

import { isFileNotFoundError, isUUID } from "../utils";
import type { SessionMetaJson } from "./collect";

export type LoadedData = {
Expand Down Expand Up @@ -114,66 +113,3 @@ export async function loadAllSessionMeta(dataDir: string): Promise<LoadedData> {

return result;
}

async function collectSessionDirsRecursively(
sessionsDir: string,
currentPath: string,
result: Array<{ path: string; name: string }>,
): Promise<void> {
const s = sep();
const fullPath = currentPath
? [sessionsDir, currentPath].join(s)
: sessionsDir;

let entries: { name: string; isDirectory: boolean }[];
try {
entries = await readDir(fullPath);
} catch {
return;
}

for (const entry of entries) {
if (!entry.isDirectory) continue;

const entryPath = currentPath
? [currentPath, entry.name].join(s)
: entry.name;
const metaPath = [sessionsDir, entryPath, "_meta.json"].join(s);
const hasMetaJson = await exists(metaPath);

if (hasMetaJson) {
result.push({ path: [sessionsDir, entryPath].join(s), name: entry.name });
} else {
await collectSessionDirsRecursively(sessionsDir, entryPath, result);
}
}
}

export async function cleanupOrphanSessionDirs(
dataDir: string,
validSessionIds: Set<string>,
): Promise<void> {
const sessionsDir = [dataDir, "sessions"].join(sep());
const existingDirs: Array<{ path: string; name: string }> = [];

try {
await collectSessionDirsRecursively(sessionsDir, "", existingDirs);
} catch {
return;
}

for (const dir of existingDirs) {
if (isUUID(dir.name) && !validSessionIds.has(dir.name)) {
try {
await remove(dir.path, { recursive: true });
} catch (e) {
if (!isFileNotFoundError(e)) {
console.error(
`[SessionPersister] Failed to remove orphan dir ${dir.path}:`,
e,
);
}
}
}
}
}
12 changes: 9 additions & 3 deletions apps/desktop/src/store/tinybase/persister/session/persister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import type {
OptionalSchemas,
} from "tinybase/with-schemas";

import { commands as folderCommands } from "@hypr/plugin-folder";

import { createSessionDirPersister, getDataDir } from "../utils";
import { collectSessionWriteOps, type SessionCollectorResult } from "./collect";
import { cleanupOrphanSessionDirs, loadAllSessionMeta } from "./load";
import { loadAllSessionMeta } from "./load";

export function createSessionPersister<Schemas extends OptionalSchemas>(
store: MergeableStore<Schemas>,
Expand All @@ -33,9 +35,13 @@ export function createSessionPersister<Schemas extends OptionalSchemas>(
return undefined;
}
},
postSave: async (dataDir, result) => {
postSave: async (_dataDir, result) => {
const { validSessionIds } = result as SessionCollectorResult;
await cleanupOrphanSessionDirs(dataDir, validSessionIds);
await folderCommands.cleanupOrphanDirs(
"sessions",
"_meta.json",
Array.from(validSessionIds),
);
},
});
}
2 changes: 2 additions & 0 deletions plugins/folder/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const COMMANDS: &[&str] = &[
"create_folder",
"rename_folder",
"delete_folder",
"cleanup_orphan_files",
"cleanup_orphan_dirs",
];

fn main() {
Expand Down
16 changes: 16 additions & 0 deletions plugins/folder/js/bindings.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ async deleteFolder(folderPath: string) : Promise<Result<null, string>> {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async cleanupOrphanFiles(subdir: string, extension: string, validIds: string[]) : Promise<Result<number, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:folder|cleanup_orphan_files", { subdir, extension, validIds }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async cleanupOrphanDirs(subdir: string, markerFile: string, validIds: string[]) : Promise<Result<number, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:folder|cleanup_orphan_dirs", { subdir, markerFile, validIds }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Automatically generated - DO NOT EDIT!

"$schema" = "../../schemas/schema.json"

[[permission]]
identifier = "allow-cleanup-orphan-dirs"
description = "Enables the cleanup_orphan_dirs command without any pre-configured scope."
commands.allow = ["cleanup_orphan_dirs"]

[[permission]]
identifier = "deny-cleanup-orphan-dirs"
description = "Denies the cleanup_orphan_dirs command without any pre-configured scope."
commands.deny = ["cleanup_orphan_dirs"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Automatically generated - DO NOT EDIT!

"$schema" = "../../schemas/schema.json"

[[permission]]
identifier = "allow-cleanup-orphan-files"
description = "Enables the cleanup_orphan_files command without any pre-configured scope."
commands.allow = ["cleanup_orphan_files"]

[[permission]]
identifier = "deny-cleanup-orphan-files"
description = "Denies the cleanup_orphan_files command without any pre-configured scope."
commands.deny = ["cleanup_orphan_files"]
Loading
Loading