@ooneex/controller 0.0.1 → 0.4.0

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/README.md CHANGED
@@ -1 +1,373 @@
1
- # @ooneex/router
1
+ # @ooneex/controller
2
+
3
+ Base controller types and interfaces for handling HTTP requests and responses in Ooneex applications. This package provides the foundational `IController` interface and context types that define how controllers interact with requests, responses, and framework services.
4
+
5
+ ![Bun](https://img.shields.io/badge/Bun-Compatible-orange?style=flat-square&logo=bun)
6
+ ![Deno](https://img.shields.io/badge/Deno-Compatible-blue?style=flat-square&logo=deno)
7
+ ![Node.js](https://img.shields.io/badge/Node.js-Compatible-green?style=flat-square&logo=node.js)
8
+ ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)
9
+ ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)
10
+
11
+ ## Features
12
+
13
+ ✅ **Controller Interface** - Standard interface for all HTTP controllers
14
+
15
+ ✅ **Rich Context** - Access to request, response, logger, cache, database, and more
16
+
17
+ ✅ **Type-Safe** - Full TypeScript support with generic type parameters
18
+
19
+ ✅ **Framework Integration** - Works seamlessly with routing, middleware, and DI container
20
+
21
+ ✅ **Service Access** - Built-in access to analytics, storage, mailer, and other services
22
+
23
+ ## Installation
24
+
25
+ ### Bun
26
+ ```bash
27
+ bun add @ooneex/controller
28
+ ```
29
+
30
+ ### pnpm
31
+ ```bash
32
+ pnpm add @ooneex/controller
33
+ ```
34
+
35
+ ### Yarn
36
+ ```bash
37
+ yarn add @ooneex/controller
38
+ ```
39
+
40
+ ### npm
41
+ ```bash
42
+ npm install @ooneex/controller
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ ### Basic Controller
48
+
49
+ ```typescript
50
+ import { Route } from '@ooneex/routing';
51
+ import type { IController, ContextType } from '@ooneex/controller';
52
+ import type { IResponse } from '@ooneex/http-response';
53
+
54
+ @Route.http({
55
+ name: 'api.users.list',
56
+ path: '/api/users',
57
+ method: 'GET',
58
+ description: 'List all users'
59
+ })
60
+ class UserListController implements IController {
61
+ public async index(context: ContextType): Promise<IResponse> {
62
+ return context.response.json({
63
+ users: [
64
+ { id: 1, name: 'John' },
65
+ { id: 2, name: 'Jane' }
66
+ ]
67
+ });
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### Controller with Typed Configuration
73
+
74
+ ```typescript
75
+ import { Route } from '@ooneex/routing';
76
+ import type { IController, ContextType, ContextConfigType } from '@ooneex/controller';
77
+ import type { IResponse } from '@ooneex/http-response';
78
+
79
+ interface UserShowConfig extends ContextConfigType {
80
+ params: { id: string };
81
+ queries: { include?: string };
82
+ payload: Record<string, never>;
83
+ response: { user: { id: string; name: string; email: string } };
84
+ }
85
+
86
+ @Route.http({
87
+ name: 'api.users.show',
88
+ path: '/api/users/:id',
89
+ method: 'GET',
90
+ description: 'Get user by ID'
91
+ })
92
+ class UserShowController implements IController<UserShowConfig> {
93
+ public async index(context: ContextType<UserShowConfig>): Promise<IResponse<UserShowConfig['response']>> {
94
+ const { id } = context.params;
95
+
96
+ // TypeScript knows params.id is a string
97
+ const user = await this.findUser(id);
98
+
99
+ return context.response.json({ user });
100
+ }
101
+ }
102
+ ```
103
+
104
+ ### Accessing Context Services
105
+
106
+ ```typescript
107
+ import { Route } from '@ooneex/routing';
108
+ import type { IController, ContextType } from '@ooneex/controller';
109
+
110
+ @Route.http({
111
+ name: 'api.products.create',
112
+ path: '/api/products',
113
+ method: 'POST',
114
+ description: 'Create a product'
115
+ })
116
+ class ProductCreateController implements IController {
117
+ public async index(context: ContextType): Promise<IResponse> {
118
+ const {
119
+ logger, // Logging service
120
+ analytics, // PostHog analytics
121
+ cache, // Redis or filesystem cache
122
+ storage, // File storage (Cloudflare R2, Bunny, filesystem)
123
+ database, // TypeORM database connection
124
+ mailer, // Email service (Resend, Nodemailer)
125
+ request, // HTTP request with parsed data
126
+ response, // HTTP response builder
127
+ params, // URL parameters
128
+ payload, // Request body
129
+ queries, // Query string parameters
130
+ method, // HTTP method
131
+ header, // Request headers
132
+ files, // Uploaded files
133
+ ip, // Client IP address
134
+ host, // Request host
135
+ language, // Detected language
136
+ user, // Authenticated user (if any)
137
+ app // Application environment
138
+ } = context;
139
+
140
+ // Log the action
141
+ logger.info('Creating product', { userId: user?.id });
142
+
143
+ // Track analytics
144
+ analytics?.capture({
145
+ id: user?.id || 'anonymous',
146
+ event: 'product_created'
147
+ });
148
+
149
+ // Cache the result
150
+ await cache?.set('latest_product', payload, 300);
151
+
152
+ return response.json({ success: true });
153
+ }
154
+ }
155
+ ```
156
+
157
+ ## API Reference
158
+
159
+ ### Interfaces
160
+
161
+ #### `IController<T>`
162
+
163
+ The main interface that all HTTP controllers must implement.
164
+
165
+ ```typescript
166
+ interface IController<T extends ContextConfigType = ContextConfigType> {
167
+ index: (context: ContextType<T>) => Promise<IResponse<T['response']>> | IResponse<T['response']>;
168
+ }
169
+ ```
170
+
171
+ **Methods:**
172
+
173
+ ##### `index(context: ContextType<T>): Promise<IResponse> | IResponse`
174
+
175
+ The main handler method called when a route is matched.
176
+
177
+ **Parameters:**
178
+ - `context` - The request context containing all services and request data
179
+
180
+ **Returns:** HTTP response (sync or async)
181
+
182
+ ### Types
183
+
184
+ #### `ContextConfigType`
185
+
186
+ Configuration type for defining controller context shape.
187
+
188
+ ```typescript
189
+ type ContextConfigType = {
190
+ response: Record<string, unknown>;
191
+ } & RequestConfigType;
192
+ ```
193
+
194
+ **Properties:**
195
+ - `response` - Shape of the response data
196
+ - `params` - URL parameter types (from RequestConfigType)
197
+ - `payload` - Request body types (from RequestConfigType)
198
+ - `queries` - Query string types (from RequestConfigType)
199
+
200
+ #### `ContextType<T>`
201
+
202
+ The full context object passed to controller methods.
203
+
204
+ ```typescript
205
+ type ContextType<T extends ContextConfigType = ContextConfigType> = {
206
+ logger: ILogger<Record<string, ScalarType>> | ILogger<LogsEntity>;
207
+ analytics?: IAnalytics;
208
+ cache?: ICache;
209
+ storage?: IStorage;
210
+ database?: IDatabase;
211
+ mailer?: IMailer;
212
+ app: {
213
+ env: IAppEnv;
214
+ };
215
+ response: IResponse<T['response']>;
216
+ request: IRequest<{ params: T['params']; payload: T['payload']; queries: T['queries'] }>;
217
+ params: T['params'];
218
+ payload: T['payload'];
219
+ queries: T['queries'];
220
+ method: HttpMethodType;
221
+ header: Header;
222
+ files: Record<string, IRequestFile>;
223
+ ip: string | null;
224
+ host: string;
225
+ language: LocaleInfoType;
226
+ user: IUser | null;
227
+ };
228
+ ```
229
+
230
+ #### `ControllerClassType`
231
+
232
+ Type for controller class constructors (used internally by the framework).
233
+
234
+ ```typescript
235
+ type ControllerClassType = new (...args: any[]) => IController<any>;
236
+ ```
237
+
238
+ ## Advanced Usage
239
+
240
+ ### Error Handling in Controllers
241
+
242
+ ```typescript
243
+ import { Route } from '@ooneex/routing';
244
+ import { NotFoundException, BadRequestException } from '@ooneex/exception';
245
+ import type { IController, ContextType } from '@ooneex/controller';
246
+
247
+ @Route.http({
248
+ name: 'api.orders.show',
249
+ path: '/api/orders/:id',
250
+ method: 'GET',
251
+ description: 'Get order by ID'
252
+ })
253
+ class OrderShowController implements IController {
254
+ public async index(context: ContextType): Promise<IResponse> {
255
+ const { id } = context.params;
256
+
257
+ if (!id) {
258
+ throw new BadRequestException('Order ID is required');
259
+ }
260
+
261
+ const order = await this.orderRepository.findById(id);
262
+
263
+ if (!order) {
264
+ throw new NotFoundException('Order not found', {
265
+ data: { orderId: id }
266
+ });
267
+ }
268
+
269
+ return context.response.json({ order });
270
+ }
271
+ }
272
+ ```
273
+
274
+ ### File Upload Handling
275
+
276
+ ```typescript
277
+ import { Route } from '@ooneex/routing';
278
+ import type { IController, ContextType } from '@ooneex/controller';
279
+
280
+ @Route.http({
281
+ name: 'api.files.upload',
282
+ path: '/api/files',
283
+ method: 'POST',
284
+ description: 'Upload a file'
285
+ })
286
+ class FileUploadController implements IController {
287
+ public async index(context: ContextType): Promise<IResponse> {
288
+ const { files, storage, user } = context;
289
+
290
+ const uploadedFile = files['document'];
291
+
292
+ if (!uploadedFile) {
293
+ return context.response.exception('No file uploaded', { status: 400 });
294
+ }
295
+
296
+ // Validate file type
297
+ if (!uploadedFile.isImage() && !uploadedFile.isPdf()) {
298
+ return context.response.exception('Invalid file type', { status: 400 });
299
+ }
300
+
301
+ // Store the file
302
+ const key = `users/${user?.id}/${uploadedFile.name}`;
303
+ await storage?.putFile(key, uploadedFile.path);
304
+
305
+ return context.response.json({
306
+ uploaded: true,
307
+ key,
308
+ size: uploadedFile.size,
309
+ type: uploadedFile.type
310
+ });
311
+ }
312
+ }
313
+ ```
314
+
315
+ ### Language-Aware Responses
316
+
317
+ ```typescript
318
+ import { Route } from '@ooneex/routing';
319
+ import type { IController, ContextType } from '@ooneex/controller';
320
+
321
+ @Route.http({
322
+ name: 'api.greetings.get',
323
+ path: '/api/greetings',
324
+ method: 'GET',
325
+ description: 'Get greeting in user language'
326
+ })
327
+ class GreetingController implements IController {
328
+ private greetings: Record<string, string> = {
329
+ en: 'Hello!',
330
+ fr: 'Bonjour!',
331
+ es: '¡Hola!',
332
+ de: 'Hallo!'
333
+ };
334
+
335
+ public async index(context: ContextType): Promise<IResponse> {
336
+ const { language } = context;
337
+
338
+ const greeting = this.greetings[language.code] || this.greetings.en;
339
+
340
+ return context.response.json({
341
+ greeting,
342
+ language: language.code,
343
+ region: language.region
344
+ });
345
+ }
346
+ }
347
+ ```
348
+
349
+ ## License
350
+
351
+ This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
352
+
353
+ ## Contributing
354
+
355
+ Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
356
+
357
+ ### Development Setup
358
+
359
+ 1. Clone the repository
360
+ 2. Install dependencies: `bun install`
361
+ 3. Run tests: `bun run test`
362
+ 4. Build the project: `bun run build`
363
+
364
+ ### Guidelines
365
+
366
+ - Write tests for new features
367
+ - Follow the existing code style
368
+ - Update documentation for API changes
369
+ - Ensure all tests pass before submitting PR
370
+
371
+ ---
372
+
373
+ Made with ❤️ by the Ooneex team
package/dist/index.d.ts CHANGED
@@ -1,19 +1,18 @@
1
1
  import { IAnalytics } from "@ooneex/analytics";
2
2
  import { IAppEnv } from "@ooneex/app-env";
3
3
  import { ICache } from "@ooneex/cache";
4
- import { IDatabase, IRedisDatabaseAdapter } from "@ooneex/database";
4
+ import { IDatabase } from "@ooneex/database";
5
5
  import { Header } from "@ooneex/http-header";
6
6
  import { IRequest, RequestConfigType } from "@ooneex/http-request";
7
7
  import { IRequestFile } from "@ooneex/http-request-file";
8
8
  import { IResponse } from "@ooneex/http-response";
9
9
  import { ILogger, LogsEntity } from "@ooneex/logger";
10
10
  import { IMailer } from "@ooneex/mailer";
11
- import { IPermission } from "@ooneex/permission";
12
11
  import { IStorage } from "@ooneex/storage";
13
12
  import { LocaleInfoType } from "@ooneex/translation";
14
13
  import { HttpMethodType, ScalarType } from "@ooneex/types";
15
14
  import { IUser } from "@ooneex/user";
16
- type ControllerClassType = new (...args: any[]) => IController;
15
+ type ControllerClassType = new (...args: any[]) => IController<any>;
17
16
  interface IController<T extends ContextConfigType = ContextConfigType> {
18
17
  index: (context: ContextType<T>) => Promise<IResponse<T["response"]>> | IResponse<T["response"]>;
19
18
  }
@@ -24,13 +23,10 @@ type ContextType<T extends ContextConfigType = ContextConfigType> = {
24
23
  logger: ILogger<Record<string, ScalarType>> | ILogger<LogsEntity>;
25
24
  analytics?: IAnalytics;
26
25
  cache?: ICache;
27
- permission?: IPermission;
28
26
  storage?: IStorage;
29
27
  database?: IDatabase;
30
- redis?: IRedisDatabaseAdapter;
31
28
  mailer?: IMailer;
32
29
  app: {
33
- url: string;
34
30
  env: IAppEnv;
35
31
  };
36
32
  response: IResponse<T["response"]>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ooneex/controller",
3
- "description": "",
4
- "version": "0.0.1",
3
+ "description": "Base controller classes and decorators for handling HTTP requests and responses in Ooneex applications",
4
+ "version": "0.4.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -24,11 +24,8 @@
24
24
  "scripts": {
25
25
  "build": "bunup",
26
26
  "lint": "tsgo --noEmit && bunx biome lint",
27
- "publish:prod": "bun publish --tolerate-republish --access public",
28
- "publish:pack": "bun pm pack --destination ./dist",
29
- "publish:dry": "bun publish --dry-run"
27
+ "npm:publish": "bun publish --tolerate-republish --access public"
30
28
  },
31
- "dependencies": {},
32
29
  "devDependencies": {
33
30
  "@ooneex/analytics": "0.0.1",
34
31
  "@ooneex/app-env": "0.0.1",
@@ -40,11 +37,19 @@
40
37
  "@ooneex/http-response": "0.0.1",
41
38
  "@ooneex/logger": "0.0.1",
42
39
  "@ooneex/mailer": "0.0.1",
43
- "@ooneex/permission": "0.0.1",
44
40
  "@ooneex/storage": "0.0.1",
45
41
  "@ooneex/translation": "0.0.1",
46
42
  "@ooneex/types": "0.0.1",
47
43
  "@ooneex/user": "0.0.1"
48
44
  },
49
- "peerDependencies": {}
45
+ "keywords": [
46
+ "bun",
47
+ "controller",
48
+ "decorator",
49
+ "http",
50
+ "mvc",
51
+ "ooneex",
52
+ "routing",
53
+ "typescript"
54
+ ]
50
55
  }