@forgedevstack/harbor 1.0.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/README.md +927 -0
  3. package/dist/changelog/index.d.ts +3 -0
  4. package/dist/changelog/index.d.ts.map +1 -0
  5. package/dist/changelog/manager.d.ts +29 -0
  6. package/dist/changelog/manager.d.ts.map +1 -0
  7. package/dist/changelog/types.d.ts +41 -0
  8. package/dist/changelog/types.d.ts.map +1 -0
  9. package/dist/cli/index.d.ts +3 -0
  10. package/dist/cli/index.d.ts.map +1 -0
  11. package/dist/cli/index.js +43 -0
  12. package/dist/cli/index.js.map +1 -0
  13. package/dist/constants/config.const.d.ts +11 -0
  14. package/dist/constants/config.const.d.ts.map +1 -0
  15. package/dist/constants/defaults.const.d.ts +10 -0
  16. package/dist/constants/defaults.const.d.ts.map +1 -0
  17. package/dist/constants/http.const.d.ts +43 -0
  18. package/dist/constants/http.const.d.ts.map +1 -0
  19. package/dist/constants/index.d.ts +5 -0
  20. package/dist/constants/index.d.ts.map +1 -0
  21. package/dist/constants/validation.const.d.ts +35 -0
  22. package/dist/constants/validation.const.d.ts.map +1 -0
  23. package/dist/core/config.d.ts +6 -0
  24. package/dist/core/config.d.ts.map +1 -0
  25. package/dist/core/errorHandler.d.ts +25 -0
  26. package/dist/core/errorHandler.d.ts.map +1 -0
  27. package/dist/core/index.d.ts +6 -0
  28. package/dist/core/index.d.ts.map +1 -0
  29. package/dist/core/router.d.ts +68 -0
  30. package/dist/core/router.d.ts.map +1 -0
  31. package/dist/core/server.d.ts +4 -0
  32. package/dist/core/server.d.ts.map +1 -0
  33. package/dist/database/connection.d.ts +39 -0
  34. package/dist/database/connection.d.ts.map +1 -0
  35. package/dist/database/index.d.ts +28 -0
  36. package/dist/database/index.d.ts.map +1 -0
  37. package/dist/database/model.d.ts +118 -0
  38. package/dist/database/model.d.ts.map +1 -0
  39. package/dist/database/schema.d.ts +63 -0
  40. package/dist/database/schema.d.ts.map +1 -0
  41. package/dist/database/types.d.ts +270 -0
  42. package/dist/database/types.d.ts.map +1 -0
  43. package/dist/docker/index.d.ts +3 -0
  44. package/dist/docker/index.d.ts.map +1 -0
  45. package/dist/docker/index.js +2 -0
  46. package/dist/docker/index.js.map +1 -0
  47. package/dist/docker/manager.d.ts +21 -0
  48. package/dist/docker/manager.d.ts.map +1 -0
  49. package/dist/i18n/index.d.ts +38 -0
  50. package/dist/i18n/index.d.ts.map +1 -0
  51. package/dist/i18n/locales/en.d.ts +2 -0
  52. package/dist/i18n/locales/en.d.ts.map +1 -0
  53. package/dist/i18n/locales/he.d.ts +2 -0
  54. package/dist/i18n/locales/he.d.ts.map +1 -0
  55. package/dist/index.cjs.js +24 -0
  56. package/dist/index.cjs.js.map +1 -0
  57. package/dist/index.d.ts +21 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.es.js +2094 -0
  60. package/dist/index.es.js.map +1 -0
  61. package/dist/logger-D7aJSi62.mjs +102 -0
  62. package/dist/logger-D7aJSi62.mjs.map +1 -0
  63. package/dist/logger-DEnWXtpk.js +3 -0
  64. package/dist/logger-DEnWXtpk.js.map +1 -0
  65. package/dist/manager-B1UKMjXW.js +4 -0
  66. package/dist/manager-B1UKMjXW.js.map +1 -0
  67. package/dist/manager-B6vqJgEn.mjs +152 -0
  68. package/dist/manager-B6vqJgEn.mjs.map +1 -0
  69. package/dist/portal.d.ts +13 -0
  70. package/dist/portal.d.ts.map +1 -0
  71. package/dist/types/config.types.d.ts +83 -0
  72. package/dist/types/config.types.d.ts.map +1 -0
  73. package/dist/types/docker.types.d.ts +92 -0
  74. package/dist/types/docker.types.d.ts.map +1 -0
  75. package/dist/types/index.d.ts +7 -0
  76. package/dist/types/index.d.ts.map +1 -0
  77. package/dist/types/logger.types.d.ts +35 -0
  78. package/dist/types/logger.types.d.ts.map +1 -0
  79. package/dist/types/route.types.d.ts +78 -0
  80. package/dist/types/route.types.d.ts.map +1 -0
  81. package/dist/types/server.types.d.ts +67 -0
  82. package/dist/types/server.types.d.ts.map +1 -0
  83. package/dist/types/validation.types.d.ts +64 -0
  84. package/dist/types/validation.types.d.ts.map +1 -0
  85. package/dist/utils/helpers.d.ts +7 -0
  86. package/dist/utils/helpers.d.ts.map +1 -0
  87. package/dist/utils/httpLogger.d.ts +52 -0
  88. package/dist/utils/httpLogger.d.ts.map +1 -0
  89. package/dist/utils/index.d.ts +6 -0
  90. package/dist/utils/index.d.ts.map +1 -0
  91. package/dist/utils/logger.d.ts +6 -0
  92. package/dist/utils/logger.d.ts.map +1 -0
  93. package/dist/utils/object.d.ts +6 -0
  94. package/dist/utils/object.d.ts.map +1 -0
  95. package/dist/validation/index.d.ts +5 -0
  96. package/dist/validation/index.d.ts.map +1 -0
  97. package/dist/validation/index.js +2 -0
  98. package/dist/validation/index.js.map +1 -0
  99. package/dist/validation/mongo.d.ts +13 -0
  100. package/dist/validation/mongo.d.ts.map +1 -0
  101. package/dist/validation/paramValidators.d.ts +18 -0
  102. package/dist/validation/paramValidators.d.ts.map +1 -0
  103. package/dist/validation/validators.d.ts +9 -0
  104. package/dist/validation/validators.d.ts.map +1 -0
  105. package/harbor.config.example.json +72 -0
  106. package/package.json +107 -0
  107. package/templates/default/.eslintrc.json +45 -0
  108. package/templates/default/README.md +97 -0
  109. package/templates/default/constants/config.ts +26 -0
  110. package/templates/default/constants/http.ts +32 -0
  111. package/templates/default/constants/index.ts +3 -0
  112. package/templates/default/controllers/index.ts +6 -0
  113. package/templates/default/controllers/user.controller.ts +77 -0
  114. package/templates/default/env.example +22 -0
  115. package/templates/default/harbor.version.json +7 -0
  116. package/templates/default/models/index.ts +6 -0
  117. package/templates/default/models/user.model.ts +68 -0
  118. package/templates/default/package.json +44 -0
  119. package/templates/default/routes/index.ts +12 -0
  120. package/templates/default/routes/user.routes.ts +21 -0
  121. package/templates/default/server.ts +45 -0
  122. package/templates/default/services/index.ts +6 -0
  123. package/templates/default/services/user.service.ts +84 -0
  124. package/templates/default/tsconfig.json +35 -0
  125. package/templates/default/types/index.ts +57 -0
  126. package/templates/default/utils/asyncHandler.ts +14 -0
  127. package/templates/default/utils/index.ts +5 -0
  128. package/templates/default/utils/logger.ts +52 -0
  129. package/templates/default/utils/response.ts +24 -0
  130. package/templates/default/utils/validation.ts +23 -0
package/README.md ADDED
@@ -0,0 +1,927 @@
1
+ # Harbor 🚢
2
+
3
+ **The Pipeline for Node.js Backends**
4
+
5
+ Harbor is a complete backend framework that replaces Express routing, Mongoose ODM, and more. Fast server creation, route management, MongoDB integration, validation, Docker orchestration, and automatic error handling — all in one lightweight, TypeScript-first package.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/harbor.svg)](https://www.npmjs.com/package/harbor)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
+
11
+ ## Table of Contents
12
+
13
+ - [Features](#features)
14
+ - [Installation](#installation)
15
+ - [Quick Start](#quick-start)
16
+ - [Server Setup](#server-setup)
17
+ - [MongoDB Connection](#mongodb-connection)
18
+ - [Schema & Models](#schema--models)
19
+ - [Route Management](#route-management)
20
+ - [Validation](#validation)
21
+ - [Error Handling](#error-handling)
22
+ - [Middleware](#middleware)
23
+ - [Docker Manager](#docker-manager)
24
+ - [Configuration](#configuration)
25
+ - [i18n (Translations)](#i18n-translations)
26
+ - [API Reference](#api-reference)
27
+
28
+ ## Features
29
+
30
+ - 🚀 **Fast Server Creation** - Create a production-ready server with one function call
31
+ - 🛣️ **Route Management** - Fluent API with pre/post middleware, validation, and automatic error handling
32
+ - 🍃 **MongoDB ODM** - Full Mongoose replacement with Schema, Model, and all query methods
33
+ - ✅ **Validation** - Powerful request validation with Mongoose-compatible schemas
34
+ - 🐳 **Docker Manager** - Build, push, pull images and orchestrate containers
35
+ - 🌍 **i18n Support** - Built-in internationalization for all messages
36
+ - 📝 **Morgan-like Logger** - HTTP request logging with customizable formats
37
+ - ⚙️ **Config-Driven** - Centralized configuration via `harbor.config.json`
38
+ - 📘 **TypeScript First** - Full type definitions with excellent IntelliSense
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ # npm
44
+ npm install harbor
45
+
46
+ # yarn
47
+ yarn add harbor
48
+
49
+ # pnpm
50
+ pnpm add harbor
51
+ ```
52
+
53
+ ### Peer Dependencies
54
+
55
+ Harbor requires `mongodb` for database operations:
56
+
57
+ ```bash
58
+ npm install mongodb
59
+ ```
60
+
61
+ ## Quick Start
62
+
63
+ ### 1. Initialize Project
64
+
65
+ ```bash
66
+ npx harbor init
67
+ ```
68
+
69
+ This creates:
70
+ - `harbor.config.json` - Configuration file
71
+ - `src/server.ts` - Basic server setup
72
+
73
+ ### 2. Create Your Server
74
+
75
+ ```typescript
76
+ import { createServer, GET, POST, connect } from 'harbor';
77
+
78
+ // Connect to MongoDB
79
+ await connect('mongodb://localhost:27017/myapp');
80
+
81
+ // Create server
82
+ const server = createServer({ port: 3000 });
83
+
84
+ // Add routes
85
+ server.addRoute(
86
+ GET('/api/health', () => ({ status: 'ok', timestamp: new Date() }))
87
+ );
88
+
89
+ server.addRoute(
90
+ POST('/api/users', async (req) => {
91
+ const { email, name } = req.validated.body;
92
+ return { id: '123', email, name };
93
+ }, {
94
+ validation: {
95
+ body: {
96
+ email: { type: 'email', required: true },
97
+ name: { type: 'string', required: true, min: 2 }
98
+ }
99
+ }
100
+ })
101
+ );
102
+
103
+ // Server is running at http://localhost:3000
104
+ ```
105
+
106
+ ### 3. Run Your Server
107
+
108
+ ```bash
109
+ npx ts-node src/server.ts
110
+ ```
111
+
112
+ ## Server Setup
113
+
114
+ ### Basic Server
115
+
116
+ ```typescript
117
+ import { createServer } from 'harbor';
118
+
119
+ const server = createServer({
120
+ port: 3000, // Default: 3000
121
+ host: 'localhost', // Default: 'localhost'
122
+ configPath: './harbor.config.json',
123
+ autoStart: true, // Default: true
124
+ onReady: (info) => console.log(`Server ready on ${info.host}:${info.port}`),
125
+ onError: (error) => console.error('Server error:', error),
126
+ });
127
+ ```
128
+
129
+ ### Server Methods
130
+
131
+ ```typescript
132
+ // Add routes
133
+ server.addRoute(route);
134
+ server.addRoutes([route1, route2]);
135
+
136
+ // Add middleware
137
+ server.addMiddleware(middleware);
138
+
139
+ // Get Express app instance
140
+ const app = server.getApp();
141
+
142
+ // Graceful shutdown
143
+ await server.stop();
144
+ ```
145
+
146
+ ## MongoDB Connection
147
+
148
+ Harbor provides a complete Mongoose replacement. All the methods you know from Mongoose are available.
149
+
150
+ ### Connecting to MongoDB
151
+
152
+ ```typescript
153
+ import { connect, disconnect, connection } from 'harbor';
154
+
155
+ // Connect to MongoDB
156
+ await connect('mongodb://localhost:27017/myapp', {
157
+ maxPoolSize: 10,
158
+ serverSelectionTimeoutMS: 30000,
159
+ });
160
+
161
+ // Connection events
162
+ connection.on('connected', () => console.log('Connected!'));
163
+ connection.on('disconnected', () => console.log('Disconnected!'));
164
+ connection.on('error', (err) => console.error('Error:', err));
165
+
166
+ // Check connection state
167
+ console.log(connection.readyState); // 0: disconnected, 1: connected, 2: connecting
168
+
169
+ // Disconnect
170
+ await disconnect();
171
+ ```
172
+
173
+ ### Connection Options
174
+
175
+ ```typescript
176
+ await connect(uri, {
177
+ maxPoolSize: 10, // Maximum connections in pool
178
+ minPoolSize: 1, // Minimum connections
179
+ serverSelectionTimeoutMS: 30000,
180
+ socketTimeoutMS: 45000,
181
+ retryWrites: true,
182
+ w: 'majority',
183
+ authSource: 'admin',
184
+ replicaSet: 'rs0',
185
+ ssl: true,
186
+ tls: true,
187
+ });
188
+ ```
189
+
190
+ ## Schema & Models
191
+
192
+ ### Defining a Schema
193
+
194
+ ```typescript
195
+ import { Schema, model } from 'harbor';
196
+
197
+ // Define schema (same as Mongoose!)
198
+ const userSchema = new Schema({
199
+ email: {
200
+ type: 'String',
201
+ required: true,
202
+ unique: true,
203
+ lowercase: true,
204
+ match: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
205
+ },
206
+ password: {
207
+ type: 'String',
208
+ required: true,
209
+ minLength: 8
210
+ },
211
+ name: {
212
+ type: 'String',
213
+ required: true,
214
+ trim: true
215
+ },
216
+ role: {
217
+ type: 'String',
218
+ enum: ['user', 'admin', 'moderator'],
219
+ default: 'user'
220
+ },
221
+ age: {
222
+ type: 'Number',
223
+ min: 0,
224
+ max: 150
225
+ },
226
+ isActive: {
227
+ type: 'Boolean',
228
+ default: true
229
+ },
230
+ profile: {
231
+ bio: 'String',
232
+ avatar: 'String',
233
+ social: {
234
+ twitter: 'String',
235
+ github: 'String'
236
+ }
237
+ },
238
+ tags: ['String'],
239
+ createdAt: 'Date',
240
+ updatedAt: 'Date'
241
+ }, {
242
+ timestamps: true, // Auto-add createdAt/updatedAt
243
+ collection: 'users', // Collection name
244
+ versionKey: '__v', // Version key field
245
+ });
246
+ ```
247
+
248
+ ### Schema Types
249
+
250
+ All Mongoose schema types are supported:
251
+
252
+ - `String` - String values
253
+ - `Number` - Numeric values
254
+ - `Boolean` - true/false
255
+ - `Date` - Date objects
256
+ - `ObjectId` - MongoDB ObjectId
257
+ - `Array` - Arrays
258
+ - `Object` / `Mixed` - Any object
259
+ - `Buffer` - Binary data
260
+
261
+ ### Schema Options
262
+
263
+ ```typescript
264
+ const schema = new Schema(definition, {
265
+ timestamps: true, // Add createdAt/updatedAt
266
+ timestamps: { createdAt: 'created', updatedAt: 'modified' }, // Custom field names
267
+ collection: 'myCollection', // Collection name
268
+ strict: true, // Only save schema fields
269
+ versionKey: '__v', // Version key
270
+ _id: true, // Add _id field
271
+ autoIndex: true, // Auto-create indexes
272
+ minimize: true, // Remove empty objects
273
+ });
274
+ ```
275
+
276
+ ### Instance Methods
277
+
278
+ ```typescript
279
+ // Define instance methods
280
+ userSchema.methods.comparePassword = async function(password: string) {
281
+ return bcrypt.compare(password, this.password);
282
+ };
283
+
284
+ userSchema.methods.generateToken = function() {
285
+ return jwt.sign({ id: this._id }, SECRET);
286
+ };
287
+
288
+ // Or use the method() function
289
+ userSchema.method('fullName', function() {
290
+ return `${this.firstName} ${this.lastName}`;
291
+ });
292
+ ```
293
+
294
+ ### Static Methods
295
+
296
+ ```typescript
297
+ // Define static methods
298
+ userSchema.statics.findByEmail = function(email: string) {
299
+ return this.findOne({ email: email.toLowerCase() });
300
+ };
301
+
302
+ userSchema.statics.findActive = function() {
303
+ return this.find({ isActive: true });
304
+ };
305
+
306
+ // Or use the static() function
307
+ userSchema.static('findByRole', function(role: string) {
308
+ return this.find({ role });
309
+ });
310
+ ```
311
+
312
+ ### Virtuals
313
+
314
+ ```typescript
315
+ userSchema.virtual('fullName')
316
+ .get(function() {
317
+ return `${this.firstName} ${this.lastName}`;
318
+ })
319
+ .set(function(name: string) {
320
+ const [firstName, lastName] = name.split(' ');
321
+ this.firstName = firstName;
322
+ this.lastName = lastName;
323
+ });
324
+ ```
325
+
326
+ ### Middleware (Hooks)
327
+
328
+ ```typescript
329
+ // Pre-save hook
330
+ userSchema.pre('save', async function(next) {
331
+ if (this.isModified('password')) {
332
+ this.password = await bcrypt.hash(this.password, 10);
333
+ }
334
+ next();
335
+ });
336
+
337
+ // Post-save hook
338
+ userSchema.post('save', function(next) {
339
+ console.log('User saved:', this._id);
340
+ next();
341
+ });
342
+
343
+ // Query middleware
344
+ userSchema.pre('find', function(next) {
345
+ // Add filter to all find queries
346
+ this.where({ isDeleted: { $ne: true } });
347
+ next();
348
+ });
349
+ ```
350
+
351
+ ### Creating a Model
352
+
353
+ ```typescript
354
+ import { model } from 'harbor';
355
+
356
+ // Create model
357
+ const User = model('User', userSchema);
358
+
359
+ // With custom collection name
360
+ const User = model('User', userSchema, 'my_users');
361
+ ```
362
+
363
+ ## Query Methods
364
+
365
+ All Mongoose query methods are available:
366
+
367
+ ### Find Documents
368
+
369
+ ```typescript
370
+ // Find all
371
+ const users = await User.find();
372
+
373
+ // Find with filter
374
+ const admins = await User.find({ role: 'admin' });
375
+
376
+ // Find one
377
+ const user = await User.findOne({ email: 'john@example.com' });
378
+
379
+ // Find by ID
380
+ const user = await User.findById('507f1f77bcf86cd799439011');
381
+
382
+ // Query builder
383
+ const users = await User.find()
384
+ .where('age').gte(18).lte(65)
385
+ .where('role').in(['user', 'admin'])
386
+ .select('name email role')
387
+ .sort('-createdAt')
388
+ .skip(0)
389
+ .limit(10)
390
+ .lean();
391
+
392
+ // Chain methods
393
+ const users = await User.find({ isActive: true })
394
+ .select('name email')
395
+ .sort({ createdAt: -1 })
396
+ .limit(10);
397
+ ```
398
+
399
+ ### Create Documents
400
+
401
+ ```typescript
402
+ // Create single document
403
+ const user = await User.create({
404
+ email: 'john@example.com',
405
+ name: 'John Doe',
406
+ password: 'secret123'
407
+ });
408
+
409
+ // Create multiple documents
410
+ const users = await User.create([
411
+ { email: 'user1@example.com', name: 'User 1' },
412
+ { email: 'user2@example.com', name: 'User 2' }
413
+ ]);
414
+
415
+ // Insert many
416
+ const result = await User.insertMany([
417
+ { email: 'user1@example.com', name: 'User 1' },
418
+ { email: 'user2@example.com', name: 'User 2' }
419
+ ]);
420
+
421
+ // Using new + save
422
+ const user = User.new({ email: 'john@example.com', name: 'John' });
423
+ await user.save();
424
+ ```
425
+
426
+ ### Update Documents
427
+
428
+ ```typescript
429
+ // Update one
430
+ await User.updateOne(
431
+ { email: 'john@example.com' },
432
+ { $set: { name: 'John Smith' } }
433
+ );
434
+
435
+ // Update many
436
+ await User.updateMany(
437
+ { role: 'user' },
438
+ { $set: { isActive: true } }
439
+ );
440
+
441
+ // Find and update (returns document)
442
+ const user = await User.findOneAndUpdate(
443
+ { email: 'john@example.com' },
444
+ { $set: { name: 'John Smith' } },
445
+ { new: true } // Return updated document
446
+ );
447
+
448
+ // Find by ID and update
449
+ const user = await User.findByIdAndUpdate(
450
+ '507f1f77bcf86cd799439011',
451
+ { name: 'New Name' },
452
+ { new: true }
453
+ );
454
+
455
+ // Replace one
456
+ await User.replaceOne(
457
+ { email: 'john@example.com' },
458
+ { email: 'john@example.com', name: 'Replaced User' }
459
+ );
460
+ ```
461
+
462
+ ### Delete Documents
463
+
464
+ ```typescript
465
+ // Delete one
466
+ await User.deleteOne({ email: 'john@example.com' });
467
+
468
+ // Delete many
469
+ await User.deleteMany({ isActive: false });
470
+
471
+ // Find and delete
472
+ const deletedUser = await User.findOneAndDelete({ email: 'john@example.com' });
473
+
474
+ // Find by ID and delete
475
+ const deletedUser = await User.findByIdAndDelete('507f1f77bcf86cd799439011');
476
+ ```
477
+
478
+ ### Count & Exists
479
+
480
+ ```typescript
481
+ // Count documents
482
+ const count = await User.countDocuments({ role: 'admin' });
483
+
484
+ // Estimated count (faster, but approximate)
485
+ const estimated = await User.estimatedDocumentCount();
486
+
487
+ // Check if exists
488
+ const exists = await User.exists({ email: 'john@example.com' });
489
+ // Returns { _id: '...' } or null
490
+ ```
491
+
492
+ ### Aggregation
493
+
494
+ ```typescript
495
+ const result = await User.aggregate([
496
+ { $match: { isActive: true } },
497
+ { $group: { _id: '$role', count: { $sum: 1 } } },
498
+ { $sort: { count: -1 } }
499
+ ]);
500
+ ```
501
+
502
+ ### Distinct
503
+
504
+ ```typescript
505
+ const roles = await User.distinct('role');
506
+ // ['user', 'admin', 'moderator']
507
+ ```
508
+
509
+ ### Indexes
510
+
511
+ ```typescript
512
+ // Create index
513
+ await User.createIndex({ email: 1 }, { unique: true });
514
+
515
+ // Create compound index
516
+ await User.createIndex({ name: 1, createdAt: -1 });
517
+
518
+ // List indexes
519
+ const indexes = await User.listIndexes();
520
+
521
+ // Drop index
522
+ await User.dropIndex('email_1');
523
+
524
+ // Define index in schema
525
+ userSchema.index({ email: 1 }, { unique: true });
526
+ userSchema.index({ name: 'text' }); // Text index
527
+ ```
528
+
529
+ ## Route Management
530
+
531
+ ### Simple Routes
532
+
533
+ ```typescript
534
+ import { GET, POST, PUT, PATCH, DELETE } from 'harbor';
535
+
536
+ // GET request
537
+ const getUsers = GET('/api/users', async (req) => {
538
+ const users = await User.find();
539
+ return { users };
540
+ });
541
+
542
+ // POST request with validation
543
+ const createUser = POST('/api/users', async (req) => {
544
+ const user = await User.create(req.validated.body);
545
+ return { user };
546
+ }, {
547
+ validation: {
548
+ body: {
549
+ email: { type: 'email', required: true },
550
+ name: { type: 'string', required: true }
551
+ }
552
+ }
553
+ });
554
+
555
+ // PUT request
556
+ const updateUser = PUT('/api/users/:id', async (req) => {
557
+ const user = await User.findByIdAndUpdate(
558
+ req.validated.params.id,
559
+ req.validated.body,
560
+ { new: true }
561
+ );
562
+ return { user };
563
+ });
564
+
565
+ // DELETE request
566
+ const deleteUser = DELETE('/api/users/:id', async (req) => {
567
+ await User.findByIdAndDelete(req.validated.params.id);
568
+ return { deleted: true };
569
+ });
570
+
571
+ // Add routes to server
572
+ server.addRoute(getUsers);
573
+ server.addRoute(createUser);
574
+ server.addRoute(updateUser);
575
+ server.addRoute(deleteUser);
576
+ ```
577
+
578
+ ### Route Options
579
+
580
+ ```typescript
581
+ const route = POST('/api/users', handler, {
582
+ // Validation
583
+ validation: {
584
+ body: { /* schema */ },
585
+ params: { /* schema */ },
586
+ query: { /* schema */ },
587
+ headers: { /* schema */ }
588
+ },
589
+
590
+ // Middleware
591
+ pre: [authMiddleware, rateLimitMiddleware],
592
+ post: [logMiddleware],
593
+
594
+ // Timeout
595
+ timeout: 30000, // 30 seconds
596
+
597
+ // Metadata
598
+ tags: ['users'],
599
+ description: 'Create a new user'
600
+ });
601
+ ```
602
+
603
+ ### Route Groups
604
+
605
+ ```typescript
606
+ // Group routes by prefix
607
+ const userRoutes = [
608
+ GET('/api/users', listUsers),
609
+ POST('/api/users', createUser),
610
+ GET('/api/users/:id', getUser),
611
+ PUT('/api/users/:id', updateUser),
612
+ DELETE('/api/users/:id', deleteUser),
613
+ ];
614
+
615
+ server.addRoutes(userRoutes);
616
+ ```
617
+
618
+ ## Validation
619
+
620
+ ### Request Validation
621
+
622
+ ```typescript
623
+ const route = POST('/api/users', handler, {
624
+ validation: {
625
+ body: {
626
+ email: { type: 'email', required: true },
627
+ password: { type: 'string', required: true, min: 8, max: 100 },
628
+ age: { type: 'number', min: 0, max: 150 },
629
+ role: { type: 'string', enum: ['user', 'admin'] },
630
+ website: { type: 'url' },
631
+ phone: { type: 'string', match: /^\+?[\d\s-]+$/ }
632
+ },
633
+ params: {
634
+ id: { type: 'objectId', required: true }
635
+ },
636
+ query: {
637
+ page: { type: 'number', default: 1 },
638
+ limit: { type: 'number', default: 20, max: 100 }
639
+ }
640
+ }
641
+ });
642
+ ```
643
+
644
+ ### Validation Types
645
+
646
+ - `string` - String values
647
+ - `number` - Numeric values
648
+ - `boolean` - true/false
649
+ - `email` - Valid email address
650
+ - `url` - Valid URL
651
+ - `objectId` - MongoDB ObjectId
652
+ - `date` - Valid date
653
+ - `array` - Array values
654
+ - `object` - Object values
655
+
656
+ ### Custom Validators
657
+
658
+ ```typescript
659
+ const schema = {
660
+ password: {
661
+ type: 'string',
662
+ required: true,
663
+ validate: {
664
+ validator: (value) => /[A-Z]/.test(value) && /[0-9]/.test(value),
665
+ message: 'Password must contain uppercase letter and number'
666
+ }
667
+ }
668
+ };
669
+ ```
670
+
671
+ ## Error Handling
672
+
673
+ ### HarborError Class
674
+
675
+ ```typescript
676
+ import { HarborError } from 'harbor';
677
+
678
+ // Throw errors in your routes
679
+ const getUser = GET('/api/users/:id', async (req) => {
680
+ const user = await User.findById(req.params.id);
681
+
682
+ if (!user) {
683
+ throw HarborError.notFound('User not found');
684
+ }
685
+
686
+ if (!user.isActive) {
687
+ throw HarborError.forbidden('User account is disabled');
688
+ }
689
+
690
+ return { user };
691
+ });
692
+ ```
693
+
694
+ ### Available Error Methods
695
+
696
+ ```typescript
697
+ HarborError.badRequest(message?, details?) // 400
698
+ HarborError.unauthorized(message?) // 401
699
+ HarborError.forbidden(message?) // 403
700
+ HarborError.notFound(message?) // 404
701
+ HarborError.conflict(message?, details?) // 409
702
+ HarborError.tooManyRequests(message?) // 429
703
+ HarborError.internal(message?) // 500
704
+ ```
705
+
706
+ ### Error Configuration
707
+
708
+ Configure error responses in `harbor.config.json`:
709
+
710
+ ```json
711
+ {
712
+ "errors": {
713
+ "401": {
714
+ "message": "Please log in to continue",
715
+ "json": true,
716
+ "log": true
717
+ },
718
+ "404": {
719
+ "message": "Resource not found",
720
+ "json": true
721
+ },
722
+ "500": {
723
+ "message": "Something went wrong",
724
+ "json": true,
725
+ "log": true
726
+ }
727
+ }
728
+ }
729
+ ```
730
+
731
+ ## Middleware
732
+
733
+ ### HTTP Logger (Morgan-like)
734
+
735
+ ```typescript
736
+ import { httpLogger } from 'harbor';
737
+
738
+ // Add logging middleware
739
+ server.addMiddleware(httpLogger({ format: 'dev' }));
740
+
741
+ // Available formats: 'tiny', 'short', 'dev', 'combined', 'common'
742
+ ```
743
+
744
+ ### Custom Format
745
+
746
+ ```typescript
747
+ server.addMiddleware(httpLogger({
748
+ format: 'custom',
749
+ customFormat: (tokens) =>
750
+ `${tokens.method} ${tokens.url} ${tokens.status} - ${tokens.responseTime}ms`
751
+ }));
752
+ ```
753
+
754
+ ### Skip Requests
755
+
756
+ ```typescript
757
+ import { httpLogger, skipFunctions } from 'harbor';
758
+
759
+ server.addMiddleware(httpLogger({
760
+ format: 'dev',
761
+ skip: skipFunctions.healthChecks // Skip /health and /healthz
762
+ }));
763
+ ```
764
+
765
+ ### Pre/Post Route Middleware
766
+
767
+ ```typescript
768
+ const authMiddleware = async (req, res, next) => {
769
+ const token = req.headers.authorization?.split(' ')[1];
770
+ if (!token) {
771
+ throw HarborError.unauthorized('No token provided');
772
+ }
773
+ req.user = await verifyToken(token);
774
+ next();
775
+ };
776
+
777
+ const logMiddleware = async (req, res, result, next) => {
778
+ console.log('Response:', result);
779
+ next();
780
+ };
781
+
782
+ const route = GET('/api/profile', handler, {
783
+ pre: [authMiddleware],
784
+ post: [logMiddleware]
785
+ });
786
+ ```
787
+
788
+ ## Docker Manager
789
+
790
+ ```typescript
791
+ import { createDockerManager } from 'harbor';
792
+
793
+ const docker = createDockerManager({
794
+ imageName: 'my-app',
795
+ tag: 'latest',
796
+ dockerfile: './Dockerfile',
797
+ context: '.'
798
+ });
799
+
800
+ // Build image
801
+ await docker.build();
802
+
803
+ // Push to registry
804
+ await docker.push('registry.example.com');
805
+
806
+ // Pull image
807
+ await docker.pull('nginx:latest');
808
+
809
+ // Container operations
810
+ await docker.startContainer('my-container');
811
+ await docker.stopContainer('my-container');
812
+ await docker.restartContainer('my-container');
813
+
814
+ // Docker Compose
815
+ await docker.composeUp();
816
+ await docker.composeDown();
817
+ ```
818
+
819
+ ## Configuration
820
+
821
+ Create `harbor.config.json` in your project root:
822
+
823
+ ```json
824
+ {
825
+ "server": {
826
+ "port": 3000,
827
+ "host": "localhost"
828
+ },
829
+ "cors": {
830
+ "enabled": true,
831
+ "origin": "*",
832
+ "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"],
833
+ "allowedHeaders": ["Content-Type", "Authorization"]
834
+ },
835
+ "logger": {
836
+ "level": "info",
837
+ "format": "dev"
838
+ },
839
+ "validation": {
840
+ "abortEarly": false,
841
+ "stripUnknown": true
842
+ },
843
+ "errors": {
844
+ "404": { "message": "Not Found", "json": true },
845
+ "500": { "message": "Internal Error", "json": true, "log": true }
846
+ },
847
+ "docker": {
848
+ "imageName": "my-app",
849
+ "tag": "latest"
850
+ }
851
+ }
852
+ ```
853
+
854
+ ## i18n (Translations)
855
+
856
+ ```typescript
857
+ import { setLocale, t, addTranslations } from 'harbor';
858
+
859
+ // Set locale
860
+ setLocale('he');
861
+
862
+ // Use translations
863
+ console.log(t('server.started', { host: 'localhost', port: 3000 }));
864
+ // Output (Hebrew): השרת פועל בכתובת http://localhost:3000
865
+
866
+ // Add custom translations
867
+ addTranslations('en', {
868
+ 'custom.message': 'Hello, {name}!'
869
+ });
870
+ ```
871
+
872
+ ### Available Locales
873
+
874
+ - `en` - English (default)
875
+ - `he` - Hebrew
876
+
877
+ ## API Reference
878
+
879
+ ### Core Functions
880
+
881
+ | Function | Description |
882
+ |----------|-------------|
883
+ | `createServer(options)` | Create a Harbor server |
884
+ | `connect(uri, options)` | Connect to MongoDB |
885
+ | `disconnect()` | Disconnect from MongoDB |
886
+ | `Schema(definition, options)` | Create a schema |
887
+ | `model(name, schema)` | Create a model |
888
+ | `GET/POST/PUT/PATCH/DELETE(path, handler, options)` | Create routes |
889
+
890
+ ### Model Methods
891
+
892
+ | Method | Description |
893
+ |--------|-------------|
894
+ | `find(filter)` | Find documents |
895
+ | `findOne(filter)` | Find one document |
896
+ | `findById(id)` | Find by ID |
897
+ | `create(doc)` | Create document(s) |
898
+ | `updateOne(filter, update)` | Update one |
899
+ | `updateMany(filter, update)` | Update many |
900
+ | `deleteOne(filter)` | Delete one |
901
+ | `deleteMany(filter)` | Delete many |
902
+ | `findOneAndUpdate(filter, update, options)` | Find and update |
903
+ | `findOneAndDelete(filter)` | Find and delete |
904
+ | `countDocuments(filter)` | Count documents |
905
+ | `aggregate(pipeline)` | Aggregation pipeline |
906
+
907
+ ### Query Methods
908
+
909
+ | Method | Description |
910
+ |--------|-------------|
911
+ | `.select(fields)` | Select fields |
912
+ | `.sort(fields)` | Sort results |
913
+ | `.limit(n)` | Limit results |
914
+ | `.skip(n)` | Skip results |
915
+ | `.lean()` | Return plain objects |
916
+ | `.where(path)` | Add condition |
917
+ | `.gt/gte/lt/lte(value)` | Comparison operators |
918
+ | `.in/nin(values)` | Array operators |
919
+ | `.regex(pattern)` | Regex match |
920
+
921
+ ## License
922
+
923
+ MIT © Harbor Contributors
924
+
925
+ ---
926
+
927
+ **Happy Sailing! 🚢**