routes refuse at the route, and a new home is empty
Three things, from a member sitting on /music with no music capability on a server with no music sidecar: an empty library, and 403s in the console. PERMISSIONS AT THE ROUTE. `canVisit` filtered the dock and nothing else, so the tile was hidden and the route was wide open — typing the path, following an old link or restoring a tab rendered the screen anyway. RouteGate now wraps every screen in one place, inside the error boundary. It does not redirect. Sending someone to `/` erases what they asked for and reads as a bug: they clicked Music and landed on Home. It says why instead, and the URL stays put so a reload after installing the thing just works. And it says which of the two reasons applies, because they need different screens and send the reader to different places. `not-installed` is a fact about the SERVER — the owner gets a link to the app store. `not-granted` is a fact about the ACCOUNT, and only the owner can change it. Presenting either as the other sends you looking in the wrong place. ROUTES FOLLOW THE SIDECAR. Free, once the above exists: `deniedRoutes` already covers "held but its sidecar is not installed", so an uninstalled feature has no tile AND no screen. The dock, the Permissions list and the routes now agree because they read one answer. NO MORE SEEDING. Downloads/Documents/Music/Videos/Pictures are gone from both places that made them — the member's provisioning and, older and worse, `/ls`, which created folders in somebody's home as a side effect of LOOKING at it. A listing that invents its own contents is a listing you cannot trust, and the platform has no standing to choose a person's folder layout. A new home is empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import { createRouter } from '@@/create-router';
|
||||
import { resolve, dirname, join, sep, parse as parsePath } from 'node:path';
|
||||
import { readdir, stat, mkdir, rm, rename, readFile, cp } from 'node:fs/promises';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { getOwnerHomeDir, DATA_PATH, HOME_SEED_DIRS } from '@@/data-path';
|
||||
import { getOwnerHomeDir, DATA_PATH } from '@@/data-path';
|
||||
import { resolveHomeDir } from '@@/user-home';
|
||||
import * as errors from '@@/custom-errors';
|
||||
import { readTtsConfig } from '@@/api/server-settings/tts';
|
||||
@@ -19,7 +19,6 @@ async function getUserTtsVoice(userId: number): Promise<string | null> {
|
||||
return null;
|
||||
}
|
||||
|
||||
const DEFAULT_HOME_DIRS = HOME_SEED_DIRS;
|
||||
const OLD_CACHE_DIRS = ['ocr', 'tts', 'transcriptions', 'audio', 'video'];
|
||||
|
||||
async function cleanOldCacheDirs(userDataDir: string) {
|
||||
@@ -29,12 +28,9 @@ async function cleanOldCacheDirs(userDataDir: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function seedHomeDir(homeDir: string) {
|
||||
for (const dir of DEFAULT_HOME_DIRS) {
|
||||
const target = join(homeDir, dir);
|
||||
if (!existsSync(target)) await mkdir(target, { recursive: true });
|
||||
}
|
||||
}
|
||||
// `seedHomeDir` used to be here, creating Downloads/Documents/Music/Videos/Pictures on the first listing of
|
||||
// any home. Removed 2026-08-11: it invented folders in somebody's home directory as a side effect of LOOKING
|
||||
// at it, which is not a listing's business and not a layout the platform has any standing to choose.
|
||||
|
||||
export const router = createRouter();
|
||||
|
||||
@@ -172,18 +168,16 @@ router.get('/ls', async (ctx) => {
|
||||
const relPath = (ctx.req.query('path') || '/').replace(/^\/+/, '');
|
||||
const absPath = resolveUserPath(rootDir, relPath);
|
||||
|
||||
// Auto-create dir if missing (only for user home root).
|
||||
// Create the home root itself if it is missing, and nothing else. A listing that invents its own contents
|
||||
// is a listing you cannot trust — the folder set it used to seed is gone.
|
||||
//
|
||||
// Non-fatal since per-user Linux accounts: a member's home is 700 and owned by THEM, so the platform
|
||||
// cannot write into it and every one of these calls raises EPERM. Their folders are seeded at account
|
||||
// creation, as them. Letting a convenience take down `/ls` would mean the file browser failing to list a
|
||||
// directory it can read perfectly well.
|
||||
// Non-fatal: a member's home is theirs, so this can raise EPERM, and `readdir` below is the real test of
|
||||
// whether the directory can be used.
|
||||
if (!ctx.req.query('root') || ctx.req.query('root') === 'home') {
|
||||
try {
|
||||
await seedHomeDir(rootDir);
|
||||
await mkdir(absPath, { recursive: true });
|
||||
} catch {
|
||||
// Nothing to report: either it exists, or it is not ours to create. `readdir` below is the real test.
|
||||
// Either it exists, or it is not ours to create.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user