Replaces every em-dash and en-dash with regular ASCII hyphens across comments, JSX strings, and dev-facing logs. Mostly cosmetic but stops the inconsistent mix that crept in over the last few months (some files used em-dashes in comments, others didn't, some used both). Bundles two small dashboard-layout tweaks that touch a couple of already-modified files: - (dashboard)/layout.tsx main padding goes from p-6 to pt-3 px-6 pb-6 so page content sits closer to the topbar. - Sidebar now receives the ports list it needs for the footer port switcher. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
1.7 KiB
TypeScript
61 lines
1.7 KiB
TypeScript
import { Client } from 'minio';
|
|
|
|
import { env } from '@/lib/env';
|
|
import { logger } from '@/lib/logger';
|
|
|
|
export const minioClient = new Client({
|
|
endPoint: env.MINIO_ENDPOINT,
|
|
port: env.MINIO_PORT,
|
|
useSSL: env.MINIO_USE_SSL,
|
|
accessKey: env.MINIO_ACCESS_KEY,
|
|
secretKey: env.MINIO_SECRET_KEY,
|
|
});
|
|
|
|
const BUCKET = env.MINIO_BUCKET;
|
|
|
|
/**
|
|
* Ensures the configured bucket exists, creating it if not.
|
|
* Should be called once at application startup.
|
|
*/
|
|
export async function ensureBucket(): Promise<void> {
|
|
try {
|
|
const exists = await minioClient.bucketExists(BUCKET);
|
|
if (!exists) {
|
|
await minioClient.makeBucket(BUCKET);
|
|
logger.info({ bucket: BUCKET }, 'MinIO bucket created');
|
|
} else {
|
|
logger.debug({ bucket: BUCKET }, 'MinIO bucket exists');
|
|
}
|
|
} catch (err) {
|
|
logger.error({ err, bucket: BUCKET }, 'Failed to ensure MinIO bucket');
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a pre-signed GET URL for an object.
|
|
*
|
|
* Default expiry is 15 minutes (900 seconds) per SECURITY-GUIDELINES.md §7.1.
|
|
*/
|
|
export async function getPresignedUrl(objectKey: string, expirySeconds = 900): Promise<string> {
|
|
return minioClient.presignedGetObject(BUCKET, objectKey, expirySeconds);
|
|
}
|
|
|
|
/**
|
|
* Constructs a storage path from typed components.
|
|
*
|
|
* Format: `{portSlug}/{entity}/{entityId}/{fileId}.{extension}`
|
|
*
|
|
* No user-supplied input should ever be used as path components - only UUIDs
|
|
* and controlled slugs (SECURITY-GUIDELINES.md §3.4, §7.1).
|
|
*/
|
|
export function buildStoragePath(
|
|
portSlug: string,
|
|
entity: string,
|
|
entityId: string,
|
|
fileId: string,
|
|
extension: string,
|
|
): string {
|
|
return `${portSlug}/${entity}/${entityId}/${fileId}.${extension}`;
|
|
}
|