merge: integrate upstream main with local Makelore changes

This commit is contained in:
inman
2026-08-31 10:55:48 +08:00
128 changed files with 8278 additions and 3030 deletions

View File

@@ -63,6 +63,10 @@ type SessionRefreshInput = {
const MAX_AUTH_ERROR_LENGTH = 180;
const MAX_CAPTCHA_IMAGE_BYTES = 1024 * 1024;
const MAX_PUBLIC_USERNAME_LENGTH = 256;
const MAX_PUBLIC_ID_LENGTH = 128;
const MAX_PUBLIC_AUTHORITIES = 100;
const MAX_PUBLIC_AUTHORITY_LENGTH = 128;
const PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
@@ -90,6 +94,57 @@ function readOptionalBoolean(value: unknown, fallback: boolean): boolean {
return typeof value === 'boolean' ? value : fallback;
}
function readBoundedString(value: unknown, maxLength: number): string | null {
const normalized = readOptionalTrimmedString(value);
return normalized && normalized.length <= maxLength ? normalized : null;
}
function readPublicStringId(...values: unknown[]): string | null {
for (const value of values) {
if (typeof value === 'number' && Number.isFinite(value)) return String(value);
const normalized = readBoundedString(value, MAX_PUBLIC_ID_LENGTH);
if (normalized) return normalized;
}
return null;
}
function readPublicStringOrNumberId(...values: unknown[]): string | number | null {
for (const value of values) {
if (typeof value === 'number' && Number.isFinite(value)) return value;
const normalized = readBoundedString(value, MAX_PUBLIC_ID_LENGTH);
if (normalized) return normalized;
}
return null;
}
function readPublicAuthorities(value: unknown): string[] {
if (!Array.isArray(value)) return [];
return value
.map((authority) => readBoundedString(authority, MAX_PUBLIC_AUTHORITY_LENGTH))
.filter((authority): authority is string => authority !== null)
.slice(0, MAX_PUBLIC_AUTHORITIES);
}
function projectCurrentUser(profile: Record<string, unknown>): {
username: string;
userId: string | null;
tenantId: string | number | null;
deptId: string | number | null;
authorities: string[];
} | null {
const username = readBoundedString(profile.username, MAX_PUBLIC_USERNAME_LENGTH)
?? readBoundedString(profile.user_name, MAX_PUBLIC_USERNAME_LENGTH);
if (!username) return null;
return {
username,
userId: readPublicStringId(profile.user_id, profile.userId, profile.id),
tenantId: readPublicStringOrNumberId(profile.tenant_id, profile.tenantId),
deptId: readPublicStringOrNumberId(profile.dept_id, profile.deptId),
authorities: readPublicAuthorities(profile.authorities),
};
}
function withoutRefreshToken(payload: unknown): unknown {
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return payload;
const { refresh_token: _refreshToken, ...publicPayload } = payload as Record<string, unknown>;
@@ -600,6 +655,7 @@ async function handleCurrentUser(res: ServerResponse, ctx: HostApiContext): Prom
: {};
sendJson(res, 200, {
success: true,
user: projectCurrentUser(profile),
moduleAccess: normalizeModuleAccess(profile.module_access),
});
}

View File

@@ -146,16 +146,6 @@ export async function handleCodingProjectRoutes(
});
return true;
}
if (url.pathname === '/api/coding/projects/legacy-conversation-notice/acknowledge'
&& req.method === 'POST') {
const body = await parseJsonBody<{ projectId?: string }>(req);
sendJson(res, 200, {
snapshot: publicProjectSnapshot(
await projects.acknowledgeLegacyConversationNotice(body.projectId ?? ''),
),
});
return true;
}
if (url.pathname === '/api/coding/projects/conversations' && req.method === 'GET') {
sendJson(res, 200, {
conversations: await conversations.listConversations(