@owlmeans/server-module 0.1.1 → 0.1.3
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.
- package/LICENSE +1 -1
- package/README.md +11 -539
- package/build/index.d.ts +11 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -2
- package/build/index.js.map +1 -1
- package/package.json +5 -6
- package/src/index.ts +13 -3
- package/tsconfig.json +4 -5
- package/src/helper.ts +0 -38
- package/src/module.ts +0 -57
- package/src/types.ts +0 -31
- package/src/utils/helper.ts +0 -2
- package/src/utils/index.ts +0 -3
- package/src/utils/module.ts +0 -3
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2026 OwlMeans Common — Fullstack typescript framework
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,546 +1,18 @@
|
|
|
1
1
|
# @owlmeans/server-module
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Deprecated reexport shim.** This package re-exports everything from [`@owlmeans/server-entrypoint`](../server-entrypoint). Use that package instead.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Migration
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- **Route Integration**: Deep integration with server routing system
|
|
11
|
-
- **Request Handling**: Standardized request/response processing
|
|
12
|
-
- **Error Management**: Built-in error handling and fixer services
|
|
13
|
-
- **Module Elevation**: Converting common modules to server modules
|
|
14
|
-
- **Context Integration**: Seamless integration with server context
|
|
15
|
-
- **Guard Support**: Authentication and authorization integration
|
|
16
|
-
- **Reference Handling**: Module reference system for complex workflows
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install @owlmeans/server-module
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Core Concepts
|
|
25
|
-
|
|
26
|
-
### Server Module
|
|
27
|
-
|
|
28
|
-
A `ServerModule` extends the common module interface with server-specific capabilities, including route models, request handlers, and error fixers.
|
|
29
|
-
|
|
30
|
-
### Module Handler
|
|
31
|
-
|
|
32
|
-
Functions that process incoming requests and generate responses, with access to the full OwlMeans context system.
|
|
33
|
-
|
|
34
|
-
### Fixer Service
|
|
35
|
-
|
|
36
|
-
Error handling services that can intercept and process errors before they're returned to clients.
|
|
37
|
-
|
|
38
|
-
### Module Elevation
|
|
39
|
-
|
|
40
|
-
The process of converting common modules to server modules with enhanced capabilities.
|
|
41
|
-
|
|
42
|
-
## API Reference
|
|
43
|
-
|
|
44
|
-
### Types
|
|
45
|
-
|
|
46
|
-
#### `ServerModule<R>`
|
|
47
|
-
Core server module interface with request handling capabilities.
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
interface ServerModule<R> extends CommonModule {
|
|
51
|
-
route: ServerRouteModel<R> // Server-specific route model
|
|
52
|
-
fixer?: string // Error fixer service alias
|
|
53
|
-
handle: ModuleHandler // Request handler function
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
#### `ModuleOptions<R>`
|
|
58
|
-
Configuration options for module creation.
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
interface ModuleOptions<R> extends CommonModuleOptions {
|
|
62
|
-
force?: boolean // Force elevation even if already elevated
|
|
63
|
-
fixer?: string // Error fixer service alias
|
|
64
|
-
intermediate?: boolean // Mark as intermediate module
|
|
65
|
-
routeOptions?: ServerRouteOptions<R> // Route-specific options
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
#### `FixerService`
|
|
70
|
-
Service interface for error handling.
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
interface FixerService extends Service {
|
|
74
|
-
handle: <R>(reply: R, error: Error) => void
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
#### `RefedModuleHandler<R>`
|
|
79
|
-
Handler function that receives module reference.
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
interface RefedModuleHandler<R = {}> {
|
|
83
|
-
(ref: ModuleRef<R>): ModuleHandler
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Factory Functions
|
|
88
|
-
|
|
89
|
-
#### `module<R>(arg, handler?, opts?): ServerModule<R>`
|
|
90
|
-
Creates a server module from various input types.
|
|
91
|
-
|
|
92
|
-
**Parameters:**
|
|
93
|
-
- `arg`: CommonModule, ServerRouteModel, or CommonRouteModel
|
|
94
|
-
- `handler`: Optional request handler function with module reference
|
|
95
|
-
- `opts`: Optional module configuration
|
|
96
|
-
|
|
97
|
-
**Returns:** Configured ServerModule instance
|
|
98
|
-
|
|
99
|
-
**Examples:**
|
|
100
|
-
|
|
101
|
-
```typescript
|
|
102
|
-
// From route model
|
|
103
|
-
const userModule = module(userRoute, (ref) => async (request, reply) => {
|
|
104
|
-
const users = await getUserList()
|
|
105
|
-
reply.resolve(users)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
// From common module
|
|
109
|
-
const elevatedModule = module(commonModule, handler, {
|
|
110
|
-
fixer: 'error-handler',
|
|
111
|
-
force: true
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
// With options
|
|
115
|
-
const apiModule = module(apiRoute, handler, {
|
|
116
|
-
intermediate: true,
|
|
117
|
-
routeOptions: { cors: true }
|
|
118
|
-
})
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
#### `elevate<R>(modules, alias, handler?, opts?): ServerModule<R>[]`
|
|
122
|
-
Elevates common modules to server modules within a module collection.
|
|
123
|
-
|
|
124
|
-
**Parameters:**
|
|
125
|
-
- `modules`: Array of modules to search within
|
|
126
|
-
- `alias`: Alias of module to elevate
|
|
127
|
-
- `handler`: Optional new handler function
|
|
128
|
-
- `opts`: Optional elevation options
|
|
129
|
-
|
|
130
|
-
**Returns:** Updated modules array with elevated module
|
|
131
|
-
|
|
132
|
-
**Example:**
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
const modules = [commonModule1, commonModule2, commonModule3]
|
|
136
|
-
|
|
137
|
-
// Elevate specific module
|
|
138
|
-
const elevated = elevate(modules, 'user-api', (ref) => async (req, reply) => {
|
|
139
|
-
// New server-specific handler
|
|
140
|
-
const result = await processUserRequest(req)
|
|
141
|
-
reply.resolve(result)
|
|
142
|
-
}, { fixer: 'user-error-handler' })
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Module Creation Patterns
|
|
146
|
-
|
|
147
|
-
#### Basic Request Handler
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
import { module } from '@owlmeans/server-module'
|
|
151
|
-
|
|
152
|
-
const userModule = module(userRoute, (ref) => async (request, reply) => {
|
|
153
|
-
try {
|
|
154
|
-
const { params, query, body } = request
|
|
155
|
-
|
|
156
|
-
// Business logic
|
|
157
|
-
const users = await userService.list(query)
|
|
158
|
-
|
|
159
|
-
// Successful response
|
|
160
|
-
reply.resolve(users, ModuleOutcome.Ok)
|
|
161
|
-
} catch (error) {
|
|
162
|
-
// Error handling
|
|
163
|
-
reply.reject(error)
|
|
164
|
-
}
|
|
165
|
-
})
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
#### Module with Context Access
|
|
169
|
-
|
|
170
|
-
```typescript
|
|
171
|
-
const contextAwareModule = module(route, (ref) => async (request, reply) => {
|
|
172
|
-
const context = ref.ref?.ctx
|
|
173
|
-
|
|
174
|
-
// Access services from context
|
|
175
|
-
const dbService = context?.service('database')
|
|
176
|
-
const authService = context?.service('auth')
|
|
177
|
-
|
|
178
|
-
// Process request with context
|
|
179
|
-
const user = authService.user()
|
|
180
|
-
const data = await dbService.get(request.params.id)
|
|
181
|
-
|
|
182
|
-
reply.resolve(data)
|
|
183
|
-
})
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
#### Module with Error Fixer
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
const resilientModule = module(route, handler, {
|
|
190
|
-
fixer: 'error-fixer'
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
// Error fixer service
|
|
194
|
-
const errorFixer: FixerService = {
|
|
195
|
-
alias: 'error-fixer',
|
|
196
|
-
initialized: true,
|
|
197
|
-
|
|
198
|
-
handle: (reply, error) => {
|
|
199
|
-
if (error instanceof ValidationError) {
|
|
200
|
-
reply.reject(new BadRequestError(error.message))
|
|
201
|
-
} else if (error instanceof DatabaseError) {
|
|
202
|
-
reply.reject(new InternalServerError('Service temporarily unavailable'))
|
|
203
|
-
} else {
|
|
204
|
-
reply.reject(error)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## Usage Examples
|
|
211
|
-
|
|
212
|
-
### Basic CRUD Module
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
import { module } from '@owlmeans/server-module'
|
|
216
|
-
import { route } from '@owlmeans/server-route'
|
|
217
|
-
|
|
218
|
-
// Define route
|
|
219
|
-
const userRoute = route({
|
|
220
|
-
path: '/users/:id?',
|
|
221
|
-
method: RouteMethod.GET,
|
|
222
|
-
alias: 'user-crud'
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
// Create module
|
|
226
|
-
const userModule = module(userRoute, (ref) => async (request, reply) => {
|
|
227
|
-
const { params, query } = request
|
|
228
|
-
|
|
229
|
-
if (params.id) {
|
|
230
|
-
// Get single user
|
|
231
|
-
const user = await userService.get(params.id)
|
|
232
|
-
reply.resolve(user)
|
|
233
|
-
} else {
|
|
234
|
-
// List users
|
|
235
|
-
const users = await userService.list(query)
|
|
236
|
-
reply.resolve(users)
|
|
237
|
-
}
|
|
238
|
-
})
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### Authenticated Module
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
const protectedModule = module(protectedRoute, (ref) => async (request, reply) => {
|
|
245
|
-
// Access authentication from context
|
|
246
|
-
const authService = ref.ref?.ctx?.service('auth')
|
|
247
|
-
const currentUser = authService?.user()
|
|
248
|
-
|
|
249
|
-
if (!currentUser) {
|
|
250
|
-
reply.reject(new UnauthorizedError('Authentication required'))
|
|
251
|
-
return
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Process authenticated request
|
|
255
|
-
const data = await processForUser(currentUser, request)
|
|
256
|
-
reply.resolve(data)
|
|
257
|
-
}, {
|
|
258
|
-
guards: ['auth-guard']
|
|
259
|
-
})
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### File Upload Module
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
const uploadModule = module(uploadRoute, (ref) => async (request, reply) => {
|
|
266
|
-
const { body, headers } = request
|
|
267
|
-
|
|
268
|
-
// Handle file upload
|
|
269
|
-
if (headers['content-type']?.includes('multipart/form-data')) {
|
|
270
|
-
const files = await parseMultipartFiles(body)
|
|
271
|
-
const saved = await fileService.saveFiles(files)
|
|
272
|
-
|
|
273
|
-
reply.resolve(saved, ModuleOutcome.Created)
|
|
274
|
-
} else {
|
|
275
|
-
reply.reject(new BadRequestError('Multipart data required'))
|
|
276
|
-
}
|
|
277
|
-
})
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
### Module with Database Transaction
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
const transactionalModule = module(route, (ref) => async (request, reply) => {
|
|
284
|
-
const dbService = ref.ref?.ctx?.service('database')
|
|
285
|
-
const transaction = await dbService.startTransaction()
|
|
286
|
-
|
|
287
|
-
try {
|
|
288
|
-
const user = await userService.create(request.body, { transaction })
|
|
289
|
-
const profile = await profileService.create(user.id, { transaction })
|
|
290
|
-
|
|
291
|
-
await transaction.commit()
|
|
292
|
-
reply.resolve({ user, profile }, ModuleOutcome.Created)
|
|
293
|
-
} catch (error) {
|
|
294
|
-
await transaction.rollback()
|
|
295
|
-
reply.reject(error)
|
|
296
|
-
}
|
|
297
|
-
})
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Module Composition
|
|
301
|
-
|
|
302
|
-
```typescript
|
|
303
|
-
// Base module
|
|
304
|
-
const baseModule = module(baseRoute, (ref) => async (request, reply) => {
|
|
305
|
-
// Base functionality
|
|
306
|
-
const result = await processBase(request)
|
|
307
|
-
reply.resolve(result)
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
// Elevated module with additional features
|
|
311
|
-
const elevatedModules = elevate([baseModule], 'base-route', (ref) => async (request, reply) => {
|
|
312
|
-
// Enhanced functionality
|
|
313
|
-
const enhanced = await enhanceProcessing(request)
|
|
314
|
-
const result = await processBase(enhanced)
|
|
315
|
-
reply.resolve(result)
|
|
316
|
-
}, {
|
|
317
|
-
fixer: 'enhanced-error-handler'
|
|
318
|
-
})
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### Module Factory Pattern
|
|
322
|
-
|
|
323
|
-
```typescript
|
|
324
|
-
const createCrudModule = <T>(
|
|
325
|
-
resource: string,
|
|
326
|
-
service: CrudService<T>
|
|
327
|
-
) => {
|
|
328
|
-
const crudRoute = route({
|
|
329
|
-
path: `/${resource}/:id?`,
|
|
330
|
-
method: RouteMethod.GET,
|
|
331
|
-
alias: `${resource}-crud`
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
return module(crudRoute, (ref) => async (request, reply) => {
|
|
335
|
-
const { params, query, body } = request
|
|
336
|
-
|
|
337
|
-
switch (request.method) {
|
|
338
|
-
case 'GET':
|
|
339
|
-
if (params.id) {
|
|
340
|
-
const item = await service.get(params.id)
|
|
341
|
-
reply.resolve(item)
|
|
342
|
-
} else {
|
|
343
|
-
const items = await service.list(query)
|
|
344
|
-
reply.resolve(items)
|
|
345
|
-
}
|
|
346
|
-
break
|
|
347
|
-
|
|
348
|
-
case 'POST':
|
|
349
|
-
const created = await service.create(body)
|
|
350
|
-
reply.resolve(created, ModuleOutcome.Created)
|
|
351
|
-
break
|
|
352
|
-
|
|
353
|
-
case 'PUT':
|
|
354
|
-
const updated = await service.update(params.id, body)
|
|
355
|
-
reply.resolve(updated)
|
|
356
|
-
break
|
|
357
|
-
|
|
358
|
-
case 'DELETE':
|
|
359
|
-
await service.delete(params.id)
|
|
360
|
-
reply.resolve(null, ModuleOutcome.Finished)
|
|
361
|
-
break
|
|
362
|
-
|
|
363
|
-
default:
|
|
364
|
-
reply.reject(new MethodNotAllowedError())
|
|
365
|
-
}
|
|
366
|
-
})
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// Usage
|
|
370
|
-
const userModule = createCrudModule('users', userService)
|
|
371
|
-
const productModule = createCrudModule('products', productService)
|
|
7
|
+
```diff
|
|
8
|
+
- import type { ServerModule, ModuleOptions } from '@owlmeans/server-module'
|
|
9
|
+
+ import type { ServerEntrypoint, EntrypointOptions } from '@owlmeans/server-entrypoint'
|
|
372
10
|
```
|
|
373
11
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
await validateRequest(request)
|
|
380
|
-
await logRequest(request)
|
|
381
|
-
|
|
382
|
-
// Main processing
|
|
383
|
-
const result = await processRequest(request)
|
|
384
|
-
|
|
385
|
-
// Post-processing middleware
|
|
386
|
-
await logResponse(result)
|
|
387
|
-
await cacheResponse(request, result)
|
|
388
|
-
|
|
389
|
-
reply.resolve(result)
|
|
390
|
-
})
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
### Error Handling Patterns
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
// Global error fixer
|
|
397
|
-
const globalFixer: FixerService = {
|
|
398
|
-
alias: 'global-error-fixer',
|
|
399
|
-
initialized: true,
|
|
400
|
-
|
|
401
|
-
handle: (reply, error) => {
|
|
402
|
-
// Log error
|
|
403
|
-
console.error('Module error:', error)
|
|
404
|
-
|
|
405
|
-
// Transform known errors
|
|
406
|
-
if (error.name === 'ValidationError') {
|
|
407
|
-
reply.reject(new BadRequestError(error.message))
|
|
408
|
-
} else if (error.name === 'NotFoundError') {
|
|
409
|
-
reply.reject(new NotFoundError(error.message))
|
|
410
|
-
} else {
|
|
411
|
-
// Generic error for unknown issues
|
|
412
|
-
reply.reject(new InternalServerError('An unexpected error occurred'))
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// Module with error handling
|
|
418
|
-
const robustModule = module(route, (ref) => async (request, reply) => {
|
|
419
|
-
try {
|
|
420
|
-
const result = await riskyOperation(request)
|
|
421
|
-
reply.resolve(result)
|
|
422
|
-
} catch (error) {
|
|
423
|
-
// Let fixer handle the error
|
|
424
|
-
throw error
|
|
425
|
-
}
|
|
426
|
-
}, {
|
|
427
|
-
fixer: 'global-error-fixer'
|
|
428
|
-
})
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
## Advanced Features
|
|
432
|
-
|
|
433
|
-
### Module Chaining
|
|
434
|
-
|
|
435
|
-
```typescript
|
|
436
|
-
const chainModules = (modules: ServerModule<any>[]) => {
|
|
437
|
-
return modules.reduce((chain, module, index) => {
|
|
438
|
-
const nextModule = modules[index + 1]
|
|
439
|
-
|
|
440
|
-
if (nextModule) {
|
|
441
|
-
// Chain modules together
|
|
442
|
-
const originalHandler = module.handle
|
|
443
|
-
module.handle = async (request, reply) => {
|
|
444
|
-
const result = await originalHandler(request, reply)
|
|
445
|
-
|
|
446
|
-
// Pass result to next module
|
|
447
|
-
if (result) {
|
|
448
|
-
request.body = result
|
|
449
|
-
return nextModule.handle(request, reply)
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
return result
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
return module
|
|
457
|
-
})
|
|
458
|
-
}
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
### Dynamic Module Loading
|
|
462
|
-
|
|
463
|
-
```typescript
|
|
464
|
-
const loadModuleFromConfig = async (config: ModuleConfig) => {
|
|
465
|
-
const route = await loadRoute(config.routeId)
|
|
466
|
-
const handler = await loadHandler(config.handlerId)
|
|
467
|
-
|
|
468
|
-
return module(route, handler, {
|
|
469
|
-
fixer: config.errorHandler,
|
|
470
|
-
guards: config.guards
|
|
471
|
-
})
|
|
472
|
-
}
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
### Module Testing
|
|
476
|
-
|
|
477
|
-
```typescript
|
|
478
|
-
import { createTestContext } from '@owlmeans/server-context'
|
|
479
|
-
|
|
480
|
-
describe('User Module', () => {
|
|
481
|
-
let context: ServerContext
|
|
482
|
-
let userModule: ServerModule<any>
|
|
483
|
-
|
|
484
|
-
beforeEach(() => {
|
|
485
|
-
context = createTestContext(testConfig)
|
|
486
|
-
userModule = module(userRoute, userHandler)
|
|
487
|
-
userModule.ctx = context
|
|
488
|
-
})
|
|
489
|
-
|
|
490
|
-
it('should handle user creation', async () => {
|
|
491
|
-
const request = {
|
|
492
|
-
method: 'POST',
|
|
493
|
-
body: { name: 'John Doe', email: 'john@example.com' },
|
|
494
|
-
params: {},
|
|
495
|
-
query: {},
|
|
496
|
-
headers: {}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const reply = createMockReply()
|
|
500
|
-
await userModule.handle(request, reply)
|
|
501
|
-
|
|
502
|
-
expect(reply.resolved).toBe(true)
|
|
503
|
-
expect(reply.value).toHaveProperty('id')
|
|
504
|
-
})
|
|
505
|
-
})
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
## Integration with OwlMeans Ecosystem
|
|
509
|
-
|
|
510
|
-
The `@owlmeans/server-module` package integrates with:
|
|
511
|
-
|
|
512
|
-
- **@owlmeans/module**: Base module system and interfaces
|
|
513
|
-
- **@owlmeans/server-route**: Server routing and path handling
|
|
514
|
-
- **@owlmeans/context**: Dependency injection and service access
|
|
515
|
-
- **@owlmeans/server-context**: Server-specific context features
|
|
516
|
-
- **@owlmeans/auth-common**: Authentication and authorization
|
|
517
|
-
- **@owlmeans/resource**: Data persistence and management
|
|
518
|
-
- **@owlmeans/error**: Error handling and transformation
|
|
519
|
-
|
|
520
|
-
## Best Practices
|
|
521
|
-
|
|
522
|
-
### Module Design
|
|
523
|
-
- Keep modules focused on single responsibilities
|
|
524
|
-
- Use descriptive aliases for easy identification
|
|
525
|
-
- Implement proper error handling in all handlers
|
|
526
|
-
- Validate input data before processing
|
|
527
|
-
|
|
528
|
-
### Performance
|
|
529
|
-
- Cache frequently accessed data
|
|
530
|
-
- Use streaming for large response payloads
|
|
531
|
-
- Implement proper pagination for list operations
|
|
532
|
-
- Monitor module execution times
|
|
533
|
-
|
|
534
|
-
### Security
|
|
535
|
-
- Always validate and sanitize input data
|
|
536
|
-
- Use appropriate authentication guards
|
|
537
|
-
- Implement proper authorization checks
|
|
538
|
-
- Log security-relevant events
|
|
539
|
-
|
|
540
|
-
### Testing
|
|
541
|
-
- Write unit tests for module handlers
|
|
542
|
-
- Use test contexts for isolated testing
|
|
543
|
-
- Mock external dependencies appropriately
|
|
544
|
-
- Test error scenarios thoroughly
|
|
12
|
+
Type renames:
|
|
13
|
+
- `ServerModule` → `ServerEntrypoint`
|
|
14
|
+
- `ModuleOptions` → `EntrypointOptions`
|
|
15
|
+
- `ModuleRef` → `EntrypointRef`
|
|
16
|
+
- `RefedModuleHandler` → `RefedEntrypointHandler`
|
|
545
17
|
|
|
546
|
-
|
|
18
|
+
See [`@owlmeans/server-entrypoint`](../server-entrypoint) for full documentation.
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
export
|
|
1
|
+
export * from '@owlmeans/server-entrypoint';
|
|
2
|
+
/** @deprecated use `entrypoint()` from @owlmeans/server-entrypoint */
|
|
3
|
+
export { entrypoint as module } from '@owlmeans/server-entrypoint';
|
|
4
|
+
/** @deprecated use ServerEntrypoint */
|
|
5
|
+
export type { ServerEntrypoint as ServerModule } from '@owlmeans/server-entrypoint';
|
|
6
|
+
/** @deprecated use EntrypointOptions */
|
|
7
|
+
export type { EntrypointOptions as ModuleOptions } from '@owlmeans/server-entrypoint';
|
|
8
|
+
/** @deprecated use EntrypointRef */
|
|
9
|
+
export type { EntrypointRef as ModuleRef } from '@owlmeans/server-entrypoint';
|
|
10
|
+
/** @deprecated use RefedEntrypointHandler */
|
|
11
|
+
export type { RefedEntrypointHandler as RefedModuleHandler } from '@owlmeans/server-entrypoint';
|
|
4
12
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,6BAA6B,CAAA;AAE3C,sEAAsE;AACtE,OAAO,EAAE,UAAU,IAAI,MAAM,EAAE,MAAM,6BAA6B,CAAA;AAElE,uCAAuC;AACvC,YAAY,EAAE,gBAAgB,IAAI,YAAY,EAAE,MAAM,6BAA6B,CAAA;AACnF,wCAAwC;AACxC,YAAY,EAAE,iBAAiB,IAAI,aAAa,EAAE,MAAM,6BAA6B,CAAA;AACrF,oCAAoC;AACpC,YAAY,EAAE,aAAa,IAAI,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAC7E,6CAA6C;AAC7C,YAAY,EAAE,sBAAsB,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAA"}
|
package/build/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export * from '
|
|
2
|
-
|
|
1
|
+
export * from '@owlmeans/server-entrypoint';
|
|
2
|
+
/** @deprecated use `entrypoint()` from @owlmeans/server-entrypoint */
|
|
3
|
+
export { entrypoint as module } from '@owlmeans/server-entrypoint';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,6BAA6B,CAAA;AAE3C,sEAAsE;AACtE,OAAO,EAAE,UAAU,IAAI,MAAM,EAAE,MAAM,6BAA6B,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/server-module",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"license": "MIT",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"scripts": {
|
|
6
7
|
"build": "tsc -b",
|
|
@@ -20,15 +21,13 @@
|
|
|
20
21
|
}
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
|
-
"@owlmeans/
|
|
24
|
-
"@owlmeans/module": "^0.1.1",
|
|
25
|
-
"@owlmeans/route": "^0.1.1",
|
|
26
|
-
"@owlmeans/server-route": "^0.1.1"
|
|
24
|
+
"@owlmeans/server-entrypoint": "^0.1.3"
|
|
27
25
|
},
|
|
28
26
|
"devDependencies": {
|
|
27
|
+
"@owlmeans/dep-config": "workspace:*",
|
|
29
28
|
"@types/node": "^24.10.1",
|
|
30
29
|
"nodemon": "^3.1.11",
|
|
31
|
-
"typescript": "^
|
|
30
|
+
"typescript": "^6.0.2"
|
|
32
31
|
},
|
|
33
32
|
"publishConfig": {
|
|
34
33
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export * from '@owlmeans/server-entrypoint'
|
|
3
|
+
|
|
4
|
+
/** @deprecated use `entrypoint()` from @owlmeans/server-entrypoint */
|
|
5
|
+
export { entrypoint as module } from '@owlmeans/server-entrypoint'
|
|
6
|
+
|
|
7
|
+
/** @deprecated use ServerEntrypoint */
|
|
8
|
+
export type { ServerEntrypoint as ServerModule } from '@owlmeans/server-entrypoint'
|
|
9
|
+
/** @deprecated use EntrypointOptions */
|
|
10
|
+
export type { EntrypointOptions as ModuleOptions } from '@owlmeans/server-entrypoint'
|
|
11
|
+
/** @deprecated use EntrypointRef */
|
|
12
|
+
export type { EntrypointRef as ModuleRef } from '@owlmeans/server-entrypoint'
|
|
13
|
+
/** @deprecated use RefedEntrypointHandler */
|
|
14
|
+
export type { RefedEntrypointHandler as RefedModuleHandler } from '@owlmeans/server-entrypoint'
|
package/tsconfig.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": [
|
|
3
|
-
"
|
|
3
|
+
"@owlmeans/dep-config/tsconfig.base.json"
|
|
4
4
|
],
|
|
5
5
|
"compilerOptions": {
|
|
6
|
-
"rootDir": "./src/",
|
|
7
|
-
"outDir": "./build/"
|
|
8
|
-
"moduleResolution": "Bundler"
|
|
6
|
+
"rootDir": "./src/",
|
|
7
|
+
"outDir": "./build/"
|
|
9
8
|
},
|
|
10
9
|
"exclude": [
|
|
11
10
|
"./dist/**/*",
|
|
12
11
|
"./build/**/*",
|
|
13
12
|
"./*.ts"
|
|
14
13
|
]
|
|
15
|
-
}
|
|
14
|
+
}
|
package/src/helper.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { ServerModule, ModuleOptions, RefedModuleHandler } from './types.js'
|
|
2
|
-
import { module } from './module.js'
|
|
3
|
-
import { isServerRouteModel } from '@owlmeans/server-route'
|
|
4
|
-
import { createBasicGuard } from './utils/helper.js'
|
|
5
|
-
import type { CommonModule } from '@owlmeans/module'
|
|
6
|
-
|
|
7
|
-
export const elevate = <R>(
|
|
8
|
-
modules: (CommonModule | ServerModule<R>)[],
|
|
9
|
-
alias: string,
|
|
10
|
-
handler?: RefedModuleHandler<R> | boolean | ModuleOptions<R>,
|
|
11
|
-
opts?: boolean | ModuleOptions<R>
|
|
12
|
-
): ServerModule<R>[] => {
|
|
13
|
-
const idx = modules.findIndex(({ route }) => route.route.alias === alias)
|
|
14
|
-
if (idx === -1) {
|
|
15
|
-
throw new SyntaxError(`Module with alias ${alias} not present`)
|
|
16
|
-
}
|
|
17
|
-
if (typeof handler === 'boolean') {
|
|
18
|
-
opts = handler
|
|
19
|
-
handler = undefined
|
|
20
|
-
}
|
|
21
|
-
if (typeof handler === 'object' && typeof handler !== 'function') {
|
|
22
|
-
opts = handler
|
|
23
|
-
handler = undefined
|
|
24
|
-
}
|
|
25
|
-
const force = typeof opts === 'object' && opts.force
|
|
26
|
-
if (isServerRouteModel(modules[idx].route) && !force) {
|
|
27
|
-
throw new SyntaxError(`Module with alias ${alias} is elready elevated`)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
modules[idx] = module(
|
|
31
|
-
modules[idx], handler, typeof opts === 'boolean' ? { intermediate: opts } : opts
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
return modules as ServerModule<R>[]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const guard = <R>(guard: string, opts?: ModuleOptions<R>): ModuleOptions<R> =>
|
|
38
|
-
({ ...createBasicGuard(guard, opts) })
|
package/src/module.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { ServerRouteModel } from '@owlmeans/server-route'
|
|
2
|
-
import type { ServerModule, ModuleOptions, ModuleRef, RefedModuleHandler } from './types.js'
|
|
3
|
-
import { isModule, makeCommonModule } from './utils/module.js'
|
|
4
|
-
import { isServerRouteModel, route } from '@owlmeans/server-route'
|
|
5
|
-
import type { CommonModule } from '@owlmeans/module'
|
|
6
|
-
import type { CommonRouteModel } from '@owlmeans/route'
|
|
7
|
-
import type { BasicContext } from '@owlmeans/context'
|
|
8
|
-
import { prependBase } from '@owlmeans/route/utils'
|
|
9
|
-
|
|
10
|
-
export const module = <R>(
|
|
11
|
-
arg: CommonModule | ServerRouteModel<R> | CommonRouteModel, handler?: RefedModuleHandler<R>, opts?: ModuleOptions<R>
|
|
12
|
-
): ServerModule<R> => {
|
|
13
|
-
const moduleHandle: ModuleRef<R> = { ref: undefined }
|
|
14
|
-
|
|
15
|
-
let _module: ServerModule<R>
|
|
16
|
-
|
|
17
|
-
if (isModule(arg)) {
|
|
18
|
-
const routeModel = route(arg.route, opts?.intermediate ?? false, opts?.routeOptions)
|
|
19
|
-
_module = arg as ServerModule<R>
|
|
20
|
-
// _module = makeCommonModule(routeModel, {
|
|
21
|
-
// ...opts,
|
|
22
|
-
// guards: [...(arg.guards ?? []), ...(opts?.guards ?? [])],
|
|
23
|
-
// gate: opts?.gate ?? arg.gate,
|
|
24
|
-
// gateParams: opts?.gateParams ?? arg.gateParams,
|
|
25
|
-
// }) as ServerModule<R>
|
|
26
|
-
_module.route = routeModel
|
|
27
|
-
_module.filter = opts?.filter ?? arg.filter
|
|
28
|
-
_module.guards = [...(arg.guards ?? []), ...(opts?.guards ?? [])]
|
|
29
|
-
_module.gate = opts?.gate ?? arg.gate
|
|
30
|
-
_module.gateParams = opts?.gateParams ?? arg.gateParams
|
|
31
|
-
} else if (isServerRouteModel(arg)) {
|
|
32
|
-
_module = makeCommonModule(arg, { ...opts }) as ServerModule<R>
|
|
33
|
-
_module.route = arg
|
|
34
|
-
} else {
|
|
35
|
-
const _route = route(arg, opts?.intermediate ?? false, opts?.routeOptions)
|
|
36
|
-
_module = makeCommonModule(_route, { ...opts }) as ServerModule<R>
|
|
37
|
-
_module.route = _route
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
_module.fixer = opts?.fixer
|
|
41
|
-
if (handler != null) {
|
|
42
|
-
_module.handle = handler(moduleHandle)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
_module.reinitializeContext = <T>(context: BasicContext<any>) => {
|
|
46
|
-
const newModule = module(arg, handler, opts)
|
|
47
|
-
newModule.ctx = context
|
|
48
|
-
|
|
49
|
-
return newModule as T
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
_module.getPath = () => prependBase(_module.route.route)
|
|
53
|
-
|
|
54
|
-
moduleHandle.ref = _module
|
|
55
|
-
|
|
56
|
-
return _module
|
|
57
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { ServerRouteModel, ServerRouteOptions } from '@owlmeans/server-route'
|
|
2
|
-
import type { CommonModule, ModuleHandler, CommonModuleOptions } from '@owlmeans/module'
|
|
3
|
-
import type { Service } from '@owlmeans/context'
|
|
4
|
-
|
|
5
|
-
export interface ServerModule<R> extends CommonModule {
|
|
6
|
-
route: ServerRouteModel<R>
|
|
7
|
-
fixer?: string
|
|
8
|
-
handle: ModuleHandler
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface ModuleOptions<R> extends CommonModuleOptions {
|
|
12
|
-
/**
|
|
13
|
-
* Force module to be elevated even if it is already elevated
|
|
14
|
-
*/
|
|
15
|
-
force?: boolean
|
|
16
|
-
fixer?: string
|
|
17
|
-
intermediate?: boolean
|
|
18
|
-
routeOptions?: ServerRouteOptions<R>
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface FixerService extends Service {
|
|
22
|
-
handle: <R>(reply: R, error: Error) => void
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ModuleRef<R> {
|
|
26
|
-
ref?: ServerModule<R>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface RefedModuleHandler<R = {}> {
|
|
30
|
-
(ref: ModuleRef<R>): ModuleHandler
|
|
31
|
-
}
|
package/src/utils/helper.ts
DELETED
package/src/utils/index.ts
DELETED
package/src/utils/module.ts
DELETED