@getsoda/core 0.2.1 → 0.3.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 (137) hide show
  1. package/README.md +103 -0
  2. package/dist/app/app.d.ts +15 -5
  3. package/dist/app/app.d.ts.map +1 -1
  4. package/dist/app/app.js +31 -8
  5. package/dist/app/app.js.map +1 -1
  6. package/dist/app/index.d.ts +1 -1
  7. package/dist/app/index.d.ts.map +1 -1
  8. package/dist/config/config.d.ts +57 -0
  9. package/dist/config/config.d.ts.map +1 -0
  10. package/dist/config/config.js +74 -0
  11. package/dist/config/config.js.map +1 -0
  12. package/dist/config/index.d.ts +9 -0
  13. package/dist/config/index.d.ts.map +1 -0
  14. package/dist/config/index.js +7 -0
  15. package/dist/config/index.js.map +1 -0
  16. package/dist/config/module.d.ts +29 -0
  17. package/dist/config/module.d.ts.map +1 -0
  18. package/dist/config/module.js +28 -0
  19. package/dist/config/module.js.map +1 -0
  20. package/dist/di/errors.d.ts.map +1 -1
  21. package/dist/di/errors.js +2 -0
  22. package/dist/di/errors.js.map +1 -1
  23. package/dist/http/arguments.d.ts +19 -6
  24. package/dist/http/arguments.d.ts.map +1 -1
  25. package/dist/http/arguments.js +7 -0
  26. package/dist/http/arguments.js.map +1 -1
  27. package/dist/http/cookies.d.ts.map +1 -1
  28. package/dist/http/cookies.js +2 -0
  29. package/dist/http/cookies.js.map +1 -1
  30. package/dist/http/decorators.d.ts +18 -6
  31. package/dist/http/decorators.d.ts.map +1 -1
  32. package/dist/http/decorators.js +7 -2
  33. package/dist/http/decorators.js.map +1 -1
  34. package/dist/http/errors.d.ts +3 -1
  35. package/dist/http/errors.d.ts.map +1 -1
  36. package/dist/http/errors.js +2 -0
  37. package/dist/http/errors.js.map +1 -1
  38. package/dist/http/index.d.ts +7 -5
  39. package/dist/http/index.d.ts.map +1 -1
  40. package/dist/http/index.js +3 -2
  41. package/dist/http/index.js.map +1 -1
  42. package/dist/http/parsers.d.ts +4 -0
  43. package/dist/http/parsers.d.ts.map +1 -1
  44. package/dist/http/parsers.js +9 -5
  45. package/dist/http/parsers.js.map +1 -1
  46. package/dist/http/pipeline.d.ts +4 -5
  47. package/dist/http/pipeline.d.ts.map +1 -1
  48. package/dist/http/pipeline.js +2 -2
  49. package/dist/http/pipeline.js.map +1 -1
  50. package/dist/http/routes.d.ts +27 -2
  51. package/dist/http/routes.d.ts.map +1 -1
  52. package/dist/http/routes.js +34 -20
  53. package/dist/http/routes.js.map +1 -1
  54. package/dist/http/schema.d.ts +2 -0
  55. package/dist/http/schema.d.ts.map +1 -1
  56. package/dist/http/schema.js +2 -1
  57. package/dist/http/schema.js.map +1 -1
  58. package/dist/http/sse.d.ts +39 -0
  59. package/dist/http/sse.d.ts.map +1 -0
  60. package/dist/http/sse.js +89 -0
  61. package/dist/http/sse.js.map +1 -0
  62. package/dist/index.d.ts +2 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +2 -0
  65. package/dist/index.js.map +1 -1
  66. package/dist/openapi/decorators.d.ts +41 -0
  67. package/dist/openapi/decorators.d.ts.map +1 -0
  68. package/dist/openapi/decorators.js +29 -0
  69. package/dist/openapi/decorators.js.map +1 -0
  70. package/dist/openapi/document.d.ts +62 -0
  71. package/dist/openapi/document.d.ts.map +1 -0
  72. package/dist/openapi/document.js +135 -0
  73. package/dist/openapi/document.js.map +1 -0
  74. package/dist/openapi/index.d.ts +11 -0
  75. package/dist/openapi/index.d.ts.map +1 -0
  76. package/dist/openapi/index.js +8 -0
  77. package/dist/openapi/index.js.map +1 -0
  78. package/dist/openapi/module.d.ts +26 -0
  79. package/dist/openapi/module.d.ts.map +1 -0
  80. package/dist/openapi/module.js +73 -0
  81. package/dist/openapi/module.js.map +1 -0
  82. package/dist/routing/errors.d.ts.map +1 -1
  83. package/dist/routing/errors.js +2 -0
  84. package/dist/routing/errors.js.map +1 -1
  85. package/dist/testing/index.d.ts +46 -0
  86. package/dist/testing/index.d.ts.map +1 -0
  87. package/dist/testing/index.js +49 -0
  88. package/dist/testing/index.js.map +1 -0
  89. package/dist/utils/errors.d.ts +11 -0
  90. package/dist/utils/errors.d.ts.map +1 -0
  91. package/dist/utils/errors.js +22 -0
  92. package/dist/utils/errors.js.map +1 -0
  93. package/dist/utils/object.d.ts +4 -0
  94. package/dist/utils/object.d.ts.map +1 -1
  95. package/dist/utils/object.js +16 -0
  96. package/dist/utils/object.js.map +1 -1
  97. package/dist/websocket/decorators.d.ts +31 -0
  98. package/dist/websocket/decorators.d.ts.map +1 -0
  99. package/dist/websocket/decorators.js +43 -0
  100. package/dist/websocket/decorators.js.map +1 -0
  101. package/dist/websocket/gateway.d.ts +61 -0
  102. package/dist/websocket/gateway.d.ts.map +1 -0
  103. package/dist/websocket/gateway.js +142 -0
  104. package/dist/websocket/gateway.js.map +1 -0
  105. package/dist/websocket/index.d.ts +7 -0
  106. package/dist/websocket/index.d.ts.map +1 -0
  107. package/dist/websocket/index.js +6 -0
  108. package/dist/websocket/index.js.map +1 -0
  109. package/package.json +12 -1
  110. package/src/app/app.ts +69 -18
  111. package/src/app/index.ts +1 -1
  112. package/src/config/config.ts +90 -0
  113. package/src/config/index.ts +9 -0
  114. package/src/config/module.ts +40 -0
  115. package/src/di/errors.ts +3 -0
  116. package/src/http/arguments.ts +31 -6
  117. package/src/http/cookies.ts +2 -0
  118. package/src/http/decorators.ts +25 -10
  119. package/src/http/errors.ts +7 -0
  120. package/src/http/index.ts +7 -4
  121. package/src/http/parsers.ts +18 -7
  122. package/src/http/pipeline.ts +6 -6
  123. package/src/http/routes.ts +68 -29
  124. package/src/http/schema.ts +2 -1
  125. package/src/http/sse.ts +120 -0
  126. package/src/index.ts +2 -0
  127. package/src/openapi/decorators.ts +50 -0
  128. package/src/openapi/document.ts +221 -0
  129. package/src/openapi/index.ts +11 -0
  130. package/src/openapi/module.ts +95 -0
  131. package/src/routing/errors.ts +3 -0
  132. package/src/testing/index.ts +73 -0
  133. package/src/utils/errors.ts +25 -0
  134. package/src/utils/object.ts +23 -0
  135. package/src/websocket/decorators.ts +55 -0
  136. package/src/websocket/gateway.ts +213 -0
  137. package/src/websocket/index.ts +7 -0
package/README.md CHANGED
@@ -72,6 +72,29 @@ app.enableShutdownSignals()
72
72
  await app.listen(3000)
73
73
  ```
74
74
 
75
+ ## Configuration
76
+
77
+ A configuration is a schema over the environment (Bun loads `.env` files into it), validated when the application starts and injected with its type:
78
+
79
+ ```ts
80
+ import { ConfigModule, defineConfig } from '@getsoda/core'
81
+ import { z } from 'zod'
82
+
83
+ export const AppConfig = defineConfig('app', z.object({
84
+ PORT: z.coerce.number().default(3000),
85
+ JWT_SECRET: z.string().min(32),
86
+ }))
87
+
88
+ @Module({ imports: [ConfigModule.forRoot({ load: [AppConfig], global: true })] })
89
+ class AppModule {}
90
+
91
+ class AuthService {
92
+ readonly #config = inject(AppConfig) // { PORT: number; JWT_SECRET: string }
93
+ }
94
+ ```
95
+
96
+ An invalid environment stops the startup with every issue listed. `defineConfig(name, schema, (env) => ({ ... }))` builds nested configurations; tests replace one with `overrides: [provide(AppConfig, { useValue })]`.
97
+
75
98
  ## Cookies
76
99
 
77
100
  `ctx.cookies` is Bun's `CookieMap` for the request: what you set or delete is sent with the response, whatever the response is. Signed cookies can be read by the client but not forged:
@@ -97,6 +120,44 @@ class SessionController {
97
120
 
98
121
  Name cookies that guard sessions with the `__Host-` prefix: browsers then refuse them from subdomains and over HTTP.
99
122
 
123
+ ## Server-sent events
124
+
125
+ An `@Sse()` route returns an async iterable of messages, streamed as `text/event-stream`; when the client disconnects, the generator is returned and its `finally` runs:
126
+
127
+ ```ts
128
+ @Sse('ticks')
129
+ async *ticks(): AsyncGenerator<SseMessage> {
130
+ for (let i = 0; ; i++) {
131
+ yield { data: { tick: i }, id: String(i) } // also event and retry
132
+ await Bun.sleep(1000)
133
+ }
134
+ }
135
+ ```
136
+
137
+ ## WebSockets
138
+
139
+ A gateway is listed in `controllers` like a controller; its guards run on the handshake, and frames follow the protocol of Nest's `WsAdapter`, `{ "event": "...", "data": ... }`:
140
+
141
+ ```ts
142
+ @WebSocketGateway('/chat')
143
+ @UseGuards(JwtGuard) // browsers send cookies with the handshake
144
+ class ChatGateway implements OnGatewayConnection {
145
+ handleConnection(socket: GatewaySocket) {
146
+ socket.subscribe('room')
147
+ }
148
+
149
+ @SubscribeMessage('say')
150
+ say(data: string, socket: GatewaySocket) {
151
+ const user = socket.data.context.get(JWT_PAYLOAD).sub
152
+
153
+ socket.publish('room', JSON.stringify({ event: 'said', data: { user, text: data } }))
154
+ return { event: 'sent' } // sent back to this socket
155
+ }
156
+ }
157
+ ```
158
+
159
+ `socket` is Bun's `ServerWebSocket`, with its pub/sub. Frames that are not such JSON are dropped; when the application closes, sockets are closed with code 1001.
160
+
100
161
  ## JWT
101
162
 
102
163
  `@getsoda/core/jwt` signs and verifies JSON Web Tokens with WebCrypto: HS256/384/512, RS, PS, ES and EdDSA, keys as secrets, PEM, JWK or `CryptoKey`. The algorithm is fixed by the options, never read from the token, so `alg: none` and algorithm confusion are refused.
@@ -130,6 +191,48 @@ class AuthModule {}
130
191
 
131
192
  `JwtModule.registerAsync({ inject, useFactory })` takes the options from other providers; `new JwtService(options)` works without the module.
132
193
 
194
+ ## OpenAPI
195
+
196
+ `@getsoda/core/openapi` describes the routes from what validates them: argument parsers and schemas implementing [Standard JSON Schema](https://standardschema.dev) (zod does). Import the module to serve the document and a Swagger UI page:
197
+
198
+ ```ts
199
+ import { ApiBearerAuth, ApiOperation, ApiResponses, ApiTags, OpenApiModule } from '@getsoda/core/openapi'
200
+
201
+ @Controller('users')
202
+ @ApiTags('users')
203
+ class UsersController {
204
+ @Get(':id', [param('id', int())])
205
+ @ApiOperation({ summary: 'One user' })
206
+ @ApiResponses({ 200: { description: 'The user', schema: User }, 404: { description: 'No such user' } })
207
+ findOne(id: number) {}
208
+ }
209
+
210
+ @Module({ imports: [OpenApiModule.forRoot({ info: { title: 'Shop', version: '1.0.0' }, ui: '/docs' })] })
211
+ class AppModule {}
212
+ ```
213
+
214
+ `/openapi.json` and `/docs` follow the global prefix; `@ApiExclude()` leaves a route out, `createOpenApiDocument(inject(ROUTES).controllers, options)` gives the document itself.
215
+
216
+ ## Testing
217
+
218
+ `@getsoda/core/testing` serves the application on a free port with a silent logger; `overrides` replace providers, as Nest's `overrideProvider()`:
219
+
220
+ ```ts
221
+ import { createTestApp } from '@getsoda/core/testing'
222
+
223
+ const app = await createTestApp(AppModule, { overrides: [provide(Mailer, { useValue: fakeMailer })] })
224
+
225
+ afterAll(() => app.close()) // or `await using app = ...` in a block
226
+
227
+ test('signs up', async () => {
228
+ const response = await app.request('/users', { method: 'POST', json: { name: 'Bo' } })
229
+
230
+ expect(response.status).toBe(201)
231
+ })
232
+ ```
233
+
234
+ A single service needs no server: `createContainer(UsersModule, { overrides })`.
235
+
133
236
  ## License
134
237
 
135
238
  [MIT](./LICENSE)
package/dist/app/app.d.ts CHANGED
@@ -21,7 +21,8 @@
21
21
  import type { Container, ContainerOptions, ModuleImport } from '../di/index.ts';
22
22
  import type { ControllerRoutesOptions, Middleware } from '../http/index.ts';
23
23
  import { Logger } from '../logger/index.ts';
24
- import type { CompiledRoutes, CompileOptions } from '../routing/index.ts';
24
+ import type { CompiledRoutes, CompileOptions, NativeHandler } from '../routing/index.ts';
25
+ import type { BuiltGateway, GatewaySocketData } from '../websocket/gateway.ts';
25
26
  /**
26
27
  * Options of `createApp`.
27
28
  */
@@ -54,16 +55,16 @@ export interface ListenOptions {
54
55
  */
55
56
  export interface App {
56
57
  readonly container: Container;
57
- /** Routes for `Bun.serve()`, when serving them yourself instead of calling `listen()`. */
58
- readonly routes: CompiledRoutes;
58
+ /** Routes (and WebSocket handlers) for `Bun.serve()`, when serving them yourself instead of calling `listen()`. */
59
+ readonly routes: ServeRoutes;
59
60
  /** The server once `listen()` resolved. */
60
- readonly server: Bun.Server<undefined> | undefined;
61
+ readonly server: Bun.Server<GatewaySocketData> | undefined;
61
62
  /**
62
63
  * Starts serving. Under `bun --hot`, a new version of the application
63
64
  * listening on the same port takes the server over from the previous one,
64
65
  * which is then destroyed (its server is not stopped: it is shared).
65
66
  */
66
- listen(options?: number | ListenOptions): Promise<Bun.Server<undefined>>;
67
+ listen(options?: number | ListenOptions): Promise<Bun.Server<GatewaySocketData>>;
67
68
  /**
68
69
  * Graceful shutdown: refuses new requests, waits for those in flight, then
69
70
  * runs `onDestroy` hooks. Safe to call more than once, even from a hook.
@@ -75,6 +76,15 @@ export interface App {
75
76
  */
76
77
  enableShutdownSignals(signals?: readonly NodeJS.Signals[]): this;
77
78
  }
79
+ /**
80
+ * Routes and WebSocket handlers for `Bun.serve()`: the handshakes of gateways
81
+ * are native routes of their own, outside middleware, as an upgrade returns no response.
82
+ */
83
+ export interface ServeRoutes {
84
+ readonly routes: Record<string, NativeHandler | BuiltGateway['handle']>;
85
+ readonly fetch: CompiledRoutes['fetch'];
86
+ readonly websocket: Bun.WebSocketHandler<GatewaySocketData>;
87
+ }
78
88
  /**
79
89
  * Creates the container and the routes, and runs every `onInit` hook.
80
90
  *
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAG/E,OAAO,KAAK,EAAE,uBAAuB,EAAoB,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7F,OAAO,EAAiB,MAAM,EAAgB,MAAM,oBAAoB,CAAA;AAExE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAGzE;;GAEG;AACH,MAAM,WAAW,UAAW,SAAQ,gBAAgB,EAAE,uBAAuB,EAAE,cAAc;IAC3F;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,UAAU,EAAE,CAAA;IAC3C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CACrC;AAKD;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA;IAClD;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAA;IACxE;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB;;;OAGG;IACH,qBAAqB,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAA;CACjE;AA+KD;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,SAAgB,YAAY,YAAW,UAAU,KAAQ,OAAO,CAAC,GAAG,CA2CzF,CAAA"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAG/E,OAAO,KAAK,EAAE,uBAAuB,EAAoB,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7F,OAAO,EAAiB,MAAM,EAAgB,MAAM,oBAAoB,CAAA;AAExE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExF,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAG9E;;GAEG;AACH,MAAM,WAAW,UAAW,SAAQ,gBAAgB,EAAE,uBAAuB,EAAE,cAAc;IAC3F;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,UAAU,EAAE,CAAA;IAC3C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CACrC;AAKD;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,mHAAmH;IACnH,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAA;IAC1D;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAA;IAChF;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB;;;OAGG;IACH,qBAAqB,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAA;CACjE;AA0KD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAA;IACvE,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;IACvC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAA;CAC5D;AA2CD;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,SAAgB,YAAY,YAAW,UAAU,KAAQ,OAAO,CAAC,GAAG,CA8CzF,CAAA"}
package/dist/app/app.js CHANGED
@@ -20,11 +20,12 @@
20
20
  */
21
21
  import { createContainer, provide } from '../di/index.js';
22
22
  import { destroyAll, initializeAll } from '../di/lifecycle.js';
23
- import { buildRoutes } from '../http/index.js';
23
+ import { buildRoutes, ControllerError, ROUTES } from '../http/index.js';
24
24
  import { errorResponse } from '../http/exceptions.js';
25
25
  import { applyMiddleware, resolveMiddleware } from '../http/middleware.js';
26
26
  import { ConsoleLogger, Logger, SilentLogger } from '../logger/index.js';
27
27
  import { compileRoutes } from '../routing/index.js';
28
+ import { websocketHandler } from '../websocket/gateway.js';
28
29
  import { release, takeOver } from './hot.js';
29
30
  /** Signals `enableShutdownSignals()` listens to by default. */
30
31
  const DEFAULT_SIGNALS = ['SIGTERM', 'SIGINT'];
@@ -38,9 +39,11 @@ class Application {
38
39
  #enhancers;
39
40
  #signals = new Map();
40
41
  #logger;
41
- constructor(container, routes, enhancers, logger) {
42
+ #gateways;
43
+ constructor(container, routes, gateways, enhancers, logger) {
42
44
  this.container = container;
43
45
  this.routes = routes;
46
+ this.#gateways = gateways;
44
47
  this.#enhancers = enhancers;
45
48
  this.#logger = logger;
46
49
  }
@@ -104,6 +107,10 @@ class Application {
104
107
  async #shutdown() {
105
108
  const server = this.#server;
106
109
  try {
110
+ // Open sockets would keep stop() waiting; under --hot, clients reconnect to the new version.
111
+ for (const gateway of this.#gateways) {
112
+ gateway.runtime.closeAll();
113
+ }
107
114
  if (server !== undefined && !this.#handedOver) {
108
115
  await server.stop();
109
116
  }
@@ -150,8 +157,18 @@ const destroyEverything = async (enhancers, container) => {
150
157
  throw new AggregateError(errors, `${errors.length} onDestroy hooks failed`);
151
158
  }
152
159
  };
160
+ const withGateways = (compiled, gateways) => {
161
+ const routes = { ...compiled.routes };
162
+ for (const gateway of gateways) {
163
+ if (Object.hasOwn(routes, gateway.path)) {
164
+ throw new ControllerError('DUPLICATE_ROUTE', `The WebSocket gateway on ${gateway.path} has the path of another gateway or route`);
165
+ }
166
+ routes[gateway.path] = gateway.handle;
167
+ }
168
+ return { routes, fetch: compiled.fetch, websocket: websocketHandler };
169
+ };
153
170
  /** What Nest logs at startup: the modules, then each controller and its routes. */
154
- const logStartup = (logger, container, controllers) => {
171
+ const logStartup = (logger, container, controllers, gateways) => {
155
172
  const modules = logger.child('Container');
156
173
  const routes = logger.child('Routes');
157
174
  for (const module of container.modules) {
@@ -159,10 +176,13 @@ const logStartup = (logger, container, controllers) => {
159
176
  }
160
177
  for (const { controller, path, routes: mapped } of controllers) {
161
178
  routes.log(`${controller.name} {${path}}:`);
162
- for (const route of mapped) {
163
- routes.log(`Mapped {${route.path}, ${route.method}} route`);
179
+ for (const { info } of mapped) {
180
+ routes.log(`Mapped {${info.path}, ${info.method}} route`);
164
181
  }
165
182
  }
183
+ for (const gateway of gateways) {
184
+ routes.log(`WebSocket gateway {${gateway.path}}, events: ${gateway.runtime.events.join(', ') || 'none'}`);
185
+ }
166
186
  };
167
187
  /**
168
188
  * Creates the container and the routes, and runs every `onInit` hook.
@@ -177,9 +197,11 @@ export const createApp = async (root, options = {}) => {
177
197
  const onError = options.onError ??
178
198
  ((error, req) => own.error('Unhandled error while handling a request', { error, method: req.method, url: req.url }));
179
199
  own.log('Starting application');
200
+ // Filled once the routes are built; read by what describes them (OpenAPI).
201
+ const registry = { controllers: [] };
180
202
  const container = await createContainer(root, {
181
203
  ...options,
182
- providers: [...(options.providers ?? []), provide(Logger, { useValue: logger })],
204
+ providers: [...(options.providers ?? []), provide(Logger, { useValue: logger }), provide(ROUTES, { useValue: registry })],
183
205
  });
184
206
  const enhancers = [];
185
207
  try {
@@ -188,13 +210,14 @@ export const createApp = async (root, options = {}) => {
188
210
  enhancers.push(instance);
189
211
  });
190
212
  const built = buildRoutes(container, { ...options, onError });
191
- logStartup(logger, container, built.controllers);
213
+ registry.controllers = built.controllers;
214
+ logStartup(logger, container, built.controllers, built.gateways);
192
215
  enhancers.push(...built.enhancers);
193
216
  await initializeAll(enhancers);
194
217
  own.log('Application started');
195
218
  const compiled = compileRoutes(built.routes, options);
196
219
  const routes = applyMiddleware(middleware, compiled.routes, compiled.fetch, (error, req) => errorResponse(error, (unknown) => onError(unknown, req)));
197
- return new Application(container, routes, enhancers, own);
220
+ return new Application(container, withGateways(routes, built.gateways), built.gateways, enhancers, own);
198
221
  }
199
222
  catch (error) {
200
223
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app/app.ts"],"names":[],"mappings":"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"}
@@ -3,5 +3,5 @@
3
3
  * The application: container, routes and server, started and stopped together.
4
4
  */
5
5
  export { createApp } from './app.ts';
6
- export type { App, AppOptions, ListenOptions } from './app.ts';
6
+ export type { App, AppOptions, ListenOptions, ServeRoutes } from './app.ts';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @module
3
+ * Configuration typed by a schema and validated at startup.
4
+ *
5
+ * What `@nestjs/config` does with `registerAs()` and a `validationSchema`,
6
+ * typed by the schema instead of read with string keys. Bun already loads
7
+ * `.env`, `.env.local` and `.env.<NODE_ENV>` into `process.env`.
8
+ *
9
+ * ```ts
10
+ * export const AppConfig = defineConfig('app', z.object({
11
+ * PORT: z.coerce.number().default(3000),
12
+ * JWT_SECRET: z.string().min(32),
13
+ * }))
14
+ *
15
+ * @Module({ imports: [ConfigModule.forRoot({ load: [AppConfig], global: true })] })
16
+ * class AppModule {}
17
+ *
18
+ * class AuthService {
19
+ * readonly #config = inject(AppConfig) // { PORT: number; JWT_SECRET: string }
20
+ * }
21
+ * ```
22
+ */
23
+ import { InjectionToken } from '../di/token.ts';
24
+ import type { InferOutput, StandardSchemaV1 } from '../http/schema.ts';
25
+ /** Environment variables, as in `process.env`. */
26
+ export type Environment = Readonly<Record<string, string | undefined>>;
27
+ /** A configuration that does not match its schema; `issues` lists every problem. */
28
+ export declare class ConfigError extends Error {
29
+ readonly config: string;
30
+ readonly issues: readonly string[];
31
+ readonly name = "ConfigError";
32
+ constructor(config: string, issues: readonly string[]);
33
+ }
34
+ /**
35
+ * A configuration, and the DI token of its value: `inject(AppConfig)`.
36
+ * `ConfigModule.forRoot()` loads it at startup; `load()` works without DI.
37
+ */
38
+ export declare class Config<T> extends InjectionToken<T> {
39
+ #private;
40
+ constructor(name: string, schema: StandardSchemaV1<unknown, T>, source: (env: Environment) => unknown);
41
+ /** The value read from `env` and validated; throws a {@link ConfigError} listing every issue. */
42
+ load(env?: Environment): Promise<T>;
43
+ toString(): string;
44
+ }
45
+ /**
46
+ * Defines a configuration validated by `schema`. Its input is the environment,
47
+ * or what `source` builds from it, for a nested configuration:
48
+ *
49
+ * ```ts
50
+ * const DatabaseConfig = defineConfig('database', DatabaseSchema, (env) => ({
51
+ * url: env.DATABASE_URL,
52
+ * pool: { max: env.DATABASE_POOL_MAX },
53
+ * }))
54
+ * ```
55
+ */
56
+ export declare const defineConfig: <S extends StandardSchemaV1>(name: string, schema: S, source?: (env: Environment) => unknown) => Config<InferOutput<S>>;
57
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAGtE,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;AAEtE,oFAAoF;AACpF,qBAAa,WAAY,SAAQ,KAAK;IAIlC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE;IAJpC,SAAkB,IAAI,iBAAgB;IAEtC,YACW,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,MAAM,EAAE,EAInC;CACF;AAED;;;GAGG;AACH,qBAAa,MAAM,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;;IAI9C,YAAY,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,EAIpG;IAED,iGAAiG;IAC3F,IAAI,CAAC,GAAG,GAAE,WAAyB,GAAG,OAAO,CAAC,CAAC,CAAC,CAQrD;IAEQ,QAAQ,IAAI,MAAM,CAE1B;CACF;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,gBAAgB,QAC/C,MAAM,UACJ,CAAC,WACD,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,KACpC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAkF,CAAA"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @module
3
+ * Configuration typed by a schema and validated at startup.
4
+ *
5
+ * What `@nestjs/config` does with `registerAs()` and a `validationSchema`,
6
+ * typed by the schema instead of read with string keys. Bun already loads
7
+ * `.env`, `.env.local` and `.env.<NODE_ENV>` into `process.env`.
8
+ *
9
+ * ```ts
10
+ * export const AppConfig = defineConfig('app', z.object({
11
+ * PORT: z.coerce.number().default(3000),
12
+ * JWT_SECRET: z.string().min(32),
13
+ * }))
14
+ *
15
+ * @Module({ imports: [ConfigModule.forRoot({ load: [AppConfig], global: true })] })
16
+ * class AppModule {}
17
+ *
18
+ * class AuthService {
19
+ * readonly #config = inject(AppConfig) // { PORT: number; JWT_SECRET: string }
20
+ * }
21
+ * ```
22
+ */
23
+ import { InjectionToken } from '../di/token.js';
24
+ import { formatIssues } from '../http/schema.js';
25
+ import { hideFrameworkFrames } from '../utils/errors.js';
26
+ /** A configuration that does not match its schema; `issues` lists every problem. */
27
+ export class ConfigError extends Error {
28
+ config;
29
+ issues;
30
+ name = 'ConfigError';
31
+ constructor(config, issues) {
32
+ super(`Invalid configuration "${config}":\n ${issues.join('\n ')}`);
33
+ this.config = config;
34
+ this.issues = issues;
35
+ hideFrameworkFrames(this);
36
+ }
37
+ }
38
+ /**
39
+ * A configuration, and the DI token of its value: `inject(AppConfig)`.
40
+ * `ConfigModule.forRoot()` loads it at startup; `load()` works without DI.
41
+ */
42
+ export class Config extends InjectionToken {
43
+ #schema;
44
+ #source;
45
+ constructor(name, schema, source) {
46
+ super(name);
47
+ this.#schema = schema;
48
+ this.#source = source;
49
+ }
50
+ /** The value read from `env` and validated; throws a {@link ConfigError} listing every issue. */
51
+ async load(env = process.env) {
52
+ const result = await this.#schema['~standard'].validate(this.#source(env));
53
+ if (result.issues !== undefined) {
54
+ throw new ConfigError(this.description, formatIssues(result.issues, ''));
55
+ }
56
+ return result.value;
57
+ }
58
+ toString() {
59
+ return `Config(${this.description})`;
60
+ }
61
+ }
62
+ /**
63
+ * Defines a configuration validated by `schema`. Its input is the environment,
64
+ * or what `source` builds from it, for a nested configuration:
65
+ *
66
+ * ```ts
67
+ * const DatabaseConfig = defineConfig('database', DatabaseSchema, (env) => ({
68
+ * url: env.DATABASE_URL,
69
+ * pool: { max: env.DATABASE_POOL_MAX },
70
+ * }))
71
+ * ```
72
+ */
73
+ export const defineConfig = (name, schema, source = (env) => env) => new Config(name, schema, source);
74
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAKxD,oFAAoF;AACpF,MAAM,OAAO,WAAY,SAAQ,KAAK;IAIzB,MAAM;IACN,MAAM;IAJC,IAAI,GAAG,aAAa,CAAA;IAEtC,YACW,MAAc,EACd,MAAyB;QAElC,KAAK,CAAC,0BAA0B,MAAM,SAAS,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;sBAH5D,MAAM;sBACN,MAAM;QAGf,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,MAAU,SAAQ,cAAiB;IACrC,OAAO,CAA8B;IACrC,OAAO,CAA+B;IAE/C,YAAY,IAAY,EAAE,MAAoC,EAAE,MAAqC;QACnG,KAAK,CAAC,IAAI,CAAC,CAAA;QACX,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAED,iGAAiG;IACjG,KAAK,CAAC,IAAI,CAAC,GAAG,GAAgB,OAAO,CAAC,GAAG;QACvC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;QAE1E,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAA;QAC1E,CAAC;QAED,OAAO,MAAM,CAAC,KAAK,CAAA;IACrB,CAAC;IAEQ,QAAQ;QACf,OAAO,UAAU,IAAI,CAAC,WAAW,GAAG,CAAA;IACtC,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,IAAY,EACZ,MAAS,EACT,MAAM,GAAkC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAC5B,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,MAAmD,EAAE,MAAM,CAAC,CAAA"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @module
3
+ * Configuration typed by a schema and validated at startup.
4
+ */
5
+ export { Config, ConfigError, defineConfig } from './config.ts';
6
+ export type { Environment } from './config.ts';
7
+ export { ConfigModule } from './module.ts';
8
+ export type { ConfigModuleOptions } from './module.ts';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/D,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @module
3
+ * Configuration typed by a schema and validated at startup.
4
+ */
5
+ export { Config, ConfigError, defineConfig } from './config.js';
6
+ export { ConfigModule } from './module.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @module
3
+ * `ConfigModule`: loads configurations at startup, like `ConfigModule.forRoot()` of `@nestjs/config`.
4
+ */
5
+ import type { DynamicModule } from '../di/index.ts';
6
+ import type { Config, Environment } from './config.ts';
7
+ export interface ConfigModuleOptions {
8
+ /** Configurations to load and provide. */
9
+ readonly load: readonly Config<unknown>[];
10
+ /** Makes them injectable in every module. Defaults to `false`, as in Nest. */
11
+ readonly global?: boolean;
12
+ /** Where variables come from, read when the container starts. Defaults to `process.env`. */
13
+ readonly env?: Environment;
14
+ }
15
+ /**
16
+ * ```ts
17
+ * @Module({ imports: [ConfigModule.forRoot({ load: [AppConfig, DatabaseConfig], global: true })] })
18
+ * class AppModule {}
19
+ * ```
20
+ *
21
+ * Each configuration is loaded when the container starts; an invalid one
22
+ * fails the startup with a `ConfigError` listing all its issues. Tests
23
+ * replace a value with `overrides: [provide(AppConfig, { useValue })]`, and
24
+ * the replaced configuration is not loaded.
25
+ */
26
+ export declare class ConfigModule {
27
+ static forRoot(options: ConfigModuleOptions): DynamicModule;
28
+ }
29
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/config/module.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEtD,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,CAAC,OAAO,CAAC,EAAE,CAAA;IACzC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,4FAA4F;IAC5F,QAAQ,CAAC,GAAG,CAAC,EAAE,WAAW,CAAA;CAC3B;AAED;;;;;;;;;;GAUG;AACH,qBACa,YAAY;IACvB,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa,CAO1D;CACF"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @module
3
+ * `ConfigModule`: loads configurations at startup, like `ConfigModule.forRoot()` of `@nestjs/config`.
4
+ */
5
+ import { Module, provide } from '../di/index.js';
6
+ /**
7
+ * ```ts
8
+ * @Module({ imports: [ConfigModule.forRoot({ load: [AppConfig, DatabaseConfig], global: true })] })
9
+ * class AppModule {}
10
+ * ```
11
+ *
12
+ * Each configuration is loaded when the container starts; an invalid one
13
+ * fails the startup with a `ConfigError` listing all its issues. Tests
14
+ * replace a value with `overrides: [provide(AppConfig, { useValue })]`, and
15
+ * the replaced configuration is not loaded.
16
+ */
17
+ @Module({})
18
+ export class ConfigModule {
19
+ static forRoot(options) {
20
+ return {
21
+ module: ConfigModule,
22
+ global: options.global ?? false,
23
+ providers: options.load.map((config) => provide(config, { useFactory: () => config.load(options.env) })),
24
+ exports: options.load,
25
+ };
26
+ }
27
+ }
28
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/config/module.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAahD;;;;;;;;;;GAUG;AACH,CAAC,MAAM,CAAC,EAAE,CAAC;AACX,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,OAAO,CAAC,OAA4B;QACzC,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;YAC/B,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACxG,OAAO,EAAE,OAAO,CAAC,IAAI;SACtB,CAAA;IACH,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/di/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GACnB,aAAa,GACb,oBAAoB,GACpB,qBAAqB,GACrB,kBAAkB,GAClB,2BAA2B,GAC3B,kBAAkB,GAClB,oBAAoB,GACpB,gBAAgB,GAChB,gBAAgB,GAChB,kBAAkB,CAAA;AAEtB;;;;GAIG;AACH,qBAAa,OAAQ,SAAQ,KAAK;IAI9B,QAAQ,CAAC,IAAI,EAAE,WAAW;IAH5B,SAAkB,IAAI,aAAY;IAElC,YACW,IAAI,EAAE,WAAW,EAC1B,OAAO,EAAE,MAAM,EAGhB;CACF"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/di/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GACnB,aAAa,GACb,oBAAoB,GACpB,qBAAqB,GACrB,kBAAkB,GAClB,2BAA2B,GAC3B,kBAAkB,GAClB,oBAAoB,GACpB,gBAAgB,GAChB,gBAAgB,GAChB,kBAAkB,CAAA;AAEtB;;;;GAIG;AACH,qBAAa,OAAQ,SAAQ,KAAK;IAI9B,QAAQ,CAAC,IAAI,EAAE,WAAW;IAH5B,SAAkB,IAAI,aAAY;IAElC,YACW,IAAI,EAAE,WAAW,EAC1B,OAAO,EAAE,MAAM,EAIhB;CACF"}
package/dist/di/errors.js CHANGED
@@ -2,6 +2,7 @@
2
2
  * @module
3
3
  * Errors raised by the dependency injection container.
4
4
  */
5
+ import { hideFrameworkFrames } from '../utils/errors.js';
5
6
  /**
6
7
  * Error thrown by the container.
7
8
  *
@@ -13,6 +14,7 @@ export class DiError extends Error {
13
14
  constructor(code, message) {
14
15
  super(message);
15
16
  this.code = code;
17
+ hideFrameworkFrames(this);
16
18
  }
17
19
  }
18
20
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/di/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA4BH;;;;GAIG;AACH,MAAM,OAAO,OAAQ,SAAQ,KAAK;IAIrB,IAAI;IAHG,IAAI,GAAG,SAAS,CAAA;IAElC,YACW,IAAiB,EAC1B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAA;oBAHL,IAAI;IAIf,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/di/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AA4BxD;;;;GAIG;AACH,MAAM,OAAO,OAAQ,SAAQ,KAAK;IAIrB,IAAI;IAHG,IAAI,GAAG,SAAS,CAAA;IAElC,YACW,IAAiB,EAC1B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAA;oBAHL,IAAI;QAIb,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;CACF"}