@fjell/express-router 4.4.55 → 4.4.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,391 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- /**
3
- * Basic Express Router Example
4
- *
5
- * This example demonstrates the fundamental usage of fjell-express-router for setting up
6
- * Express routes that automatically handle CRUD operations for data models.
7
- * It shows how to create routers, integrate with Express apps, and handle basic HTTP operations.
8
- *
9
- * Perfect for understanding the basics of fjell-express-router before moving to advanced features.
10
- *
11
- * Run this example with: npx tsx examples/basic-router-example.ts
12
- */
13
-
14
- import { Item, PriKey, UUID } from '@fjell/core';
15
- import { NotFoundError } from '@fjell/lib';
16
- import express, { Application } from 'express';
17
- import { createRegistry, PItemRouter } from '../src';
18
-
19
- // Define our data models
20
- export interface User extends Item<'user'> {
21
- id: string;
22
- name: string;
23
- email: string;
24
- role: 'admin' | 'user' | 'guest';
25
- lastLogin?: Date;
26
- }
27
-
28
- export interface Task extends Item<'task'> {
29
- id: string;
30
- title: string;
31
- description: string;
32
- assignedTo?: string;
33
- status: 'pending' | 'in-progress' | 'completed';
34
- priority: 'low' | 'medium' | 'high';
35
- dueDate?: Date;
36
- }
37
-
38
- // Mock storage for demonstration (in real apps, this would be your database/API)
39
- const mockUserStorage = new Map<string, User>();
40
- const mockTaskStorage = new Map<string, Task>();
41
-
42
- // Counters for unique ID generation
43
- let userIdCounter = 1000;
44
- let taskIdCounter = 1000;
45
-
46
- // Initialize with some sample data
47
- const initializeSampleData = () => {
48
- const users: User[] = [
49
- {
50
- key: { kt: 'user', pk: 'user-1' as UUID },
51
- id: 'user-1',
52
- name: 'Alice Johnson',
53
- email: 'alice@example.com',
54
- role: 'admin',
55
- lastLogin: new Date('2025-01-15T10:30:00Z'),
56
- events: {
57
- created: { at: new Date('2025-01-01T00:00:00Z') },
58
- updated: { at: new Date('2025-01-15T10:30:00Z') },
59
- deleted: { at: null }
60
- }
61
- },
62
- {
63
- key: { kt: 'user', pk: 'user-2' as UUID },
64
- id: 'user-2',
65
- name: 'Bob Smith',
66
- email: 'bob@example.com',
67
- role: 'user',
68
- lastLogin: new Date('2025-01-14T15:20:00Z'),
69
- events: {
70
- created: { at: new Date('2025-01-02T00:00:00Z') },
71
- updated: { at: new Date('2025-01-14T15:20:00Z') },
72
- deleted: { at: null }
73
- }
74
- }
75
- ];
76
-
77
- const tasks: Task[] = [
78
- {
79
- key: { kt: 'task', pk: 'task-1' as UUID },
80
- id: 'task-1',
81
- title: 'Setup project documentation',
82
- description: 'Create comprehensive documentation for the new project',
83
- assignedTo: 'user-1',
84
- status: 'in-progress',
85
- priority: 'high',
86
- dueDate: new Date('2025-01-30T00:00:00Z'),
87
- events: {
88
- created: { at: new Date('2025-01-10T00:00:00Z') },
89
- updated: { at: new Date('2025-01-15T00:00:00Z') },
90
- deleted: { at: null }
91
- }
92
- },
93
- {
94
- key: { kt: 'task', pk: 'task-2' as UUID },
95
- id: 'task-2',
96
- title: 'Review code changes',
97
- description: 'Review and approve pending pull requests',
98
- assignedTo: 'user-2',
99
- status: 'pending',
100
- priority: 'medium',
101
- dueDate: new Date('2025-01-25T00:00:00Z'),
102
- events: {
103
- created: { at: new Date('2025-01-12T00:00:00Z') },
104
- updated: { at: new Date('2025-01-12T00:00:00Z') },
105
- deleted: { at: null }
106
- }
107
- }
108
- ];
109
-
110
- users.forEach(user => mockUserStorage.set(user.id, user));
111
- tasks.forEach(task => mockTaskStorage.set(task.id, task));
112
-
113
- console.log('šŸ“¦ Initialized sample data:');
114
- console.log(` Users: ${users.length} records`);
115
- console.log(` Tasks: ${tasks.length} records`);
116
- };
117
-
118
- // Create mock operations for Users and Tasks
119
- const createUserOperations = () => {
120
- return {
121
- async all() {
122
- console.log('šŸ“¦ UserOperations.all() - Fetching all users...');
123
- return Array.from(mockUserStorage.values());
124
- },
125
-
126
- async get(key: PriKey<'user'>) {
127
- console.log(`šŸ” UserOperations.get(${key.pk}) - Fetching user...`);
128
- const user = mockUserStorage.get(String(key.pk));
129
- if (!user) {
130
- throw new NotFoundError('get', { kta: ['user', '', '', '', '', ''], scopes: [] }, key);
131
- }
132
- return user;
133
- },
134
-
135
- async create(item: User) {
136
- console.log(`✨ UserOperations.create() - Creating user: ${item.name}`);
137
- const id = `user-${++userIdCounter}`;
138
- const newUser: User = {
139
- ...item,
140
- id,
141
- key: { kt: 'user', pk: id as UUID },
142
- events: {
143
- created: { at: new Date() },
144
- updated: { at: new Date() },
145
- deleted: { at: null }
146
- }
147
- };
148
- mockUserStorage.set(id, newUser);
149
- return newUser;
150
- },
151
-
152
- async update(key: PriKey<'user'>, updates: Partial<User>) {
153
- console.log(`šŸ”„ UserOperations.update(${key.pk}) - Updating user...`);
154
- const existing = mockUserStorage.get(String(key.pk));
155
- if (!existing) {
156
- throw new NotFoundError('update', { kta: ['user', '', '', '', '', ''], scopes: [] }, key);
157
- }
158
- const updated: User = {
159
- ...existing,
160
- ...updates,
161
- events: {
162
- ...existing.events,
163
- updated: { at: new Date() }
164
- }
165
- };
166
- mockUserStorage.set(String(key.pk), updated);
167
- return updated;
168
- },
169
-
170
- async remove(key: PriKey<'user'>) {
171
- console.log(`šŸ—‘ļø UserOperations.remove(${key.pk}) - Removing user...`);
172
- const existing = mockUserStorage.get(String(key.pk));
173
- if (!existing) {
174
- return false;
175
- }
176
- mockUserStorage.delete(String(key.pk));
177
- return existing;
178
- },
179
-
180
- async find(finder: string, params: any) {
181
- console.log(`šŸ”Ž UserOperations.find(${finder}) - Finding users...`, params);
182
- const users = Array.from(mockUserStorage.values());
183
-
184
- switch (finder) {
185
- case 'byRole':
186
- return users.filter(user => user.role === params.role);
187
- case 'byEmail':
188
- return users.filter(user => user.email.includes(params.email));
189
- default:
190
- return users;
191
- }
192
- }
193
- };
194
- };
195
-
196
- const createTaskOperations = () => {
197
- return {
198
- async all() {
199
- console.log('šŸ“¦ TaskOperations.all() - Fetching all tasks...');
200
- return Array.from(mockTaskStorage.values());
201
- },
202
-
203
- async get(key: PriKey<'task'>) {
204
- console.log(`šŸ” TaskOperations.get(${key.pk}) - Fetching task...`);
205
- const task = mockTaskStorage.get(String(key.pk));
206
- if (!task) {
207
- throw new NotFoundError('get', { kta: ['task', '', '', '', '', ''], scopes: [] }, key);
208
- }
209
- return task;
210
- },
211
-
212
- async create(item: Task) {
213
- console.log(`✨ TaskOperations.create() - Creating task: ${item.title}`);
214
- const id = `task-${++taskIdCounter}`;
215
- const newTask: Task = {
216
- ...item,
217
- id,
218
- key: { kt: 'task', pk: id as UUID },
219
- events: {
220
- created: { at: new Date() },
221
- updated: { at: new Date() },
222
- deleted: { at: null }
223
- }
224
- };
225
- mockTaskStorage.set(id, newTask);
226
- return newTask;
227
- },
228
-
229
- async update(key: PriKey<'task'>, updates: Partial<Task>) {
230
- console.log(`šŸ”„ TaskOperations.update(${key.pk}) - Updating task...`);
231
- const existing = mockTaskStorage.get(String(key.pk));
232
- if (!existing) {
233
- throw new NotFoundError('update', { kta: ['task', '', '', '', '', ''], scopes: [] }, key);
234
- }
235
- const updated: Task = {
236
- ...existing,
237
- ...updates,
238
- events: {
239
- ...existing.events,
240
- updated: { at: new Date() }
241
- }
242
- };
243
- mockTaskStorage.set(String(key.pk), updated);
244
- return updated;
245
- },
246
-
247
- async remove(key: PriKey<'task'>) {
248
- console.log(`šŸ—‘ļø TaskOperations.remove(${key.pk}) - Removing task...`);
249
- const existing = mockTaskStorage.get(String(key.pk));
250
- if (!existing) {
251
- return false;
252
- }
253
- mockTaskStorage.delete(String(key.pk));
254
- return existing;
255
- },
256
-
257
- async find(finder: string, params: any) {
258
- console.log(`šŸ”Ž TaskOperations.find(${finder}) - Finding tasks...`, params);
259
- const tasks = Array.from(mockTaskStorage.values());
260
-
261
- switch (finder) {
262
- case 'byStatus':
263
- return tasks.filter(task => task.status === params.status);
264
- case 'byAssignee':
265
- return tasks.filter(task => task.assignedTo === params.assignedTo);
266
- case 'byPriority':
267
- return tasks.filter(task => task.priority === params.priority);
268
- default:
269
- return tasks;
270
- }
271
- }
272
- };
273
- };
274
-
275
- /**
276
- * Main function demonstrating basic fjell-express-router usage
277
- */
278
- export const runBasicRouterExample = async (): Promise<{ app: Application; userRouter: PItemRouter<User, 'user'>; taskRouter: PItemRouter<Task, 'task'> }> => {
279
- console.log('šŸš€ Starting Basic Express Router Example...\n');
280
-
281
- // Initialize sample data
282
- initializeSampleData();
283
-
284
- // Create registry and instances
285
- console.log('šŸ“‹ Creating registry and instances...');
286
- const registry = createRegistry();
287
-
288
- // Create mock instances that simulate the fjell pattern
289
- const mockUserInstance = {
290
- operations: createUserOperations(),
291
- options: {}
292
- } as any;
293
-
294
- const mockTaskInstance = {
295
- operations: createTaskOperations(),
296
- options: {}
297
- } as any;
298
-
299
- // Create Express app
300
- const app: Application = express();
301
- app.use(express.json());
302
-
303
- // Add request logging middleware
304
- app.use((req, res, next) => {
305
- console.log(`🌐 ${req.method} ${req.path}`, req.query);
306
- next();
307
- });
308
-
309
- // Create PItemRouters for our models
310
- console.log('šŸ›¤ļø Creating Express routers...');
311
- const userRouter = new PItemRouter(mockUserInstance, 'user');
312
- const taskRouter = new PItemRouter(mockTaskInstance, 'task');
313
-
314
- // Mount the routers on Express app
315
- // These will automatically create REST endpoints:
316
- // GET /api/users - Get all users
317
- // GET /api/users/:userPk - Get specific user
318
- // POST /api/users - Create new user
319
- // PUT /api/users/:userPk - Update user
320
- // DELETE /api/users/:userPk - Delete user
321
- app.use('/api/users', userRouter.getRouter());
322
- app.use('/api/tasks', taskRouter.getRouter());
323
-
324
- // Add some custom routes to demonstrate business logic
325
- app.get('/api/health', (req, res) => {
326
- res.json({
327
- status: 'healthy',
328
- timestamp: new Date().toISOString(),
329
- users: mockUserStorage.size,
330
- tasks: mockTaskStorage.size
331
- });
332
- });
333
-
334
- // Dashboard route showing summary data
335
- app.get('/api/dashboard', async (req, res) => {
336
- try {
337
- const users = await mockUserInstance.operations.all();
338
- const tasks = await mockTaskInstance.operations.all();
339
-
340
- const dashboard = {
341
- summary: {
342
- totalUsers: users.length,
343
- totalTasks: tasks.length,
344
- completedTasks: tasks.filter((t: Task) => t.status === 'completed').length,
345
- pendingTasks: tasks.filter((t: Task) => t.status === 'pending').length,
346
- inProgressTasks: tasks.filter((t: Task) => t.status === 'in-progress').length
347
- },
348
- users: users.map((u: User) => ({ id: u.id, name: u.name, role: u.role })),
349
- recentTasks: tasks
350
- .sort((a: Task, b: Task) => b.events.created.at.getTime() - a.events.created.at.getTime())
351
- .slice(0, 5)
352
- };
353
-
354
- res.json(dashboard);
355
- } catch (error) {
356
- res.status(500).json({ error: 'Failed to load dashboard' });
357
- }
358
- });
359
-
360
- console.log('\nāœ… Basic Express Router Example setup complete!');
361
- console.log('\nšŸ“š Available endpoints:');
362
- console.log(' GET /api/health - Health check');
363
- console.log(' GET /api/dashboard - Dashboard summary');
364
- console.log(' GET /api/users - List all users');
365
- console.log(' GET /api/users/:userPk - Get specific user');
366
- console.log(' POST /api/users - Create new user');
367
- console.log(' PUT /api/users/:userPk - Update user');
368
- console.log(' DELETE /api/users/:userPk - Delete user');
369
- console.log(' GET /api/tasks - List all tasks');
370
- console.log(' GET /api/tasks/:taskPk - Get specific task');
371
- console.log(' POST /api/tasks - Create new task');
372
- console.log(' PUT /api/tasks/:taskPk - Update task');
373
- console.log(' DELETE /api/tasks/:taskPk - Delete task');
374
-
375
- return { app, userRouter, taskRouter };
376
- };
377
-
378
- // If this file is run directly, start the server
379
- if (import.meta.url === `file://${process.argv[1]}`) {
380
- runBasicRouterExample().then(({ app }) => {
381
- const PORT = process.env.PORT || 3001;
382
- app.listen(PORT, () => {
383
- console.log(`\n🌟 Server running on http://localhost:${PORT}`);
384
- console.log('\nšŸ’” Try these example requests:');
385
- console.log(` curl http://localhost:${PORT}/api/health`);
386
- console.log(` curl http://localhost:${PORT}/api/dashboard`);
387
- console.log(` curl http://localhost:${PORT}/api/users`);
388
- console.log(` curl http://localhost:${PORT}/api/tasks`);
389
- });
390
- }).catch(console.error);
391
- }