glasswork 0.1.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/LICENSE +21 -0
- package/README.md +182 -0
- package/dist/bootstrap.d.ts +55 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +359 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/core/bootstrap.d.ts +55 -0
- package/dist/core/bootstrap.d.ts.map +1 -0
- package/dist/core/bootstrap.js +329 -0
- package/dist/core/bootstrap.js.map +1 -0
- package/dist/core/module.d.ts +21 -0
- package/dist/core/module.d.ts.map +1 -0
- package/dist/core/module.js +85 -0
- package/dist/core/module.js.map +1 -0
- package/dist/core/types.d.ts +273 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/environment.d.ts +21 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +29 -0
- package/dist/environment.js.map +1 -0
- package/dist/error-handler.d.ts +33 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +53 -0
- package/dist/error-handler.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +65 -0
- package/dist/errors.js.map +1 -0
- package/dist/get-client-ip.d.ts +24 -0
- package/dist/get-client-ip.d.ts.map +1 -0
- package/dist/get-client-ip.js +49 -0
- package/dist/get-client-ip.js.map +1 -0
- package/dist/http/error-handler.d.ts +33 -0
- package/dist/http/error-handler.d.ts.map +1 -0
- package/dist/http/error-handler.js +55 -0
- package/dist/http/error-handler.js.map +1 -0
- package/dist/http/errors.d.ts +36 -0
- package/dist/http/errors.d.ts.map +1 -0
- package/dist/http/errors.js +65 -0
- package/dist/http/errors.js.map +1 -0
- package/dist/http/route-helpers.d.ts +172 -0
- package/dist/http/route-helpers.d.ts.map +1 -0
- package/dist/http/route-helpers.js +249 -0
- package/dist/http/route-helpers.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +37 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +52 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +7 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +182 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/module.d.ts +21 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +85 -0
- package/dist/module.js.map +1 -0
- package/dist/omit.d.ts +20 -0
- package/dist/omit.d.ts.map +1 -0
- package/dist/omit.js +28 -0
- package/dist/omit.js.map +1 -0
- package/dist/openapi/defaults.d.ts +11 -0
- package/dist/openapi/defaults.d.ts.map +1 -0
- package/dist/openapi/defaults.js +127 -0
- package/dist/openapi/defaults.js.map +1 -0
- package/dist/openapi/hooks.d.ts +14 -0
- package/dist/openapi/hooks.d.ts.map +1 -0
- package/dist/openapi/hooks.js +80 -0
- package/dist/openapi/hooks.js.map +1 -0
- package/dist/openapi/openapi.d.ts +24 -0
- package/dist/openapi/openapi.d.ts.map +1 -0
- package/dist/openapi/openapi.js +108 -0
- package/dist/openapi/openapi.js.map +1 -0
- package/dist/openapi-defaults.d.ts +11 -0
- package/dist/openapi-defaults.d.ts.map +1 -0
- package/dist/openapi-defaults.js +127 -0
- package/dist/openapi-defaults.js.map +1 -0
- package/dist/openapi-hooks.d.ts +14 -0
- package/dist/openapi-hooks.d.ts.map +1 -0
- package/dist/openapi-hooks.js +80 -0
- package/dist/openapi-hooks.js.map +1 -0
- package/dist/openapi.d.ts +24 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +106 -0
- package/dist/openapi.js.map +1 -0
- package/dist/pagination.d.ts +48 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +43 -0
- package/dist/pagination.js.map +1 -0
- package/dist/pick.d.ts +20 -0
- package/dist/pick.d.ts.map +1 -0
- package/dist/pick.js +28 -0
- package/dist/pick.js.map +1 -0
- package/dist/rate-limit.d.ts +7 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +180 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/route-helpers.d.ts +172 -0
- package/dist/route-helpers.d.ts.map +1 -0
- package/dist/route-helpers.js +249 -0
- package/dist/route-helpers.js.map +1 -0
- package/dist/serialize-dates.d.ts +27 -0
- package/dist/serialize-dates.d.ts.map +1 -0
- package/dist/serialize-dates.js +39 -0
- package/dist/serialize-dates.js.map +1 -0
- package/dist/testing.d.ts +87 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +94 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +273 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/deep-merge.d.ts +5 -0
- package/dist/utils/deep-merge.d.ts.map +1 -0
- package/dist/utils/deep-merge.js +21 -0
- package/dist/utils/deep-merge.js.map +1 -0
- package/dist/utils/environment.d.ts +21 -0
- package/dist/utils/environment.d.ts.map +1 -0
- package/dist/utils/environment.js +29 -0
- package/dist/utils/environment.js.map +1 -0
- package/dist/utils/get-client-ip.d.ts +24 -0
- package/dist/utils/get-client-ip.d.ts.map +1 -0
- package/dist/utils/get-client-ip.js +49 -0
- package/dist/utils/get-client-ip.js.map +1 -0
- package/dist/utils/logger.d.ts +37 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +52 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/omit.d.ts +20 -0
- package/dist/utils/omit.d.ts.map +1 -0
- package/dist/utils/omit.js +28 -0
- package/dist/utils/omit.js.map +1 -0
- package/dist/utils/pagination.d.ts +48 -0
- package/dist/utils/pagination.d.ts.map +1 -0
- package/dist/utils/pagination.js +42 -0
- package/dist/utils/pagination.js.map +1 -0
- package/dist/utils/pick.d.ts +20 -0
- package/dist/utils/pick.d.ts.map +1 -0
- package/dist/utils/pick.js +28 -0
- package/dist/utils/pick.js.map +1 -0
- package/dist/utils/serialize-dates.d.ts +27 -0
- package/dist/utils/serialize-dates.d.ts.map +1 -0
- package/dist/utils/serialize-dates.js +39 -0
- package/dist/utils/serialize-dates.js.map +1 -0
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +31 -0
- package/dist/utils.js.map +1 -0
- package/package.json +79 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Roland Boon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Glasswork
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
[](https://github.com/yourusername/glasswork)
|
|
6
|
+
|
|
7
|
+
**A transparent, Lambda-optimized web framework for building OpenAPI-compliant REST APIs.**
|
|
8
|
+
|
|
9
|
+
Built on Hono, Awilix, and Prisma, Glasswork helps you create production-ready APIs with automatic OpenAPI spec generation, type-safe routing, and clean architecture.
|
|
10
|
+
|
|
11
|
+
## Why Glasswork?
|
|
12
|
+
|
|
13
|
+
**Build NestJS-quality APIs that run practically for free on Lambda.**
|
|
14
|
+
|
|
15
|
+
If you're building hobby projects or side APIs, you want:
|
|
16
|
+
|
|
17
|
+
- **Near-zero hosting costs** - Lambda + S3 is practically free at low usage
|
|
18
|
+
- **Professional architecture** - Clean separation, DI, modules (like NestJS)
|
|
19
|
+
- **Automatic OpenAPI docs** - No manual Swagger decorators
|
|
20
|
+
- **Fast deployment** - No containers, no servers to maintain
|
|
21
|
+
- **Easy testing** - Services are framework-agnostic, no HTTP mocking needed
|
|
22
|
+
|
|
23
|
+
### The Problem with NestJS on Lambda
|
|
24
|
+
|
|
25
|
+
NestJS is excellent for professional projects, but on Lambda it has issues:
|
|
26
|
+
|
|
27
|
+
- Large bundle size = slower cold starts
|
|
28
|
+
- Decorators and reflection = harder to tree-shake
|
|
29
|
+
- Heavy abstractions = less control over the HTTP layer
|
|
30
|
+
- Requires containers for full features (not Lambda-friendly)
|
|
31
|
+
|
|
32
|
+
### The Glasswork Solution
|
|
33
|
+
|
|
34
|
+
Keep what's great about NestJS (modules, DI, OpenAPI), but:
|
|
35
|
+
|
|
36
|
+
- ~1MB bundles with fast cold starts
|
|
37
|
+
- No decorators, no reflection - just TypeScript
|
|
38
|
+
- Direct access to Hono, Awilix, Prisma (no framework lock-in)
|
|
39
|
+
- Built specifically for Lambda deployment
|
|
40
|
+
- Still maintain clean architecture and testability
|
|
41
|
+
|
|
42
|
+
**Perfect for:** Hobby projects, MVPs, side APIs, serverless-first applications
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **OpenAPI-First**: Automatic spec generation from Valibot schemas - write code, get docs
|
|
47
|
+
- **Type-Safe Routes**: Request/response validation with full TypeScript inference
|
|
48
|
+
- **Module System**: Organize your API into logical, testable modules
|
|
49
|
+
- **Dependency Injection**: Powered by Awilix with Lambda-compatible PROXY mode
|
|
50
|
+
- **Framework-Agnostic Services**: Test business logic without any HTTP mocking
|
|
51
|
+
- **Lambda-Optimized**: ~1MB bundles, fast cold starts, production-ready
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install glasswork hono awilix valibot hono-openapi
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
### 1. Define Your DTOs (Valibot Schemas)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { object, string, email } from 'valibot';
|
|
65
|
+
|
|
66
|
+
// These schemas automatically generate OpenAPI documentation
|
|
67
|
+
export const LoginDto = object({
|
|
68
|
+
email: string([email()]),
|
|
69
|
+
password: string([minLength(8)]),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export const SessionDto = object({
|
|
73
|
+
token: string(),
|
|
74
|
+
expiresAt: string(),
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 2. Create Type-Safe Routes
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { createRoutes, route } from 'glasswork';
|
|
82
|
+
|
|
83
|
+
export const authRoutes = createRoutes<{ authService: AuthService }>(
|
|
84
|
+
(router, { authService }) => {
|
|
85
|
+
// router is a real Hono instance - all features work
|
|
86
|
+
|
|
87
|
+
router.post('/login', route({
|
|
88
|
+
tags: ['Auth'],
|
|
89
|
+
summary: 'User login',
|
|
90
|
+
public: true,
|
|
91
|
+
body: LoginDto,
|
|
92
|
+
responses: { 200: SessionDto },
|
|
93
|
+
handler: async ({ body }) => {
|
|
94
|
+
// body is fully typed from LoginDto
|
|
95
|
+
return authService.login(body.email, body.password);
|
|
96
|
+
},
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3. Write Framework-Agnostic Services
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Services have zero framework coupling
|
|
106
|
+
export class AuthService {
|
|
107
|
+
constructor({ prismaService, hashService }: {
|
|
108
|
+
prismaService: PrismaService;
|
|
109
|
+
hashService: HashService;
|
|
110
|
+
}) {
|
|
111
|
+
this.prismaService = prismaService;
|
|
112
|
+
this.hashService = hashService;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async login(email: string, password: string) {
|
|
116
|
+
const user = await this.prismaService.user.findUnique({ where: { email } });
|
|
117
|
+
if (!user) throw new NotFoundException('Invalid credentials');
|
|
118
|
+
|
|
119
|
+
await this.hashService.verify(password, user.password);
|
|
120
|
+
return this.createSession(user);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 4. Define Modules and Bootstrap
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// auth.module.ts
|
|
129
|
+
export const AuthModule = defineModule({
|
|
130
|
+
name: 'auth',
|
|
131
|
+
basePath: 'auth',
|
|
132
|
+
providers: [AuthService],
|
|
133
|
+
routes: authRoutes,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// app.ts
|
|
137
|
+
import { bootstrap } from 'glasswork';
|
|
138
|
+
|
|
139
|
+
const { app } = bootstrap(AppModule, {
|
|
140
|
+
openapi: {
|
|
141
|
+
enabled: true,
|
|
142
|
+
documentation: {
|
|
143
|
+
info: { title: 'My API', version: '1.0.0' },
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
export default app; // Ready for Lambda or local server
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Your OpenAPI spec is automatically generated at `/api/openapi.json`** 🎉
|
|
152
|
+
|
|
153
|
+
## When to Use Glasswork
|
|
154
|
+
|
|
155
|
+
**Choose Glasswork if you:**
|
|
156
|
+
|
|
157
|
+
- Want to deploy on Lambda (hobby projects, low-cost hosting)
|
|
158
|
+
- Like NestJS patterns but need smaller bundles
|
|
159
|
+
- Value clean architecture and testability
|
|
160
|
+
- Want automatic OpenAPI without decorators
|
|
161
|
+
- Prefer transparency over heavy abstractions
|
|
162
|
+
|
|
163
|
+
**Consider alternatives if you:**
|
|
164
|
+
|
|
165
|
+
- Need GraphQL (use Apollo Server, Pothos)
|
|
166
|
+
- Deploy to containers anyway (use NestJS, it's excellent)
|
|
167
|
+
- Want full-stack with frontend (use Next.js, Remix)
|
|
168
|
+
- Need minimal setup with zero opinions (use Hono directly)
|
|
169
|
+
|
|
170
|
+
## Requirements
|
|
171
|
+
|
|
172
|
+
- Node.js 18+
|
|
173
|
+
- TypeScript 5+
|
|
174
|
+
- (Optional) AWS Lambda for serverless deployment
|
|
175
|
+
|
|
176
|
+
## Contributing
|
|
177
|
+
|
|
178
|
+
Glasswork is in active development. Feedback, issues, and contributions are welcome!
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { AwilixContainer } from 'awilix';
|
|
2
|
+
import type { BootstrapOptions, BootstrapResult, ModuleConfig } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Bootstrap the application with modules.
|
|
5
|
+
*
|
|
6
|
+
* This function:
|
|
7
|
+
* 1. Creates an Awilix container (PROXY mode for Lambda compatibility)
|
|
8
|
+
* 2. Registers all module providers
|
|
9
|
+
* 3. Creates a Hono app
|
|
10
|
+
* 4. Applies rate limiting middleware (if configured)
|
|
11
|
+
* 5. Configures OpenAPI (environment-aware)
|
|
12
|
+
* 6. Mounts module routes
|
|
13
|
+
* 7. Returns both app and container (container remains accessible!)
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - Automatic environment detection (development/production/test)
|
|
17
|
+
* - OpenAPI generation and serving (environment-aware)
|
|
18
|
+
* - Rate limiting with pluggable storage (memory/DynamoDB)
|
|
19
|
+
* - Module system with dependency injection
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const { app, container } = bootstrap(AppModule, {
|
|
24
|
+
* openapi: {
|
|
25
|
+
* enabled: true,
|
|
26
|
+
* documentation: { ... }
|
|
27
|
+
* },
|
|
28
|
+
* rateLimit: {
|
|
29
|
+
* enabled: true,
|
|
30
|
+
* storage: 'memory'
|
|
31
|
+
* }
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* // Container is still accessible for advanced use
|
|
35
|
+
* console.log(container.cradle.authService);
|
|
36
|
+
* container.register({ customService: asClass(CustomService) });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function bootstrap(rootModule: ModuleConfig, options?: BootstrapOptions): BootstrapResult;
|
|
40
|
+
/**
|
|
41
|
+
* Collect all modules (flatten imports recursively)
|
|
42
|
+
* @internal - exported for testing utilities
|
|
43
|
+
*/
|
|
44
|
+
export declare function collectModules(rootModule: ModuleConfig): ModuleConfig[];
|
|
45
|
+
/**
|
|
46
|
+
* Validate no circular dependencies between modules
|
|
47
|
+
* @internal - exported for testing utilities
|
|
48
|
+
*/
|
|
49
|
+
export declare function validateNoCycles(modules: ModuleConfig[]): void;
|
|
50
|
+
/**
|
|
51
|
+
* Register module providers with Awilix container
|
|
52
|
+
* @internal - exported for testing utilities
|
|
53
|
+
*/
|
|
54
|
+
export declare function registerModuleProviders(module: ModuleConfig, container: AwilixContainer, debug?: boolean): void;
|
|
55
|
+
//# sourceMappingURL=bootstrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAY9C,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAKf,YAAY,EAKb,MAAM,YAAY,CAAC;AAwBpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,YAAY,EACxB,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CAgEjB;AAsKD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,YAAY,GAAG,YAAY,EAAE,CAuBvE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,CA2C9D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,eAAe,EAC1B,KAAK,UAAQ,GACZ,IAAI,CAQN"}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { asClass, asValue, createContainer, InjectionMode } from 'awilix';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { cors } from 'hono/cors';
|
|
4
|
+
import { logger as honoLogger } from 'hono/logger';
|
|
5
|
+
import { requestId } from 'hono/request-id';
|
|
6
|
+
import { secureHeaders } from 'hono/secure-headers';
|
|
7
|
+
import { isLambda } from './environment.js';
|
|
8
|
+
import { defaultErrorHandler } from './error-handler.js';
|
|
9
|
+
import { createPlainLogger } from './logger.js';
|
|
10
|
+
import { configureOpenAPI } from './openapi.js';
|
|
11
|
+
import { createRateLimitMiddleware } from './rate-limit.js';
|
|
12
|
+
/**
|
|
13
|
+
* Detect environment from NODE_ENV or AWS Lambda context
|
|
14
|
+
*/
|
|
15
|
+
function detectEnvironment() {
|
|
16
|
+
const nodeEnv = process.env.NODE_ENV;
|
|
17
|
+
if (nodeEnv === 'production') {
|
|
18
|
+
return 'production';
|
|
19
|
+
}
|
|
20
|
+
if (nodeEnv === 'test') {
|
|
21
|
+
return 'test';
|
|
22
|
+
}
|
|
23
|
+
// Check if running in AWS Lambda
|
|
24
|
+
if (process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.LAMBDA_TASK_ROOT) {
|
|
25
|
+
return 'production';
|
|
26
|
+
}
|
|
27
|
+
return 'development';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Bootstrap the application with modules.
|
|
31
|
+
*
|
|
32
|
+
* This function:
|
|
33
|
+
* 1. Creates an Awilix container (PROXY mode for Lambda compatibility)
|
|
34
|
+
* 2. Registers all module providers
|
|
35
|
+
* 3. Creates a Hono app
|
|
36
|
+
* 4. Applies rate limiting middleware (if configured)
|
|
37
|
+
* 5. Configures OpenAPI (environment-aware)
|
|
38
|
+
* 6. Mounts module routes
|
|
39
|
+
* 7. Returns both app and container (container remains accessible!)
|
|
40
|
+
*
|
|
41
|
+
* Features:
|
|
42
|
+
* - Automatic environment detection (development/production/test)
|
|
43
|
+
* - OpenAPI generation and serving (environment-aware)
|
|
44
|
+
* - Rate limiting with pluggable storage (memory/DynamoDB)
|
|
45
|
+
* - Module system with dependency injection
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const { app, container } = bootstrap(AppModule, {
|
|
50
|
+
* openapi: {
|
|
51
|
+
* enabled: true,
|
|
52
|
+
* documentation: { ... }
|
|
53
|
+
* },
|
|
54
|
+
* rateLimit: {
|
|
55
|
+
* enabled: true,
|
|
56
|
+
* storage: 'memory'
|
|
57
|
+
* }
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* // Container is still accessible for advanced use
|
|
61
|
+
* console.log(container.cradle.authService);
|
|
62
|
+
* container.register({ customService: asClass(CustomService) });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export function bootstrap(rootModule, options = {}) {
|
|
66
|
+
const { apiBasePath = '/api', debug = false, environment = detectEnvironment(), errorHandler = defaultErrorHandler, openapi, rateLimit, middleware, logger, } = options;
|
|
67
|
+
// Create Awilix container with PROXY mode (Lambda-compatible)
|
|
68
|
+
const container = createContainer({
|
|
69
|
+
injectionMode: InjectionMode.PROXY,
|
|
70
|
+
strict: true,
|
|
71
|
+
});
|
|
72
|
+
if (debug) {
|
|
73
|
+
console.log('[Glasswork] Bootstrapping application...');
|
|
74
|
+
}
|
|
75
|
+
// Collect all modules (flatten imports)
|
|
76
|
+
const allModules = collectModules(rootModule);
|
|
77
|
+
if (debug) {
|
|
78
|
+
console.log(`[Glasswork] Found ${allModules.length} modules:`, allModules.map((m) => m.name).join(', '));
|
|
79
|
+
}
|
|
80
|
+
// Validate no circular dependencies
|
|
81
|
+
validateNoCycles(allModules);
|
|
82
|
+
// Register all providers
|
|
83
|
+
for (const module of allModules) {
|
|
84
|
+
if (debug) {
|
|
85
|
+
console.log(`[Glasswork] Registering module: ${module.name}`);
|
|
86
|
+
}
|
|
87
|
+
registerModuleProviders(module, container, debug);
|
|
88
|
+
}
|
|
89
|
+
// Create Hono app and apply middleware
|
|
90
|
+
const app = createApp({
|
|
91
|
+
environment,
|
|
92
|
+
errorHandler,
|
|
93
|
+
openapi,
|
|
94
|
+
rateLimit,
|
|
95
|
+
middleware,
|
|
96
|
+
logger,
|
|
97
|
+
debug,
|
|
98
|
+
});
|
|
99
|
+
// Mount module routes
|
|
100
|
+
mountModuleRoutes({ app, modules: allModules, container, apiBasePath, debug });
|
|
101
|
+
if (debug) {
|
|
102
|
+
console.log('[Glasswork] Bootstrap complete');
|
|
103
|
+
console.log(`[Glasswork] Environment: ${environment}`);
|
|
104
|
+
console.log(`[Glasswork] Registered ${Object.keys(container.cradle).length} services`);
|
|
105
|
+
}
|
|
106
|
+
return { app, container };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create Hono app and apply middleware
|
|
110
|
+
*/
|
|
111
|
+
function createApp(options) {
|
|
112
|
+
const app = new Hono();
|
|
113
|
+
applyErrorHandler(app, options);
|
|
114
|
+
applySecurityMiddleware(app, options);
|
|
115
|
+
applyLoggingMiddleware(app, options);
|
|
116
|
+
applyRateLimiting(app, options);
|
|
117
|
+
applyOpenAPIDocumentation(app, options);
|
|
118
|
+
return app;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Apply error handler to the app
|
|
122
|
+
*/
|
|
123
|
+
function applyErrorHandler(app, { errorHandler, debug }) {
|
|
124
|
+
if (errorHandler === false)
|
|
125
|
+
return;
|
|
126
|
+
if (debug) {
|
|
127
|
+
console.log('[Glasswork] Applying error handler');
|
|
128
|
+
}
|
|
129
|
+
app.onError(errorHandler);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Apply security-related middleware (secure headers, request ID, CORS)
|
|
133
|
+
*/
|
|
134
|
+
function applySecurityMiddleware(app, { environment, middleware, debug, }) {
|
|
135
|
+
// Secure headers (default: true in production)
|
|
136
|
+
if (middleware?.secureHeaders !== false && environment === 'production') {
|
|
137
|
+
if (debug) {
|
|
138
|
+
console.log('[Glasswork] Applying secure headers');
|
|
139
|
+
}
|
|
140
|
+
app.use(secureHeaders());
|
|
141
|
+
}
|
|
142
|
+
// Request ID (default: true)
|
|
143
|
+
if (middleware?.requestId !== false) {
|
|
144
|
+
if (debug) {
|
|
145
|
+
console.log('[Glasswork] Applying request ID middleware');
|
|
146
|
+
}
|
|
147
|
+
app.use(requestId());
|
|
148
|
+
}
|
|
149
|
+
// CORS
|
|
150
|
+
if (middleware?.cors) {
|
|
151
|
+
if (debug) {
|
|
152
|
+
console.log('[Glasswork] Applying CORS middleware');
|
|
153
|
+
}
|
|
154
|
+
app.use(cors(middleware.cors));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Apply logging middleware
|
|
159
|
+
*/
|
|
160
|
+
function applyLoggingMiddleware(app, { logger, debug }) {
|
|
161
|
+
if (logger?.enabled === false)
|
|
162
|
+
return;
|
|
163
|
+
// Auto-detect plain mode based on environment if not specified
|
|
164
|
+
const usePlainLogger = logger?.plain ?? isLambda();
|
|
165
|
+
if (debug) {
|
|
166
|
+
console.log(`[Glasswork] Applying logger (plain: ${usePlainLogger})`);
|
|
167
|
+
}
|
|
168
|
+
app.use(usePlainLogger ? createPlainLogger() : honoLogger());
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Apply rate limiting middleware
|
|
172
|
+
*/
|
|
173
|
+
function applyRateLimiting(app, { rateLimit, debug }) {
|
|
174
|
+
if (!rateLimit?.enabled)
|
|
175
|
+
return;
|
|
176
|
+
if (debug) {
|
|
177
|
+
console.log(`[Glasswork] Rate limiting enabled (${rateLimit.storage} storage, ${rateLimit.maxRequests || 100} req/${rateLimit.windowMs || 60000}ms)`);
|
|
178
|
+
}
|
|
179
|
+
app.use(createRateLimitMiddleware(rateLimit));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Apply OpenAPI documentation
|
|
183
|
+
*/
|
|
184
|
+
function applyOpenAPIDocumentation(app, options) {
|
|
185
|
+
const { environment, openapi, rateLimit, middleware, debug } = options;
|
|
186
|
+
if (!openapi?.enabled)
|
|
187
|
+
return;
|
|
188
|
+
if (debug) {
|
|
189
|
+
console.log('[Glasswork] Configuring OpenAPI');
|
|
190
|
+
}
|
|
191
|
+
configureOpenAPI({ app, environment, openapi, rateLimit, middleware });
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Mount module routes to the app
|
|
195
|
+
*/
|
|
196
|
+
function mountModuleRoutes(options) {
|
|
197
|
+
const { app, modules, container, apiBasePath, debug } = options;
|
|
198
|
+
for (const module of modules) {
|
|
199
|
+
if (!module.routes || !module.basePath) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (debug) {
|
|
203
|
+
console.log(`[Glasswork] Mounting routes: ${apiBasePath}/${module.basePath}`);
|
|
204
|
+
}
|
|
205
|
+
const router = new Hono();
|
|
206
|
+
// Call route factory with router and services
|
|
207
|
+
module.routes(router, container.cradle);
|
|
208
|
+
// Mount at base path
|
|
209
|
+
app.route(`${apiBasePath}/${module.basePath}`, router);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Collect all modules (flatten imports recursively)
|
|
214
|
+
* @internal - exported for testing utilities
|
|
215
|
+
*/
|
|
216
|
+
export function collectModules(rootModule) {
|
|
217
|
+
const modules = new Map();
|
|
218
|
+
const visited = new Set();
|
|
219
|
+
function collect(module) {
|
|
220
|
+
if (visited.has(module.name)) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
visited.add(module.name);
|
|
224
|
+
modules.set(module.name, module);
|
|
225
|
+
// Recursively collect imports
|
|
226
|
+
if (module.imports) {
|
|
227
|
+
for (const importedModule of module.imports) {
|
|
228
|
+
collect(importedModule);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
collect(rootModule);
|
|
233
|
+
return Array.from(modules.values());
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Validate no circular dependencies between modules
|
|
237
|
+
* @internal - exported for testing utilities
|
|
238
|
+
*/
|
|
239
|
+
export function validateNoCycles(modules) {
|
|
240
|
+
const graph = new Map();
|
|
241
|
+
// Build dependency graph
|
|
242
|
+
for (const module of modules) {
|
|
243
|
+
if (!graph.has(module.name)) {
|
|
244
|
+
graph.set(module.name, new Set());
|
|
245
|
+
}
|
|
246
|
+
if (module.imports) {
|
|
247
|
+
for (const importedModule of module.imports) {
|
|
248
|
+
graph.get(module.name)?.add(importedModule.name);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Detect cycles using DFS
|
|
253
|
+
const visiting = new Set();
|
|
254
|
+
const visited = new Set();
|
|
255
|
+
function visit(name, path) {
|
|
256
|
+
if (visiting.has(name)) {
|
|
257
|
+
throw new Error(`Circular dependency detected: ${[...path, name].join(' -> ')}`);
|
|
258
|
+
}
|
|
259
|
+
if (visited.has(name)) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
visiting.add(name);
|
|
263
|
+
const dependencies = graph.get(name) || new Set();
|
|
264
|
+
for (const dep of dependencies) {
|
|
265
|
+
visit(dep, [...path, name]);
|
|
266
|
+
}
|
|
267
|
+
visiting.delete(name);
|
|
268
|
+
visited.add(name);
|
|
269
|
+
}
|
|
270
|
+
for (const module of modules) {
|
|
271
|
+
visit(module.name, []);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Register module providers with Awilix container
|
|
276
|
+
* @internal - exported for testing utilities
|
|
277
|
+
*/
|
|
278
|
+
export function registerModuleProviders(module, container, debug = false) {
|
|
279
|
+
if (!module.providers) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
for (const provider of module.providers) {
|
|
283
|
+
registerProvider(provider, container, module.name, debug);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Register a single provider with Awilix
|
|
288
|
+
*/
|
|
289
|
+
function registerProvider(provider, container, moduleName, debug) {
|
|
290
|
+
if (typeof provider === 'function') {
|
|
291
|
+
registerClassProvider(provider, container, debug);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if ('useClass' in provider) {
|
|
295
|
+
registerExplicitClassProvider(provider, container, debug);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if ('useValue' in provider) {
|
|
299
|
+
registerValueProvider(provider, container, debug);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if ('useFactory' in provider) {
|
|
303
|
+
registerFactoryProvider(provider, container, debug);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
throw new Error(`Invalid provider configuration in module "${moduleName}"`);
|
|
307
|
+
}
|
|
308
|
+
function registerClassProvider(provider, container, debug) {
|
|
309
|
+
const name = camelCase(provider.name);
|
|
310
|
+
if (debug) {
|
|
311
|
+
console.log(` - Registering ${name} (${provider.name})`);
|
|
312
|
+
}
|
|
313
|
+
container.register({
|
|
314
|
+
[name]: asClass(provider).singleton(),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
function registerExplicitClassProvider(provider, container, debug) {
|
|
318
|
+
const name = typeof provider.provide === 'string' ? provider.provide : camelCase(provider.provide.name);
|
|
319
|
+
const scope = provider.scope || 'SINGLETON';
|
|
320
|
+
if (debug) {
|
|
321
|
+
console.log(` - Registering ${name} (scope: ${scope})`);
|
|
322
|
+
}
|
|
323
|
+
const registration = asClass(provider.useClass);
|
|
324
|
+
container.register({
|
|
325
|
+
[name]: applyScopeToRegistration(registration, scope),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
function registerValueProvider(provider, container, debug) {
|
|
329
|
+
if (debug) {
|
|
330
|
+
console.log(` - Registering ${provider.provide} (value)`);
|
|
331
|
+
}
|
|
332
|
+
container.register({
|
|
333
|
+
[provider.provide]: asValue(provider.useValue),
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
function registerFactoryProvider(provider, container, debug) {
|
|
337
|
+
if (debug) {
|
|
338
|
+
console.log(` - Registering ${provider.provide} (factory)`);
|
|
339
|
+
}
|
|
340
|
+
container.register({
|
|
341
|
+
[provider.provide]: asValue(provider.useFactory(container)),
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
function applyScopeToRegistration(registration, scope) {
|
|
345
|
+
if (scope === 'SCOPED') {
|
|
346
|
+
return registration.scoped();
|
|
347
|
+
}
|
|
348
|
+
if (scope === 'TRANSIENT') {
|
|
349
|
+
return registration.transient();
|
|
350
|
+
}
|
|
351
|
+
return registration.singleton();
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Convert PascalCase to camelCase
|
|
355
|
+
*/
|
|
356
|
+
function camelCase(str) {
|
|
357
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"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"}
|