glasswork 0.1.0 → 0.1.1
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 +22 -43
- package/dist/http/error-response.dto.d.ts +76 -0
- package/dist/http/error-response.dto.d.ts.map +1 -0
- package/dist/http/error-response.dto.js +67 -0
- package/dist/http/error-response.dto.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/openapi/defaults.d.ts.map +1 -1
- package/dist/openapi/defaults.js +6 -38
- package/dist/openapi/defaults.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -4,51 +4,32 @@
|
|
|
4
4
|
[](https://www.typescriptlang.org/)
|
|
5
5
|
[](https://github.com/yourusername/glasswork)
|
|
6
6
|
|
|
7
|
-
**A transparent,
|
|
7
|
+
**A transparent, serverless-optimized web framework for building OpenAPI-compliant REST APIs.**
|
|
8
8
|
|
|
9
|
-
Built on Hono, Awilix, and
|
|
9
|
+
Built on Hono, Awilix, and Valibot, Glasswork provides automatic OpenAPI spec generation, type-safe routing, dependency injection, and clean modular architecture.
|
|
10
10
|
|
|
11
11
|
## Why Glasswork?
|
|
12
12
|
|
|
13
|
-
**
|
|
13
|
+
**NestJS-style architecture with serverless-first design.**
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Glasswork combines the best patterns from NestJS (modules, DI, OpenAPI) with the performance characteristics needed for serverless:
|
|
16
16
|
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
17
|
+
- **Small & Fast** - tiny bundles (~1MB incl Prisma), no decorators, no reflection
|
|
18
|
+
- **Clean Architecture** - Module system with dependency injection (Awilix)
|
|
19
|
+
- **OpenAPI Built-in** - Automatic spec generation from Valibot schemas
|
|
20
|
+
- **Framework-Agnostic Services** - Test business logic without HTTP mocking
|
|
21
|
+
- **Transparent** - Direct access to Hono, no heavy abstractions
|
|
22
22
|
|
|
23
|
-
|
|
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
|
|
23
|
+
**Perfect for:** Lambda-first projects, MVPs, hobby APIs, or anywhere you want NestJS patterns without the bundle size.
|
|
43
24
|
|
|
44
25
|
## Features
|
|
45
26
|
|
|
46
27
|
- **OpenAPI-First**: Automatic spec generation from Valibot schemas - write code, get docs
|
|
47
28
|
- **Type-Safe Routes**: Request/response validation with full TypeScript inference
|
|
48
29
|
- **Module System**: Organize your API into logical, testable modules
|
|
49
|
-
- **Dependency Injection**: Powered by Awilix with
|
|
30
|
+
- **Dependency Injection**: Powered by Awilix with serverless-compatible PROXY mode
|
|
50
31
|
- **Framework-Agnostic Services**: Test business logic without any HTTP mocking
|
|
51
|
-
- **
|
|
32
|
+
- **Production-Ready**: Small bundles, fast cold starts, works anywhere Node.js runs
|
|
52
33
|
|
|
53
34
|
## Installation
|
|
54
35
|
|
|
@@ -152,26 +133,24 @@ export default app; // Ready for Lambda or local server
|
|
|
152
133
|
|
|
153
134
|
## When to Use Glasswork
|
|
154
135
|
|
|
155
|
-
**Choose Glasswork
|
|
136
|
+
**Choose Glasswork when you want:**
|
|
156
137
|
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
- Prefer transparency over heavy abstractions
|
|
138
|
+
- NestJS-style architecture with smaller bundles
|
|
139
|
+
- Automatic OpenAPI generation without decorators
|
|
140
|
+
- Serverless-first design (Lambda, Cloudflare Workers, etc.)
|
|
141
|
+
- Clean, testable code with dependency injection
|
|
162
142
|
|
|
163
|
-
**Consider alternatives
|
|
143
|
+
**Consider alternatives:**
|
|
164
144
|
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
145
|
+
- **GraphQL?** Use Apollo Server or Pothos
|
|
146
|
+
- **Container deployment?** NestJS is excellent for this
|
|
147
|
+
- **Full-stack app?** Use Next.js or Remix
|
|
148
|
+
- **Minimal framework?** Use Hono directly
|
|
169
149
|
|
|
170
150
|
## Requirements
|
|
171
151
|
|
|
172
152
|
- Node.js 18+
|
|
173
153
|
- TypeScript 5+
|
|
174
|
-
- (Optional) AWS Lambda for serverless deployment
|
|
175
154
|
|
|
176
155
|
## Contributing
|
|
177
156
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type InferOutput } from 'valibot';
|
|
2
|
+
/**
|
|
3
|
+
* Standard error response for all non-validation errors
|
|
4
|
+
* Used for: 4xx and 5xx errors (except 422)
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* router.get('/users/:id', route({
|
|
9
|
+
* responses: {
|
|
10
|
+
* 200: UserDto,
|
|
11
|
+
* 404: ErrorResponseDto, // Not found
|
|
12
|
+
* },
|
|
13
|
+
* handler: async ({ params }) => {
|
|
14
|
+
* const user = await userService.findById(params.id);
|
|
15
|
+
* if (!user) throw new NotFoundException('User not found');
|
|
16
|
+
* return user;
|
|
17
|
+
* },
|
|
18
|
+
* }));
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare const ErrorResponseDto: import("valibot").ObjectSchema<{
|
|
22
|
+
readonly error: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 1000, undefined>]>;
|
|
23
|
+
}, undefined>;
|
|
24
|
+
export type ErrorResponse = InferOutput<typeof ErrorResponseDto>;
|
|
25
|
+
/**
|
|
26
|
+
* Validation issue - simplified version of Valibot's internal structure
|
|
27
|
+
* Only includes the fields typically needed for client-side error handling
|
|
28
|
+
*/
|
|
29
|
+
export declare const ValidationIssueDto: import("valibot").ObjectSchema<{
|
|
30
|
+
readonly message: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 500, undefined>]>;
|
|
31
|
+
readonly path: import("valibot").SchemaWithPipe<readonly [import("valibot").ArraySchema<import("valibot").UnionSchema<[import("valibot").StringSchema<undefined>, import("valibot").NumberSchema<undefined>], undefined>, undefined>, import("valibot").MaxLengthAction<(string | number)[], 20, undefined>]>;
|
|
32
|
+
}, undefined>;
|
|
33
|
+
export type ValidationIssue = InferOutput<typeof ValidationIssueDto>;
|
|
34
|
+
/**
|
|
35
|
+
* Validation error response (422 Unprocessable Entity)
|
|
36
|
+
* Returned when request body, query params, or path params fail validation
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* router.post('/users', route({
|
|
41
|
+
* body: CreateUserDto,
|
|
42
|
+
* responses: {
|
|
43
|
+
* 201: UserDto,
|
|
44
|
+
* 422: ValidationErrorResponseDto, // Validation failed
|
|
45
|
+
* },
|
|
46
|
+
* handler: async ({ body }) => {
|
|
47
|
+
* return userService.create(body);
|
|
48
|
+
* },
|
|
49
|
+
* }));
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* Response format:
|
|
53
|
+
* ```json
|
|
54
|
+
* {
|
|
55
|
+
* "error": "Validation failed",
|
|
56
|
+
* "issues": [
|
|
57
|
+
* {
|
|
58
|
+
* "message": "Invalid email",
|
|
59
|
+
* "path": ["email"]
|
|
60
|
+
* }
|
|
61
|
+
* ]
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare const ValidationErrorResponseDto: import("valibot").ObjectSchema<{
|
|
66
|
+
readonly error: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 1000, undefined>]>;
|
|
67
|
+
readonly issues: import("valibot").SchemaWithPipe<readonly [import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
68
|
+
readonly message: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 500, undefined>]>;
|
|
69
|
+
readonly path: import("valibot").SchemaWithPipe<readonly [import("valibot").ArraySchema<import("valibot").UnionSchema<[import("valibot").StringSchema<undefined>, import("valibot").NumberSchema<undefined>], undefined>, undefined>, import("valibot").MaxLengthAction<(string | number)[], 20, undefined>]>;
|
|
70
|
+
}, undefined>, undefined>, import("valibot").MaxLengthAction<{
|
|
71
|
+
message: string;
|
|
72
|
+
path: (string | number)[];
|
|
73
|
+
}[], 100, undefined>]>;
|
|
74
|
+
}, undefined>;
|
|
75
|
+
export type ValidationErrorResponse = InferOutput<typeof ValidationErrorResponseDto>;
|
|
76
|
+
//# sourceMappingURL=error-response.dto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-response.dto.d.ts","sourceRoot":"","sources":["../../src/http/error-response.dto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,WAAW,EAAkD,MAAM,SAAS,CAAC;AAElG;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB;;aAE3B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;aAG7B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;aAGrC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,WAAW,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { array, maxLength, number, object, pipe, string, union } from 'valibot';
|
|
2
|
+
/**
|
|
3
|
+
* Standard error response for all non-validation errors
|
|
4
|
+
* Used for: 4xx and 5xx errors (except 422)
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* router.get('/users/:id', route({
|
|
9
|
+
* responses: {
|
|
10
|
+
* 200: UserDto,
|
|
11
|
+
* 404: ErrorResponseDto, // Not found
|
|
12
|
+
* },
|
|
13
|
+
* handler: async ({ params }) => {
|
|
14
|
+
* const user = await userService.findById(params.id);
|
|
15
|
+
* if (!user) throw new NotFoundException('User not found');
|
|
16
|
+
* return user;
|
|
17
|
+
* },
|
|
18
|
+
* }));
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export const ErrorResponseDto = object({
|
|
22
|
+
error: pipe(string(), maxLength(1000)),
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Validation issue - simplified version of Valibot's internal structure
|
|
26
|
+
* Only includes the fields typically needed for client-side error handling
|
|
27
|
+
*/
|
|
28
|
+
export const ValidationIssueDto = object({
|
|
29
|
+
message: pipe(string(), maxLength(500)),
|
|
30
|
+
path: pipe(array(union([string(), number()])), maxLength(20)),
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Validation error response (422 Unprocessable Entity)
|
|
34
|
+
* Returned when request body, query params, or path params fail validation
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* router.post('/users', route({
|
|
39
|
+
* body: CreateUserDto,
|
|
40
|
+
* responses: {
|
|
41
|
+
* 201: UserDto,
|
|
42
|
+
* 422: ValidationErrorResponseDto, // Validation failed
|
|
43
|
+
* },
|
|
44
|
+
* handler: async ({ body }) => {
|
|
45
|
+
* return userService.create(body);
|
|
46
|
+
* },
|
|
47
|
+
* }));
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Response format:
|
|
51
|
+
* ```json
|
|
52
|
+
* {
|
|
53
|
+
* "error": "Validation failed",
|
|
54
|
+
* "issues": [
|
|
55
|
+
* {
|
|
56
|
+
* "message": "Invalid email",
|
|
57
|
+
* "path": ["email"]
|
|
58
|
+
* }
|
|
59
|
+
* ]
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export const ValidationErrorResponseDto = object({
|
|
64
|
+
error: pipe(string(), maxLength(1000)),
|
|
65
|
+
issues: pipe(array(ValidationIssueDto), maxLength(100)),
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=error-response.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-response.dto.js","sourceRoot":"","sources":["../../src/http/error-response.dto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAoB,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAElG;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;IACrC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;CACvC,CAAC,CAAC;AAIH;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;CAC9D,CAAC,CAAC;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;IAC/C,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;CACxD,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { bootstrap } from './core/bootstrap.js';
|
|
|
12
12
|
export { defineModule } from './core/module.js';
|
|
13
13
|
export type { BootstrapOptions, BootstrapResult, Constructor, Environment, LoggerOptions, MiddlewareOptions, ModuleConfig, OpenAPIDocumentation, OpenAPIOptions, OpenAPIResponseHook, ProviderConfig, RateLimitOptions, RateLimitStorage, ServiceScope, } from './core/types.js';
|
|
14
14
|
export { createErrorHandler, defaultErrorHandler } from './http/error-handler.js';
|
|
15
|
+
export { type ErrorResponse, ErrorResponseDto, type ValidationErrorResponse, ValidationErrorResponseDto, type ValidationIssue, ValidationIssueDto, } from './http/error-response.dto.js';
|
|
15
16
|
export { BadRequestException, ConflictException, DomainException, ForbiddenException, NotFoundException, TooManyRequestsException, UnauthorizedException, ValidationException, } from './http/errors.js';
|
|
16
17
|
export type { RouteConfig, RouteContext, RouteFactory, ValibotSchema, } from './http/route-helpers.js';
|
|
17
18
|
export { createRoutes, route } from './http/route-helpers.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EACL,KAAK,aAAa,EAClB,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,0BAA0B,EAC1B,KAAK,eAAe,EACpB,kBAAkB,GACnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
export { bootstrap } from './core/bootstrap.js';
|
|
10
10
|
export { defineModule } from './core/module.js';
|
|
11
11
|
export { createErrorHandler, defaultErrorHandler } from './http/error-handler.js';
|
|
12
|
+
export { ErrorResponseDto, ValidationErrorResponseDto, ValidationIssueDto, } from './http/error-response.dto.js';
|
|
12
13
|
export { BadRequestException, ConflictException, DomainException, ForbiddenException, NotFoundException, TooManyRequestsException, UnauthorizedException, ValidationException, } from './http/errors.js';
|
|
13
14
|
export { createRoutes, route } from './http/route-helpers.js';
|
|
14
15
|
// Middleware
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,iBAAiB;AACjB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAiBhD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAC9D,aAAa;AACb,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,UAAU;AACV,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,YAAY;AACZ,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,iBAAiB;AACjB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAiBhD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAEL,gBAAgB,EAEhB,0BAA0B,EAE1B,kBAAkB,GACnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAC9D,aAAa;AACb,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,UAAU;AACV,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,YAAY;AACZ,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/openapi/defaults.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/openapi/defaults.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAO/C;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,CAAC,gBAqFhD,CAAC"}
|
package/dist/openapi/defaults.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { toJsonSchema } from '@valibot/to-json-schema';
|
|
2
|
+
import { ErrorResponseDto, ValidationErrorResponseDto, ValidationIssueDto, } from '../http/error-response.dto.js';
|
|
1
3
|
/**
|
|
2
4
|
* Default OpenAPI components provided by Glasswork.
|
|
3
5
|
* These include headers for features implemented by the framework:
|
|
@@ -8,44 +10,10 @@
|
|
|
8
10
|
*/
|
|
9
11
|
export const defaultOpenAPIComponents = {
|
|
10
12
|
schemas: {
|
|
11
|
-
// Error response schemas
|
|
12
|
-
ErrorResponse:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
properties: {
|
|
16
|
-
error: {
|
|
17
|
-
type: 'string',
|
|
18
|
-
maxLength: 1000,
|
|
19
|
-
pattern: '^[\\s\\S]*$', // Any characters including whitespace
|
|
20
|
-
description: 'Error message',
|
|
21
|
-
},
|
|
22
|
-
issues: {
|
|
23
|
-
type: 'array',
|
|
24
|
-
maxItems: 100,
|
|
25
|
-
items: {
|
|
26
|
-
type: 'object',
|
|
27
|
-
required: ['message'],
|
|
28
|
-
properties: {
|
|
29
|
-
message: {
|
|
30
|
-
type: 'string',
|
|
31
|
-
maxLength: 500,
|
|
32
|
-
},
|
|
33
|
-
path: {
|
|
34
|
-
type: 'array',
|
|
35
|
-
maxItems: 20,
|
|
36
|
-
items: {
|
|
37
|
-
oneOf: [
|
|
38
|
-
{ type: 'string', maxLength: 200 },
|
|
39
|
-
{ type: 'number', format: 'int32' },
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
description: 'Validation error details',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
},
|
|
13
|
+
// Error response schemas - converted from Valibot DTOs
|
|
14
|
+
ErrorResponse: toJsonSchema(ErrorResponseDto),
|
|
15
|
+
ValidationErrorResponse: toJsonSchema(ValidationErrorResponseDto),
|
|
16
|
+
ValidationIssue: toJsonSchema(ValidationIssueDto),
|
|
49
17
|
},
|
|
50
18
|
headers: {
|
|
51
19
|
// CORS headers
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/openapi/defaults.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/openapi/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAA+B;IAClE,OAAO,EAAE;QACP,uDAAuD;QACvD,aAAa,EAAE,YAAY,CAAC,gBAAgB,CAA2B;QACvE,uBAAuB,EAAE,YAAY,CAAC,0BAA0B,CAA2B;QAC3F,eAAe,EAAE,YAAY,CAAC,kBAAkB,CAA2B;KAC5E;IACD,OAAO,EAAE;QACP,eAAe;QACf,6BAA6B,EAAE;YAC7B,WAAW,EAAE,kCAAkC;YAC/C,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,qCAAqC;aAC/C;SACF;QAED,6CAA6C;QAC7C,iBAAiB,EAAE;YACjB,WAAW,EAAE,mDAAmD;YAChE,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,KAAK;aACf;SACF;QACD,qBAAqB,EAAE;YACrB,WAAW,EAAE,0CAA0C;YACvD,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,KAAK;aACf;SACF;QACD,iBAAiB,EAAE;YACjB,WAAW,EAAE,4CAA4C;YACzD,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,IAAI;aACd;SACF;QACD,aAAa,EAAE;YACb,WAAW,EAAE,4DAA4D;YACzE,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,IAAI;aACd;SACF;QAED,0CAA0C;QAC1C,eAAe,EAAE;YACf,WAAW,EAAE,iCAAiC;YAC9C,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,UAAU,EAAE,YAAY;aAClC;SACF;QACD,QAAQ,EAAE;YACR,WAAW,EAAE,qBAAqB;YAClC,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,UAAU,EAAE,YAAY;aAClC;SACF;QACD,SAAS,EAAE;YACT,WAAW,EAAE,0BAA0B;YACvC,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,GAAG;aACb;SACF;KACF;CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glasswork",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A transparent, Lambda-optimized web framework for building OpenAPI-compliant REST APIs.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
10
11
|
"import": "./dist/index.js",
|
|
11
|
-
"
|
|
12
|
+
"default": "./dist/index.js"
|
|
12
13
|
},
|
|
13
14
|
"./package.json": "./package.json"
|
|
14
15
|
},
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
"dev": "tsc --watch",
|
|
50
51
|
"test": "vitest",
|
|
51
52
|
"test:coverage": "vitest --coverage",
|
|
53
|
+
"lint": "biome check . --write",
|
|
52
54
|
"prepublishOnly": "npm run build && npm test"
|
|
53
55
|
},
|
|
54
56
|
"publishConfig": {
|