fix(mindspace): sync nested OA files and count workspace assets
Recursive workspace sync now imports files in oa/private/public subfolders, references workspace paths without duplicating storage, and includes workspace-sourced assets in category itemCount. Refresh counts when leaving a category view. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import path from 'node:path';
|
||||
import { resolveUserWorkspaceRoot, resolveZoneFilePath } from './user-space.mjs';
|
||||
|
||||
export const WORKSPACE_STORAGE_PREFIX = 'workspace://';
|
||||
|
||||
export function buildWorkspaceStorageKey(userId, categoryCode, relativeFilename) {
|
||||
const category = String(categoryCode ?? '').trim();
|
||||
const relativePath = String(relativeFilename ?? '').replace(/\\/g, '/').replace(/^\/+/, '');
|
||||
if (!userId || !category || !relativePath) {
|
||||
throw new Error('invalid workspace storage key parts');
|
||||
}
|
||||
if (relativePath.split('/').some((part) => part === '..' || part === '.')) {
|
||||
throw new Error('invalid workspace relative path');
|
||||
}
|
||||
return `${WORKSPACE_STORAGE_PREFIX}${userId}/${category}/${relativePath}`;
|
||||
}
|
||||
|
||||
export function isWorkspaceStorageKey(storageKey) {
|
||||
return String(storageKey ?? '').startsWith(WORKSPACE_STORAGE_PREFIX);
|
||||
}
|
||||
|
||||
export function resolveWorkspaceStoragePath(h5Root, storageKey) {
|
||||
if (!h5Root || !isWorkspaceStorageKey(storageKey)) return null;
|
||||
const rest = storageKey.slice(WORKSPACE_STORAGE_PREFIX.length);
|
||||
const slash = rest.indexOf('/');
|
||||
if (slash <= 0) return null;
|
||||
const userId = rest.slice(0, slash);
|
||||
const remainder = rest.slice(slash + 1);
|
||||
const slash2 = remainder.indexOf('/');
|
||||
if (slash2 <= 0) return null;
|
||||
const categoryCode = remainder.slice(0, slash2);
|
||||
const relativeFilename = remainder.slice(slash2 + 1);
|
||||
if (!relativeFilename) return null;
|
||||
const workspaceRoot = resolveUserWorkspaceRoot(h5Root, { id: userId });
|
||||
const resolved = path.resolve(resolveZoneFilePath(workspaceRoot, categoryCode, relativeFilename));
|
||||
const zoneRoot = path.resolve(resolveZoneFilePath(workspaceRoot, categoryCode, ''));
|
||||
if (resolved !== zoneRoot && !resolved.startsWith(`${zoneRoot}${path.sep}`)) {
|
||||
return null;
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
Reference in New Issue
Block a user