feat: complete per-user integration config isolation and UI initialization
Some checks failed
Release Binaries / release (push) Has been cancelled
Some checks failed
Release Binaries / release (push) Has been cancelled
This commit is contained in:
101
packages/server/src/user-context.ts
Normal file
101
packages/server/src/user-context.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* User Context Module
|
||||
* Manages the active user context for per-user config isolation
|
||||
*/
|
||||
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
import { existsSync, mkdirSync } from "fs"
|
||||
|
||||
const CONFIG_ROOT = path.join(os.homedir(), ".config", "codenomad")
|
||||
const USERS_ROOT = path.join(CONFIG_ROOT, "users")
|
||||
|
||||
// Active user ID (set by the main process or HTTP header)
|
||||
let activeUserId: string | null = null
|
||||
|
||||
/**
|
||||
* Set the active user ID
|
||||
*/
|
||||
export function setActiveUserId(userId: string | null): void {
|
||||
activeUserId = userId
|
||||
console.log(`[UserContext] Active user set to: ${userId || "(none)"}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active user ID
|
||||
*/
|
||||
export function getActiveUserId(): string | null {
|
||||
return activeUserId
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data root for a specific user
|
||||
* Falls back to global config if no user is set
|
||||
*/
|
||||
export function getUserDataRoot(userId?: string): string {
|
||||
const effectiveUserId = userId || activeUserId
|
||||
|
||||
if (effectiveUserId) {
|
||||
const userDir = path.join(USERS_ROOT, effectiveUserId)
|
||||
return userDir
|
||||
}
|
||||
|
||||
// Prioritize environment variable if set (from Electron)
|
||||
const override = process.env.CODENOMAD_USER_DIR
|
||||
if (override && override.trim().length > 0) {
|
||||
return path.resolve(override)
|
||||
}
|
||||
|
||||
// Fallback to global config root
|
||||
return CONFIG_ROOT
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the integrations directory for the current or specified user
|
||||
*/
|
||||
export function getUserIntegrationsDir(userId?: string): string {
|
||||
const userRoot = getUserDataRoot(userId)
|
||||
const integrationsDir = path.join(userRoot, "integrations")
|
||||
|
||||
// Ensure directory exists
|
||||
if (!existsSync(integrationsDir)) {
|
||||
try {
|
||||
mkdirSync(integrationsDir, { recursive: true })
|
||||
console.log(`[UserContext] Created integrations dir: ${integrationsDir}`)
|
||||
} catch (e) {
|
||||
console.error(`[UserContext] Failed to create integrations dir:`, e)
|
||||
}
|
||||
}
|
||||
|
||||
return integrationsDir
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instances directory for the current or specified user
|
||||
*/
|
||||
export function getUserInstancesDir(userId?: string): string {
|
||||
const userRoot = getUserDataRoot(userId)
|
||||
return path.join(userRoot, "instances")
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the config file path for a specific integration
|
||||
*/
|
||||
export function getIntegrationConfigPath(integrationId: string, userId?: string): string {
|
||||
const integrationsDir = getUserIntegrationsDir(userId)
|
||||
return path.join(integrationsDir, `${integrationId}-config.json`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract user ID from request headers
|
||||
*/
|
||||
export function getUserIdFromRequest(request: { headers?: Record<string, string | string[] | undefined> }): string | null {
|
||||
const header = request.headers?.["x-user-id"]
|
||||
if (typeof header === "string" && header.length > 0) {
|
||||
return header
|
||||
}
|
||||
if (Array.isArray(header) && header.length > 0) {
|
||||
return header[0]
|
||||
}
|
||||
return activeUserId
|
||||
}
|
||||
Reference in New Issue
Block a user