mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 01:01:09 +02:00
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:
parent
e7f5f942f3
commit
2c58d03f63
23 changed files with 738 additions and 0 deletions
24
packages/shared-supabase/package.json
Normal file
24
packages/shared-supabase/package.json
Normal 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:*"
|
||||
}
|
||||
}
|
||||
62
packages/shared-supabase/src/index.ts
Normal file
62
packages/shared-supabase/src/index.ts
Normal 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 };
|
||||
},
|
||||
};
|
||||
17
packages/shared-supabase/tsconfig.json
Normal file
17
packages/shared-supabase/tsconfig.json
Normal 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"]
|
||||
}
|
||||
18
packages/shared-types/package.json
Normal file
18
packages/shared-types/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
47
packages/shared-types/src/index.ts
Normal file
47
packages/shared-types/src/index.ts
Normal 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;
|
||||
}
|
||||
17
packages/shared-types/tsconfig.json
Normal file
17
packages/shared-types/tsconfig.json
Normal 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"]
|
||||
}
|
||||
23
packages/shared-ui/package.json
Normal file
23
packages/shared-ui/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
24
packages/shared-ui/src/index.ts
Normal file
24
packages/shared-ui/src/index.ts
Normal 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';
|
||||
18
packages/shared-ui/tsconfig.json
Normal file
18
packages/shared-ui/tsconfig.json
Normal 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"]
|
||||
}
|
||||
21
packages/shared-utils/package.json
Normal file
21
packages/shared-utils/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
71
packages/shared-utils/src/async.ts
Normal file
71
packages/shared-utils/src/async.ts
Normal 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);
|
||||
};
|
||||
}
|
||||
43
packages/shared-utils/src/date.ts
Normal file
43
packages/shared-utils/src/date.ts
Normal 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();
|
||||
}
|
||||
12
packages/shared-utils/src/index.ts
Normal file
12
packages/shared-utils/src/index.ts
Normal 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';
|
||||
43
packages/shared-utils/src/string.ts
Normal file
43
packages/shared-utils/src/string.ts
Normal 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, '');
|
||||
}
|
||||
17
packages/shared-utils/tsconfig.json
Normal file
17
packages/shared-utils/tsconfig.json
Normal 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"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue