feat: add monorepo configuration and shared packages structure

Root-level setup:
- package.json with Turborepo scripts
- pnpm-workspace.yaml for workspace management
- turbo.json for build pipeline
- Common config files (.nvmrc, .prettierrc, .editorconfig)

Shared packages (packages/):
- @manacore/shared-types - Common TypeScript types
- @manacore/shared-supabase - Unified Supabase client
- @manacore/shared-utils - Date, string, async utilities
- @manacore/shared-ui - React Native UI components (placeholder)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-11-22 23:41:52 +01:00
parent e7f5f942f3
commit 2c58d03f63
23 changed files with 738 additions and 0 deletions

View file

@ -0,0 +1,24 @@
{
"name": "@manacore/shared-supabase",
"version": "0.1.0",
"private": true,
"description": "Shared Supabase client and utilities for Manacore monorepo",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"type-check": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@supabase/supabase-js": "^2.81.1"
},
"devDependencies": {
"typescript": "^5.9.2"
},
"peerDependencies": {
"@manacore/shared-types": "workspace:*"
}
}

View file

@ -0,0 +1,62 @@
/**
* Shared Supabase utilities for Manacore monorepo
*
* This package provides a unified Supabase client and common database utilities.
*/
import { createClient, SupabaseClient } from '@supabase/supabase-js';
import type { SupabaseConfig } from '@manacore/shared-types';
export { SupabaseClient } from '@supabase/supabase-js';
/**
* Create a Supabase client with the given configuration
*/
export function createSupabaseClient(config: SupabaseConfig): SupabaseClient {
return createClient(config.url, config.anonKey, {
auth: {
persistSession: true,
autoRefreshToken: true,
},
});
}
/**
* Create a Supabase admin client with service role key
*/
export function createSupabaseAdminClient(config: SupabaseConfig): SupabaseClient {
if (!config.serviceRoleKey) {
throw new Error('Service role key is required for admin client');
}
return createClient(config.url, config.serviceRoleKey, {
auth: {
persistSession: false,
autoRefreshToken: false,
},
});
}
/**
* Common database query helpers
*/
export const dbHelpers = {
/**
* Handle Supabase query result and return standardized response
*/
handleQueryResult<T>(result: { data: T | null; error: any }): {
data: T | null;
error: { message: string; code?: string } | null;
} {
if (result.error) {
return {
data: null,
error: {
message: result.error.message,
code: result.error.code,
},
};
}
return { data: result.data, error: null };
},
};

View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,18 @@
{
"name": "@manacore/shared-types",
"version": "0.1.0",
"private": true,
"description": "Shared TypeScript types for Manacore monorepo",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"type-check": "tsc --noEmit",
"clean": "rm -rf dist"
},
"devDependencies": {
"typescript": "^5.9.2"
}
}

View file

@ -0,0 +1,47 @@
/**
* Shared types for Manacore monorepo
*
* This package contains common TypeScript types used across all projects.
*/
// Common user types
export interface User {
id: string;
email: string;
created_at: string;
updated_at: string;
}
// Common API response types
export interface ApiResponse<T> {
data: T | null;
error: ApiError | null;
}
export interface ApiError {
message: string;
code?: string;
status?: number;
}
// Pagination types
export interface PaginationParams {
page?: number;
limit?: number;
offset?: number;
}
export interface PaginatedResponse<T> {
data: T[];
total: number;
page: number;
limit: number;
hasMore: boolean;
}
// Supabase common types
export interface SupabaseConfig {
url: string;
anonKey: string;
serviceRoleKey?: string;
}

View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,23 @@
{
"name": "@manacore/shared-ui",
"version": "0.1.0",
"private": true,
"description": "Shared React Native UI components for Manacore monorepo",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"type-check": "tsc --noEmit",
"clean": "rm -rf dist"
},
"peerDependencies": {
"react": ">=18.0.0",
"react-native": ">=0.70.0"
},
"devDependencies": {
"@types/react": "^18.3.0",
"typescript": "^5.9.2"
}
}

View file

@ -0,0 +1,24 @@
/**
* Shared React Native UI components for Manacore monorepo
*
* This package will contain common UI components used across all mobile apps.
*
* Planned components:
* - Button
* - Text
* - Input
* - Card
* - Modal
* - Loading indicators
* - Icons
*/
// Placeholder export until components are migrated
export const SHARED_UI_VERSION = '0.1.0';
// Future exports will include:
// export { Button } from './components/Button';
// export { Text } from './components/Text';
// export { Input } from './components/Input';
// export { Card } from './components/Card';
// export { Modal } from './components/Modal';

View file

@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020"],
"jsx": "react-native",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,21 @@
{
"name": "@manacore/shared-utils",
"version": "0.1.0",
"private": true,
"description": "Shared utility functions for Manacore monorepo",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"type-check": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"date-fns": "^4.1.0"
},
"devDependencies": {
"typescript": "^5.9.2"
}
}

View file

@ -0,0 +1,71 @@
/**
* Async utility functions
*/
/**
* Sleep for a specified number of milliseconds
*/
export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Retry a function with exponential backoff
*/
export async function retry<T>(
fn: () => Promise<T>,
options: {
maxAttempts?: number;
initialDelay?: number;
maxDelay?: number;
backoffMultiplier?: number;
} = {}
): Promise<T> {
const {
maxAttempts = 3,
initialDelay = 1000,
maxDelay = 10000,
backoffMultiplier = 2,
} = options;
let lastError: Error | undefined;
let delay = initialDelay;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
if (attempt === maxAttempts) {
break;
}
await sleep(delay);
delay = Math.min(delay * backoffMultiplier, maxDelay);
}
}
throw lastError;
}
/**
* Debounce a function
*/
export function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: NodeJS.Timeout | null = null;
return (...args: Parameters<T>) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
fn(...args);
timeoutId = null;
}, delay);
};
}

View file

@ -0,0 +1,43 @@
/**
* Date utility functions
*/
import { format, formatDistanceToNow, parseISO } from 'date-fns';
import { de, enUS } from 'date-fns/locale';
const locales = {
de,
en: enUS,
};
type LocaleKey = keyof typeof locales;
/**
* Format a date string to a readable format
*/
export function formatDate(
date: string | Date,
formatStr: string = 'PPP',
locale: LocaleKey = 'de'
): string {
const dateObj = typeof date === 'string' ? parseISO(date) : date;
return format(dateObj, formatStr, { locale: locales[locale] });
}
/**
* Get relative time from now (e.g., "2 hours ago")
*/
export function formatRelativeTime(date: string | Date, locale: LocaleKey = 'de'): string {
const dateObj = typeof date === 'string' ? parseISO(date) : date;
return formatDistanceToNow(dateObj, {
addSuffix: true,
locale: locales[locale],
});
}
/**
* Format a date for API requests (ISO string)
*/
export function toISOString(date: Date): string {
return date.toISOString();
}

View file

@ -0,0 +1,12 @@
/**
* Shared utility functions for Manacore monorepo
*/
// Date utilities
export * from './date';
// String utilities
export * from './string';
// Async utilities
export * from './async';

View file

@ -0,0 +1,43 @@
/**
* String utility functions
*/
/**
* Truncate a string to a maximum length with ellipsis
*/
export function truncate(str: string, maxLength: number): string {
if (str.length <= maxLength) return str;
return str.slice(0, maxLength - 3) + '...';
}
/**
* Capitalize the first letter of a string
*/
export function capitalize(str: string): string {
if (!str) return str;
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* Generate a random string ID
*/
export function generateId(length: number = 8): string {
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
/**
* Slugify a string for URLs
*/
export function slugify(str: string): string {
return str
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_-]+/g, '-')
.replace(/^-+|-+$/g, '');
}

View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}