style: auto-format codebase with Prettier

Applied formatting to 1487+ files using pnpm format:write
  - TypeScript/JavaScript files
  - Svelte components
  - Astro pages
  - JSON configs
  - Markdown docs

  13 files still need manual review (Astro JSX comments)
This commit is contained in:
Wuesteon 2025-11-27 18:33:16 +01:00
parent 0241f5554c
commit d36b321d9d
3952 changed files with 661498 additions and 739751 deletions

View file

@ -1,24 +1,24 @@
{
"name": "@manacore/shared-config",
"version": "1.0.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./env": "./src/env.ts",
"./api": "./src/api.ts",
"./features": "./src/features.ts"
},
"scripts": {
"type-check": "tsc --noEmit"
},
"dependencies": {
"zod": "^3.24.0"
},
"devDependencies": {
"@types/node": "^24.10.1",
"typescript": "^5.7.3"
}
"name": "@manacore/shared-config",
"version": "1.0.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./env": "./src/env.ts",
"./api": "./src/api.ts",
"./features": "./src/features.ts"
},
"scripts": {
"type-check": "tsc --noEmit"
},
"dependencies": {
"zod": "^3.24.0"
},
"devDependencies": {
"@types/node": "^24.10.1",
"typescript": "^5.7.3"
}
}

View file

@ -6,202 +6,202 @@
* API configuration
*/
export interface ApiConfig {
/** Base URL for the API */
baseUrl: string;
/** API version prefix (e.g., 'v1') */
version?: string;
/** Default timeout in milliseconds */
timeout?: number;
/** Default headers */
headers?: Record<string, string>;
/** Base URL for the API */
baseUrl: string;
/** API version prefix (e.g., 'v1') */
version?: string;
/** Default timeout in milliseconds */
timeout?: number;
/** Default headers */
headers?: Record<string, string>;
}
/**
* Create API endpoint URL builder
*/
export function createApiBuilder(config: ApiConfig) {
const { baseUrl, version } = config;
const { baseUrl, version } = config;
// Remove trailing slash from base URL
const base = baseUrl.replace(/\/$/, '');
// Remove trailing slash from base URL
const base = baseUrl.replace(/\/$/, '');
// Build base path with optional version
const basePath = version ? `${base}/${version}` : base;
// Build base path with optional version
const basePath = version ? `${base}/${version}` : base;
return {
/**
* Build endpoint URL from path segments
*/
endpoint(...segments: (string | number)[]): string {
const path = segments
.map(String)
.map(s => s.replace(/^\/+|\/+$/g, '')) // Remove leading/trailing slashes
.filter(Boolean)
.join('/');
return {
/**
* Build endpoint URL from path segments
*/
endpoint(...segments: (string | number)[]): string {
const path = segments
.map(String)
.map((s) => s.replace(/^\/+|\/+$/g, '')) // Remove leading/trailing slashes
.filter(Boolean)
.join('/');
return `${basePath}/${path}`;
},
return `${basePath}/${path}`;
},
/**
* Build endpoint URL with query parameters
*/
endpointWithQuery(
path: string | string[],
params?: Record<string, string | number | boolean | undefined>
): string {
const segments = Array.isArray(path) ? path : [path];
const url = this.endpoint(...segments);
/**
* Build endpoint URL with query parameters
*/
endpointWithQuery(
path: string | string[],
params?: Record<string, string | number | boolean | undefined>
): string {
const segments = Array.isArray(path) ? path : [path];
const url = this.endpoint(...segments);
if (!params) {
return url;
}
if (!params) {
return url;
}
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value !== undefined) {
searchParams.append(key, String(value));
}
}
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value !== undefined) {
searchParams.append(key, String(value));
}
}
const queryString = searchParams.toString();
return queryString ? `${url}?${queryString}` : url;
},
const queryString = searchParams.toString();
return queryString ? `${url}?${queryString}` : url;
},
/**
* Get the base URL
*/
getBaseUrl(): string {
return basePath;
},
/**
* Get the base URL
*/
getBaseUrl(): string {
return basePath;
},
/**
* Get the config
*/
getConfig(): ApiConfig {
return config;
},
};
/**
* Get the config
*/
getConfig(): ApiConfig {
return config;
},
};
}
/**
* Build URL with query parameters
*/
export function buildUrl(
baseUrl: string,
path: string,
params?: Record<string, string | number | boolean | undefined>
baseUrl: string,
path: string,
params?: Record<string, string | number | boolean | undefined>
): string {
// Ensure single slash between base and path
const base = baseUrl.replace(/\/$/, '');
const cleanPath = path.replace(/^\//, '');
const url = `${base}/${cleanPath}`;
// Ensure single slash between base and path
const base = baseUrl.replace(/\/$/, '');
const cleanPath = path.replace(/^\//, '');
const url = `${base}/${cleanPath}`;
if (!params) {
return url;
}
if (!params) {
return url;
}
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value !== undefined) {
searchParams.append(key, String(value));
}
}
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value !== undefined) {
searchParams.append(key, String(value));
}
}
const queryString = searchParams.toString();
return queryString ? `${url}?${queryString}` : url;
const queryString = searchParams.toString();
return queryString ? `${url}?${queryString}` : url;
}
/**
* Parse URL and extract components
*/
export function parseUrl(url: string): {
protocol: string;
host: string;
port: string;
pathname: string;
search: string;
params: Record<string, string>;
protocol: string;
host: string;
port: string;
pathname: string;
search: string;
params: Record<string, string>;
} {
const urlObj = new URL(url);
const urlObj = new URL(url);
const params: Record<string, string> = {};
urlObj.searchParams.forEach((value, key) => {
params[key] = value;
});
const params: Record<string, string> = {};
urlObj.searchParams.forEach((value, key) => {
params[key] = value;
});
return {
protocol: urlObj.protocol.replace(':', ''),
host: urlObj.hostname,
port: urlObj.port,
pathname: urlObj.pathname,
search: urlObj.search,
params,
};
return {
protocol: urlObj.protocol.replace(':', ''),
host: urlObj.hostname,
port: urlObj.port,
pathname: urlObj.pathname,
search: urlObj.search,
params,
};
}
/**
* Join URL path segments
*/
export function joinPath(...segments: string[]): string {
return segments
.map(s => s.replace(/^\/+|\/+$/g, ''))
.filter(Boolean)
.join('/');
return segments
.map((s) => s.replace(/^\/+|\/+$/g, ''))
.filter(Boolean)
.join('/');
}
/**
* Common HTTP methods
*/
export const HTTP_METHODS = {
GET: 'GET',
POST: 'POST',
PUT: 'PUT',
PATCH: 'PATCH',
DELETE: 'DELETE',
HEAD: 'HEAD',
OPTIONS: 'OPTIONS',
GET: 'GET',
POST: 'POST',
PUT: 'PUT',
PATCH: 'PATCH',
DELETE: 'DELETE',
HEAD: 'HEAD',
OPTIONS: 'OPTIONS',
} as const;
export type HttpMethod = typeof HTTP_METHODS[keyof typeof HTTP_METHODS];
export type HttpMethod = (typeof HTTP_METHODS)[keyof typeof HTTP_METHODS];
/**
* Common HTTP status codes
*/
export const HTTP_STATUS = {
OK: 200,
CREATED: 201,
NO_CONTENT: 204,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
CONFLICT: 409,
UNPROCESSABLE_ENTITY: 422,
TOO_MANY_REQUESTS: 429,
INTERNAL_SERVER_ERROR: 500,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
OK: 200,
CREATED: 201,
NO_CONTENT: 204,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
CONFLICT: 409,
UNPROCESSABLE_ENTITY: 422,
TOO_MANY_REQUESTS: 429,
INTERNAL_SERVER_ERROR: 500,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
} as const;
export type HttpStatus = typeof HTTP_STATUS[keyof typeof HTTP_STATUS];
export type HttpStatus = (typeof HTTP_STATUS)[keyof typeof HTTP_STATUS];
/**
* Check if status code is successful (2xx)
*/
export function isSuccessStatus(status: number): boolean {
return status >= 200 && status < 300;
return status >= 200 && status < 300;
}
/**
* Check if status code is client error (4xx)
*/
export function isClientError(status: number): boolean {
return status >= 400 && status < 500;
return status >= 400 && status < 500;
}
/**
* Check if status code is server error (5xx)
*/
export function isServerError(status: number): boolean {
return status >= 500 && status < 600;
return status >= 500 && status < 600;
}

View file

@ -8,166 +8,163 @@ import { z } from 'zod';
* Common environment variable schemas
*/
export const envSchemas = {
/** URL schema */
url: z.string().url(),
/** URL schema */
url: z.string().url(),
/** Non-empty string schema */
nonEmpty: z.string().min(1),
/** Non-empty string schema */
nonEmpty: z.string().min(1),
/** Optional string schema */
optional: z.string().optional(),
/** Optional string schema */
optional: z.string().optional(),
/** Port number schema */
port: z.coerce.number().int().min(1).max(65535),
/** Port number schema */
port: z.coerce.number().int().min(1).max(65535),
/** Boolean schema (accepts various formats) */
boolean: z.preprocess(
(val) => {
if (typeof val === 'boolean') return val;
if (typeof val === 'string') {
return ['true', '1', 'yes', 'on'].includes(val.toLowerCase());
}
return false;
},
z.boolean()
),
/** Boolean schema (accepts various formats) */
boolean: z.preprocess((val) => {
if (typeof val === 'boolean') return val;
if (typeof val === 'string') {
return ['true', '1', 'yes', 'on'].includes(val.toLowerCase());
}
return false;
}, z.boolean()),
/** Number schema */
number: z.coerce.number(),
/** Number schema */
number: z.coerce.number(),
/** Positive integer schema */
positiveInt: z.coerce.number().int().positive(),
/** Positive integer schema */
positiveInt: z.coerce.number().int().positive(),
/** Email schema */
email: z.string().email(),
/** Email schema */
email: z.string().email(),
/** Node environment schema */
nodeEnv: z.enum(['development', 'production', 'test']).default('development'),
/** Node environment schema */
nodeEnv: z.enum(['development', 'production', 'test']).default('development'),
};
/**
* Common Supabase environment schema
*/
export const supabaseEnvSchema = z.object({
SUPABASE_URL: envSchemas.url,
SUPABASE_ANON_KEY: envSchemas.nonEmpty,
SUPABASE_SERVICE_ROLE_KEY: envSchemas.nonEmpty.optional(),
SUPABASE_URL: envSchemas.url,
SUPABASE_ANON_KEY: envSchemas.nonEmpty,
SUPABASE_SERVICE_ROLE_KEY: envSchemas.nonEmpty.optional(),
});
/**
* Common app environment schema
*/
export const appEnvSchema = z.object({
NODE_ENV: envSchemas.nodeEnv,
PORT: envSchemas.port.default(3000),
NODE_ENV: envSchemas.nodeEnv,
PORT: envSchemas.port.default(3000),
});
/**
* Create an environment config from schema
*/
export function createEnvConfig<T extends z.ZodTypeAny>(
schema: T,
env: NodeJS.ProcessEnv = process.env
schema: T,
env: NodeJS.ProcessEnv = process.env
): z.infer<T> {
const result = schema.safeParse(env);
const result = schema.safeParse(env);
if (!result.success) {
const errors = result.error.errors
.map((err) => ` ${err.path.join('.')}: ${err.message}`)
.join('\n');
if (!result.success) {
const errors = result.error.errors
.map((err) => ` ${err.path.join('.')}: ${err.message}`)
.join('\n');
throw new Error(`Environment validation failed:\n${errors}`);
}
throw new Error(`Environment validation failed:\n${errors}`);
}
return result.data;
return result.data;
}
/**
* Validate environment variables with custom schema
*/
export function validateEnv<T extends z.ZodRawShape>(
schema: z.ZodObject<T>,
env: NodeJS.ProcessEnv = process.env
schema: z.ZodObject<T>,
env: NodeJS.ProcessEnv = process.env
): z.infer<z.ZodObject<T>> {
return createEnvConfig(schema, env);
return createEnvConfig(schema, env);
}
/**
* Get required environment variable with type safety
*/
export function getRequiredEnv(key: string, env: NodeJS.ProcessEnv = process.env): string {
const value = env[key];
const value = env[key];
if (value === undefined || value === '') {
throw new Error(`Required environment variable "${key}" is not set`);
}
if (value === undefined || value === '') {
throw new Error(`Required environment variable "${key}" is not set`);
}
return value;
return value;
}
/**
* Get optional environment variable with default
*/
export function getEnv(
key: string,
defaultValue: string,
env: NodeJS.ProcessEnv = process.env
key: string,
defaultValue: string,
env: NodeJS.ProcessEnv = process.env
): string {
return env[key] ?? defaultValue;
return env[key] ?? defaultValue;
}
/**
* Get boolean environment variable
*/
export function getBoolEnv(
key: string,
defaultValue: boolean = false,
env: NodeJS.ProcessEnv = process.env
key: string,
defaultValue: boolean = false,
env: NodeJS.ProcessEnv = process.env
): boolean {
const value = env[key];
const value = env[key];
if (value === undefined) {
return defaultValue;
}
if (value === undefined) {
return defaultValue;
}
return ['true', '1', 'yes', 'on'].includes(value.toLowerCase());
return ['true', '1', 'yes', 'on'].includes(value.toLowerCase());
}
/**
* Get number environment variable
*/
export function getNumEnv(
key: string,
defaultValue: number,
env: NodeJS.ProcessEnv = process.env
key: string,
defaultValue: number,
env: NodeJS.ProcessEnv = process.env
): number {
const value = env[key];
const value = env[key];
if (value === undefined) {
return defaultValue;
}
if (value === undefined) {
return defaultValue;
}
const parsed = Number(value);
return isNaN(parsed) ? defaultValue : parsed;
const parsed = Number(value);
return isNaN(parsed) ? defaultValue : parsed;
}
/**
* Check if running in development
*/
export function isDevelopment(env: NodeJS.ProcessEnv = process.env): boolean {
return env.NODE_ENV === 'development';
return env.NODE_ENV === 'development';
}
/**
* Check if running in production
*/
export function isProduction(env: NodeJS.ProcessEnv = process.env): boolean {
return env.NODE_ENV === 'production';
return env.NODE_ENV === 'production';
}
/**
* Check if running in test
*/
export function isTest(env: NodeJS.ProcessEnv = process.env): boolean {
return env.NODE_ENV === 'test';
return env.NODE_ENV === 'test';
}

View file

@ -6,168 +6,168 @@
* Feature flag configuration
*/
export interface FeatureFlag {
/** Feature key */
key: string;
/** Default enabled state */
defaultEnabled: boolean;
/** Description */
description?: string;
/** Environment variable to override */
envVar?: string;
/** Feature key */
key: string;
/** Default enabled state */
defaultEnabled: boolean;
/** Description */
description?: string;
/** Environment variable to override */
envVar?: string;
}
/**
* Create a feature flag manager
*/
export function createFeatureFlags<T extends Record<string, FeatureFlag>>(
flags: T,
env: NodeJS.ProcessEnv = process.env
flags: T,
env: NodeJS.ProcessEnv = process.env
) {
type FlagKey = keyof T;
type FlagKey = keyof T;
/**
* Check if a feature is enabled
*/
function isEnabled(key: FlagKey): boolean {
const flag = flags[key];
/**
* Check if a feature is enabled
*/
function isEnabled(key: FlagKey): boolean {
const flag = flags[key];
if (!flag) {
return false;
}
if (!flag) {
return false;
}
// Check environment variable override
if (flag.envVar) {
const envValue = env[flag.envVar];
if (envValue !== undefined) {
return ['true', '1', 'yes', 'on'].includes(envValue.toLowerCase());
}
}
// Check environment variable override
if (flag.envVar) {
const envValue = env[flag.envVar];
if (envValue !== undefined) {
return ['true', '1', 'yes', 'on'].includes(envValue.toLowerCase());
}
}
// Check generic feature flag env var
const genericEnvVar = `FEATURE_${String(key).toUpperCase()}`;
const genericValue = env[genericEnvVar];
if (genericValue !== undefined) {
return ['true', '1', 'yes', 'on'].includes(genericValue.toLowerCase());
}
// Check generic feature flag env var
const genericEnvVar = `FEATURE_${String(key).toUpperCase()}`;
const genericValue = env[genericEnvVar];
if (genericValue !== undefined) {
return ['true', '1', 'yes', 'on'].includes(genericValue.toLowerCase());
}
return flag.defaultEnabled;
}
return flag.defaultEnabled;
}
/**
* Get all enabled features
*/
function getEnabledFeatures(): FlagKey[] {
return (Object.keys(flags) as FlagKey[]).filter(isEnabled);
}
/**
* Get all enabled features
*/
function getEnabledFeatures(): FlagKey[] {
return (Object.keys(flags) as FlagKey[]).filter(isEnabled);
}
/**
* Get all disabled features
*/
function getDisabledFeatures(): FlagKey[] {
return (Object.keys(flags) as FlagKey[]).filter(key => !isEnabled(key));
}
/**
* Get all disabled features
*/
function getDisabledFeatures(): FlagKey[] {
return (Object.keys(flags) as FlagKey[]).filter((key) => !isEnabled(key));
}
/**
* Get feature configuration
*/
function getFlag(key: FlagKey): FeatureFlag | undefined {
return flags[key];
}
/**
* Get feature configuration
*/
function getFlag(key: FlagKey): FeatureFlag | undefined {
return flags[key];
}
/**
* Get all flags with their current state
*/
function getAllFlags(): Record<string, boolean> {
const result: Record<string, boolean> = {};
for (const key of Object.keys(flags) as FlagKey[]) {
result[String(key)] = isEnabled(key);
}
return result;
}
/**
* Get all flags with their current state
*/
function getAllFlags(): Record<string, boolean> {
const result: Record<string, boolean> = {};
for (const key of Object.keys(flags) as FlagKey[]) {
result[String(key)] = isEnabled(key);
}
return result;
}
return {
isEnabled,
getEnabledFeatures,
getDisabledFeatures,
getFlag,
getAllFlags,
};
return {
isEnabled,
getEnabledFeatures,
getDisabledFeatures,
getFlag,
getAllFlags,
};
}
/**
* Simple feature check using environment variable
*/
export function isFeatureEnabled(
featureName: string,
defaultValue: boolean = false,
env: NodeJS.ProcessEnv = process.env
featureName: string,
defaultValue: boolean = false,
env: NodeJS.ProcessEnv = process.env
): boolean {
const envVar = `FEATURE_${featureName.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;
const value = env[envVar];
const envVar = `FEATURE_${featureName.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;
const value = env[envVar];
if (value === undefined) {
return defaultValue;
}
if (value === undefined) {
return defaultValue;
}
return ['true', '1', 'yes', 'on'].includes(value.toLowerCase());
return ['true', '1', 'yes', 'on'].includes(value.toLowerCase());
}
/**
* App metadata configuration
*/
export interface AppMetadata {
/** App name */
name: string;
/** App version */
version: string;
/** App description */
description?: string;
/** Build number */
buildNumber?: string;
/** Git commit hash */
commitHash?: string;
/** Build timestamp */
buildTime?: string;
/** Environment */
environment?: string;
/** App name */
name: string;
/** App version */
version: string;
/** App description */
description?: string;
/** Build number */
buildNumber?: string;
/** Git commit hash */
commitHash?: string;
/** Build timestamp */
buildTime?: string;
/** Environment */
environment?: string;
}
/**
* Create app metadata from environment
*/
export function createAppMetadata(
config: {
name: string;
version: string;
description?: string;
},
env: NodeJS.ProcessEnv = process.env
config: {
name: string;
version: string;
description?: string;
},
env: NodeJS.ProcessEnv = process.env
): AppMetadata {
return {
name: config.name,
version: config.version,
description: config.description,
buildNumber: env.BUILD_NUMBER || env.VITE_BUILD_NUMBER,
commitHash: env.COMMIT_HASH || env.VITE_COMMIT_HASH || env.GIT_COMMIT,
buildTime: env.BUILD_TIME || env.VITE_BUILD_TIME,
environment: env.NODE_ENV || 'development',
};
return {
name: config.name,
version: config.version,
description: config.description,
buildNumber: env.BUILD_NUMBER || env.VITE_BUILD_NUMBER,
commitHash: env.COMMIT_HASH || env.VITE_COMMIT_HASH || env.GIT_COMMIT,
buildTime: env.BUILD_TIME || env.VITE_BUILD_TIME,
environment: env.NODE_ENV || 'development',
};
}
/**
* Format version string with build info
*/
export function formatVersion(metadata: AppMetadata): string {
let version = metadata.version;
let version = metadata.version;
if (metadata.buildNumber) {
version += ` (${metadata.buildNumber})`;
}
if (metadata.buildNumber) {
version += ` (${metadata.buildNumber})`;
}
if (metadata.commitHash) {
const shortHash = metadata.commitHash.substring(0, 7);
version += ` [${shortHash}]`;
}
if (metadata.commitHash) {
const shortHash = metadata.commitHash.substring(0, 7);
version += ` [${shortHash}]`;
}
return version;
return version;
}

View file

@ -7,42 +7,42 @@
// Environment utilities
export {
envSchemas,
supabaseEnvSchema,
appEnvSchema,
createEnvConfig,
validateEnv,
getRequiredEnv,
getEnv,
getBoolEnv,
getNumEnv,
isDevelopment,
isProduction,
isTest,
envSchemas,
supabaseEnvSchema,
appEnvSchema,
createEnvConfig,
validateEnv,
getRequiredEnv,
getEnv,
getBoolEnv,
getNumEnv,
isDevelopment,
isProduction,
isTest,
} from './env';
// API utilities
export {
type ApiConfig,
createApiBuilder,
buildUrl,
parseUrl,
joinPath,
HTTP_METHODS,
HTTP_STATUS,
type HttpMethod,
type HttpStatus,
isSuccessStatus,
isClientError,
isServerError,
type ApiConfig,
createApiBuilder,
buildUrl,
parseUrl,
joinPath,
HTTP_METHODS,
HTTP_STATUS,
type HttpMethod,
type HttpStatus,
isSuccessStatus,
isClientError,
isServerError,
} from './api';
// Feature flag utilities
export {
type FeatureFlag,
createFeatureFlags,
isFeatureEnabled,
type AppMetadata,
createAppMetadata,
formatVersion,
type FeatureFlag,
createFeatureFlags,
isFeatureEnabled,
type AppMetadata,
createAppMetadata,
formatVersion,
} from './features';

View file

@ -1,19 +1,19 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "DOM"],
"types": ["node"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "DOM"],
"types": ["node"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}