@crescender/calendar
Version:
A comprehensive TypeScript calendar library with musician-specific capabilities, architected for client/server separation.
380 lines (295 loc) ⢠9.6 kB
Markdown
Version 0.3.0 introduces a significant architectural change with **client/server separation**. The package is now structured to provide clean separation between browser-safe client code and Node.js server code.
**Before (v0.2.x):**
```typescript
import {
createEvent,
Event,
Calendar,
addEventIncome,
calculateEventProfit,
generateIcs,
validateEvent,
formatDateAustralian
} from '@crescender/calendar';
```
**After (v0.3.0):**
```typescript
// For server-side operations (Node.js only)
import {
createEvent,
Event,
Calendar,
addEventIncome,
calculateEventProfit,
generateIcs,
initDb
} from '@crescender/calendar/server';
// For client-side operations (browser-safe)
import {
validateEvent,
formatDateAustralian,
enhanceClientEvent,
expandRecurrence,
EventCard
} from '@crescender/calendar/client';
// For shared utilities (both environments)
import {
EVENT_TYPES,
PAYMENT_STATUS,
EventType,
IEvent
} from '@crescender/calendar/shared';
// OR from main entry:
import { EVENT_TYPES, PAYMENT_STATUS } from '@crescender/calendar';
```
| Functionality | v0.2.x Location | v0.3.0 Location |
|---------------|-----------------|-----------------|
| Database operations | Main package | `/server` |
| ICS generation | Main package | `/server` |
| Event validation | Main package | `/client` |
| Date formatting | Main package | `/client` |
| React components | Main package | `/client` |
| Types & constants | Main package | `/shared` (or main) |
**Before (v0.2.x):**
```typescript
import { initDb, createEvent } from '@crescender/calendar';
await initDb(dataSource);
const event = await createEvent('calendar-id', eventData);
```
**After (v0.3.0):**
```typescript
import { initDb, createEvent } from '@crescender/calendar/server';
await initDb(dataSource);
const event = await createEvent('calendar-id', eventData);
```
**Before (v0.2.x):**
```typescript
import { validateEvent, formatDateAustralian } from '@crescender/calendar';
const validation = validateEvent(formData);
const formattedDate = formatDateAustralian(new Date());
```
**After (v0.3.0):**
```typescript
import { validateEvent, formatDateAustralian } from '@crescender/calendar/client';
const validation = validateEvent(formData);
const formattedDate = formatDateAustralian(new Date());
```
```typescript
import {
enhanceClientEvent,
expandRecurrence,
filterEvents,
sortEvents,
groupEventsByDate,
calculateFinancials
} from '@crescender/calendar/client';
// Enhanced event processing with computed properties
const enhancedEvent = enhanceClientEvent(rawEvent);
console.log(enhancedEvent.duration); // Computed duration
console.log(enhancedEvent.profit); // Computed profit
console.log(enhancedEvent.formattedDate); // Australian date format
// Recurrence expansion
const occurrences = expandRecurrence(recurringEvent, startDate, endDate);
// Advanced filtering and sorting
const filteredEvents = filterEvents(events, { type: 'gig', status: 'confirmed' });
const sortedEvents = sortEvents(events, 'date', 'asc');
const groupedEvents = groupEventsByDate(events);
// Financial calculations
const financials = calculateFinancials(events);
```
```typescript
import { EventCard, CalendarView } from '@crescender/calendar/client';
function MyCalendar({ events }) {
return (
<div>
{events.map(event => (
<EventCard
key={event.id}
event={event}
onEdit={handleEdit}
onDelete={handleDelete}
/>
))}
</div>
);
}
```
```typescript
import {
createEvent,
updateEvent,
deleteEvent,
getEventsByType,
getUpcomingGigs,
getFinancialSummary,
generateIcs
} from '@crescender/calendar/server';
// All existing server operations remain the same
// but now properly separated from client code
```
```
@crescender/calendar
āāā index.js (everything mixed together)
āāā types.d.ts
```
```
@crescender/calendar
āāā index.js (shared functionality only)
āāā client/
ā āāā index.js (browser-safe code)
āāā server/
ā āāā index.js (Node.js only code)
āāā shared/
āāā index.js (common utilities)
```
1. **Identify your usage context:**
- Server-side (API routes, Node.js scripts) ā use `/server`
- Client-side (React components, browser) ā use `/client`
- Shared (types, constants) ā use `/shared` or main import
2. **Update import statements:**
```typescript
// Before
import { createEvent, validateEvent, EVENT_TYPES } from '@crescender/calendar';
// After - separate by context
import { createEvent } from '@crescender/calendar/server';
import { validateEvent } from '@crescender/calendar/client';
import { EVENT_TYPES } from '@crescender/calendar'; // or /shared
```
If using TypeScript with module resolution, ensure your `tsconfig.json` supports the new export structure:
```json
{
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}
```
For client-side builds, the `/client` module is optimized to exclude Node.js dependencies:
```typescript
// Webpack/Vite will automatically tree-shake Node.js dependencies
// when importing from /client
import { validateEvent } from '@crescender/calendar/client';
```
1. **Server-side code** should import from `/server`
2. **Client-side code** should import from `/client`
3. **Shared utilities** can import from main package or `/shared`
```typescript
import type { ClientEvent, ServerEvent, IEvent } from '@crescender/calendar/shared';
// ClientEvent: Browser-optimized with computed properties
// ServerEvent: Full database entity with relations
// IEvent: Shared interface for both
```
```typescript
import type {
EventFormData,
ValidationResult,
IncomeFormData,
ExpenseFormData
} from '@crescender/calendar/client';
```
- **Main entry point** still exports shared functionality for basic compatibility
- **Core types** remain unchanged
- **Database schema** is unchanged
- **Import paths** for specific functionality
- **Mixed client/server** operations in the same import
- **Direct access** to internal modules
```typescript
// api/events.ts (Server-side)
import { createEvent, getEventsByType } from '@crescender/calendar/server';
export async function POST(request: Request) {
const eventData = await request.json();
const event = await createEvent('calendar-id', eventData);
return Response.json(event);
}
export async function GET() {
const events = await getEventsByType('calendar-id', 'gig');
return Response.json(events);
}
```
```typescript
// components/EventList.tsx (Client-side)
import { EventCard, enhanceClientEvent } from '@crescender/calendar/client';
import type { IEvent } from '@crescender/calendar/shared';
interface Props {
events: IEvent[];
}
export function EventList({ events }: Props) {
const enhancedEvents = events.map(enhanceClientEvent);
return (
<div>
{enhancedEvents.map(event => (
<EventCard key={event.id} event={event} />
))}
</div>
);
}
```
```typescript
// scripts/generate-report.ts
import {
initDb,
getEventsByType,
getFinancialSummary
} from '@crescender/calendar/server';
const dataSource = new DataSource(config);
await dataSource.initialize();
initDb(dataSource);
const gigs = await getEventsByType('calendar-id', 'gig');
const summary = await getFinancialSummary(gigs.map(g => g.id));
console.log('Financial Summary:', summary);
```
1. **"Cannot resolve module"** error
- Update import paths to use `/client`, `/server`, or `/shared`
2. **Node.js dependencies in browser**
- Use `/client` imports for browser code
- Check bundler configuration
3. **TypeScript errors**
- Update type imports to use specific modules
- Ensure `moduleResolution: "node"` in tsconfig.json
4. **Mixed environment code**
- Separate client and server logic into different files
- Use appropriate module imports for each environment
If you encounter issues during migration:
1. Check the [examples](./examples/) directory
2. Review the [API documentation](./docs/api.md)
3. Open an issue on [GitHub](https://github.com/lincalinca/Crescalendar/issues)
- **Smaller bundle sizes** for client applications
- **Better tree-shaking** support
- **Cleaner separation** of concerns
- **Enhanced type safety** with environment-specific types
- **New React components** for rapid development
- **Improved developer experience** with clear module boundaries
The migration effort pays off with better performance, clearer code organization, and enhanced development experience!