docs: update README files for core packages with architecture diagrams and usage examples
This commit is contained in:
@@ -89,6 +89,12 @@ declare module '@repo/core-events' {
|
||||
'STORE:ORDER_PLACED': OrderPayload;
|
||||
'STORE:ORDER_CANCELLED': { orderId: string; reason: string };
|
||||
'UI:SIDEBAR_TOGGLED': { collapsed: boolean };
|
||||
|
||||
// Explicit payloads for the examples below:
|
||||
'DEVICE:PRINT_RECEIPT': { receiptId: string; items: any[]; total: number; cashierName: string; timestamp: number };
|
||||
'WS:STOCK_UPDATE': { id: string; price: number };
|
||||
'AUTH:PROFILE_UPDATED': { id: string; name: string; email: string; avatar: string; updatedAt: number };
|
||||
'SYSTEM:ERROR': { source: string; error: Error };
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -102,7 +108,7 @@ function CheckoutButton() {
|
||||
const publish = usePublishEvent();
|
||||
// ✅ 'STORE:ORDER_PLACED' autocompletes.
|
||||
// ✅ Payload shape is enforced by TypeScript.
|
||||
publish('STORE:ORDER_PLACED', { orderId: '123', total: 99, items: [...] });
|
||||
publish('STORE:ORDER_PLACED', { orderId: '123', total: 99, items: [] });
|
||||
}
|
||||
|
||||
function OrderTracker() {
|
||||
@@ -124,6 +130,29 @@ function OrderTracker() {
|
||||
|
||||
---
|
||||
|
||||
## Usage Outside React (Vanilla TS)
|
||||
|
||||
For utility files, API interceptors, Web Workers, or vanilla functions where React hooks cannot be used, import the raw `eventBus` instance directly.
|
||||
|
||||
```ts
|
||||
import { eventBus } from '@repo/core-events';
|
||||
|
||||
// Publishing
|
||||
eventBus.publish('STORE:ORDER_CANCELLED', { orderId: '123', reason: 'Out of stock' });
|
||||
|
||||
// Subscribing
|
||||
const handler = (payload) => {
|
||||
console.log('Order cancelled:', payload.orderId);
|
||||
};
|
||||
|
||||
eventBus.subscribe('STORE:ORDER_CANCELLED', handler);
|
||||
|
||||
// CRITICAL: Always unsubscribe when done to prevent memory leaks in non-React contexts!
|
||||
eventBus.unsubscribe('STORE:ORDER_CANCELLED', handler);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
Here are three real-world architectural patterns powered by the Event Bus. All event types below are registered in `apps/web/src/types/events.d.ts`, **not** in the core package.
|
||||
@@ -145,7 +174,7 @@ export function CashierUI() {
|
||||
// Fire and forget. Zero knowledge of how printing actually happens.
|
||||
publish('DEVICE:PRINT_RECEIPT', {
|
||||
receiptId: 'RCP-123',
|
||||
items: [...],
|
||||
items: [],
|
||||
total: 45.00,
|
||||
cashierName: 'Firman',
|
||||
timestamp: Date.now(),
|
||||
@@ -235,7 +264,7 @@ export const StockRow = memo(function StockRow({ stockId }) {
|
||||
|
||||
**Problem**: When a user updates their profile, we need to persist it to the secure local IndexedDB. We don't want to tightly couple our UI forms to the `@repo/core-storage` package.
|
||||
|
||||
**Solution**: The UI form announces the profile update. A dedicated storage listener persists it in the background.
|
||||
**Solution**: The UI form announces the profile update. A dedicated storage listener persists it in the background, properly escalating errors if the storage fails.
|
||||
|
||||
**Publisher (Profile UI)**:
|
||||
```tsx
|
||||
@@ -249,7 +278,7 @@ export function ProfileSettingsUI() {
|
||||
id: 'user-1',
|
||||
name: 'Firman',
|
||||
email: 'firman@eigen.co.id',
|
||||
avatar: 'https://example.com/avatar.png',
|
||||
avatar: '[https://example.com/avatar.png](https://example.com/avatar.png)',
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
};
|
||||
@@ -260,16 +289,21 @@ export function ProfileSettingsUI() {
|
||||
|
||||
**Subscriber (Storage Sync Listener)**:
|
||||
```tsx
|
||||
import { useAppEvent } from '@repo/core-events';
|
||||
import { useAppEvent, usePublishEvent } from '@repo/core-events';
|
||||
import { secureIndexedDB } from '@repo/core-storage';
|
||||
|
||||
export function StorageSyncListener() {
|
||||
const publish = usePublishEvent();
|
||||
|
||||
useAppEvent('AUTH:PROFILE_UPDATED', (payload) => {
|
||||
// Automatically encrypted at rest because 'user_profile'
|
||||
// is defined in ENCRYPTED_KEYS in @repo/core-storage
|
||||
secureIndexedDB.setItem('user_profile', payload).catch(console.error);
|
||||
secureIndexedDB.setItem('user_profile', payload).catch((error) => {
|
||||
// Escalate to global error handler instead of swallowing it
|
||||
publish('SYSTEM:ERROR', { source: 'StorageSyncListener', error });
|
||||
});
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
```
|
||||
```
|
||||
Reference in New Issue
Block a user