@rudderjs/core 0.0.8
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 +245 -0
- package/boost/guidelines.md +144 -0
- package/dist/application.d.ts +147 -0
- package/dist/application.d.ts.map +1 -0
- package/dist/application.js +418 -0
- package/dist/application.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -0
- package/dist/di.d.ts +62 -0
- package/dist/di.d.ts.map +1 -0
- package/dist/di.js +228 -0
- package/dist/di.js.map +1 -0
- package/dist/events-fake.d.ts +40 -0
- package/dist/events-fake.d.ts.map +1 -0
- package/dist/events-fake.js +78 -0
- package/dist/events-fake.js.map +1 -0
- package/dist/events.d.ts +40 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +72 -0
- package/dist/events.js.map +1 -0
- package/dist/exceptions.d.ts +28 -0
- package/dist/exceptions.d.ts.map +1 -0
- package/dist/exceptions.js +147 -0
- package/dist/exceptions.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/service-provider.d.ts +49 -0
- package/dist/service-provider.d.ts.map +1 -0
- package/dist/service-provider.js +42 -0
- package/dist/service-provider.js.map +1 -0
- package/dist/validation.d.ts +20 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +79 -0
- package/dist/validation.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Suleiman Shahbari
|
|
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,245 @@
|
|
|
1
|
+
# @rudderjs/core
|
|
2
|
+
|
|
3
|
+
Application bootstrap, service provider lifecycle, and framework-level runtime orchestration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @rudderjs/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Application } from '@rudderjs/core'
|
|
15
|
+
import { hono } from '@rudderjs/server-hono'
|
|
16
|
+
import { RateLimit } from '@rudderjs/middleware'
|
|
17
|
+
|
|
18
|
+
export default Application.configure({
|
|
19
|
+
server: hono(configs.server),
|
|
20
|
+
config: configs,
|
|
21
|
+
providers,
|
|
22
|
+
})
|
|
23
|
+
.withRouting({
|
|
24
|
+
web: () => import('../routes/web.js'),
|
|
25
|
+
api: () => import('../routes/api.js'),
|
|
26
|
+
commands: () => import('../routes/console.js'),
|
|
27
|
+
})
|
|
28
|
+
.withMiddleware((m) => {
|
|
29
|
+
m.use(RateLimit.perMinute(60))
|
|
30
|
+
})
|
|
31
|
+
.withExceptions((e) => {
|
|
32
|
+
// Custom error type → custom response
|
|
33
|
+
e.render(PaymentError, (err) =>
|
|
34
|
+
new Response(JSON.stringify({ code: err.code }), {
|
|
35
|
+
status: 402,
|
|
36
|
+
headers: { 'Content-Type': 'application/json' },
|
|
37
|
+
})
|
|
38
|
+
)
|
|
39
|
+
// Override the reporter (default: @rudderjs/log when installed, otherwise console.error)
|
|
40
|
+
e.reportUsing((err) => Sentry.captureException(err))
|
|
41
|
+
// Re-throw to the server's native fallback
|
|
42
|
+
e.ignore(DebugOnlyError)
|
|
43
|
+
})
|
|
44
|
+
.create()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API Reference
|
|
48
|
+
|
|
49
|
+
- `ServiceProvider` — `register()`, `boot()`, `publishes()`
|
|
50
|
+
- `PublishGroup` — `{ from, to, tag? }`
|
|
51
|
+
- `getPublishGroups()` — returns the global publish registry (used by `vendor:publish`)
|
|
52
|
+
- `Listener`, `EventDispatcher`, `dispatcher`, `dispatch()`, `events()`
|
|
53
|
+
- `Application`, `AppConfig`
|
|
54
|
+
- `ConfigureOptions`, `RoutingOptions`
|
|
55
|
+
- `MiddlewareConfigurator`, `ExceptionConfigurator`
|
|
56
|
+
- `AppBuilder`, `RudderJS`
|
|
57
|
+
- `app()`, `resolve()`
|
|
58
|
+
- `defineConfig()`
|
|
59
|
+
- `HttpException` — HTTP error with `statusCode`, `message`, `headers`
|
|
60
|
+
- `abort(status, message?, headers?)` — throws `HttpException`
|
|
61
|
+
- `abort_if(condition, status, message?)` — conditional abort
|
|
62
|
+
- `abort_unless(condition, status, message?)` — inverse conditional abort
|
|
63
|
+
- `report(err)` — report an error to the configured reporter
|
|
64
|
+
- `report_if(condition, err)` — conditional report
|
|
65
|
+
- `setExceptionReporter(fn)` — override the global reporter (wired automatically by `@rudderjs/log`)
|
|
66
|
+
- Re-exports from `@rudderjs/rudder`, `@rudderjs/support`, and `@rudderjs/contracts` types plus built-in DI and Events primitives
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
- `AppConfig`
|
|
71
|
+
- `name?`, `env?`, `debug?`
|
|
72
|
+
- `providers?`
|
|
73
|
+
- `config?` (config object bound into the container)
|
|
74
|
+
- `ConfigureOptions`
|
|
75
|
+
- `server`, `config?`, `providers?`
|
|
76
|
+
|
|
77
|
+
## Dynamic Provider Registration
|
|
78
|
+
|
|
79
|
+
Providers can register other providers at runtime — useful for modules, conditional features, and package composition:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { ServiceProvider } from '@rudderjs/core'
|
|
83
|
+
import { cache } from '@rudderjs/cache'
|
|
84
|
+
import { panels } from '@rudderjs/panels'
|
|
85
|
+
import { adminPanel } from '../Panels/Admin/AdminPanel.js'
|
|
86
|
+
|
|
87
|
+
export class AppServiceProvider extends ServiceProvider {
|
|
88
|
+
register() {
|
|
89
|
+
// Static sub-provider
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async boot() {
|
|
93
|
+
// Register panels from your own provider
|
|
94
|
+
await this.app.register(panels([adminPanel]))
|
|
95
|
+
|
|
96
|
+
// Conditional features
|
|
97
|
+
const config = this.app.make<{ get(k: string): unknown }>('config')
|
|
98
|
+
if (config.get('cache.enabled')) {
|
|
99
|
+
await this.app.register(cache(cacheConfig))
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`register()` calls the provider's `register()` immediately so bindings are available. If the app is already booted, `boot()` runs too. Duplicate providers (by class reference or class name) are silently skipped.
|
|
106
|
+
|
|
107
|
+
## Publishing Assets
|
|
108
|
+
|
|
109
|
+
Service providers can declare publishable assets (pages, config files, migrations) that users copy into their app with `pnpm rudder vendor:publish`.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { ServiceProvider } from '@rudderjs/core'
|
|
113
|
+
|
|
114
|
+
export class MyPackageServiceProvider extends ServiceProvider {
|
|
115
|
+
register(): void {}
|
|
116
|
+
|
|
117
|
+
async boot(): Promise<void> {
|
|
118
|
+
this.publishes({
|
|
119
|
+
from: new URL('../pages', import.meta.url).pathname,
|
|
120
|
+
to: 'pages/(panels)',
|
|
121
|
+
tag: 'my-package-pages',
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Multiple groups with different tags:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
this.publishes([
|
|
131
|
+
{ from: new URL('../pages', import.meta.url).pathname, to: 'pages/(panels)', tag: 'my-pages' },
|
|
132
|
+
{ from: new URL('../config', import.meta.url).pathname, to: 'config', tag: 'my-config' },
|
|
133
|
+
])
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Users publish with:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pnpm rudder vendor:publish --tag=my-package-pages
|
|
140
|
+
pnpm rudder vendor:publish --provider=MyPackageServiceProvider
|
|
141
|
+
pnpm rudder vendor:publish --list # see all available assets
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Events
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
import { dispatch, dispatcher, events } from '@rudderjs/core'
|
|
148
|
+
|
|
149
|
+
// Define an event
|
|
150
|
+
class UserCreated {
|
|
151
|
+
constructor(public readonly id: number) {}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Define a listener
|
|
155
|
+
class SendWelcomeEmail {
|
|
156
|
+
async handle(event: UserCreated) {
|
|
157
|
+
await mailer.send(event.id)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Register via provider in bootstrap/providers.ts
|
|
162
|
+
import { events } from '@rudderjs/core'
|
|
163
|
+
export default [
|
|
164
|
+
events({ UserCreated: [SendWelcomeEmail] }),
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
// Dispatch anywhere
|
|
168
|
+
await dispatch(new UserCreated(42))
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### `EventDispatcher` API
|
|
172
|
+
|
|
173
|
+
| Method | Description |
|
|
174
|
+
|--------|-------------|
|
|
175
|
+
| `register(name, ...listeners)` | Register listeners for an event name. Use `'*'` for wildcard (all events). |
|
|
176
|
+
| `dispatch(event)` | Dispatch to matching listeners, then wildcard listeners. Awaited in order. |
|
|
177
|
+
| `count(name)` | Number of listeners for an event name. |
|
|
178
|
+
| `hasListeners(name)` | `true` if at least one listener is registered. |
|
|
179
|
+
| `list()` | `Record<string, number>` snapshot of all registered events and counts. |
|
|
180
|
+
| `reset()` | Clear all listeners (testing / hot-reload). |
|
|
181
|
+
|
|
182
|
+
## Exception Handling
|
|
183
|
+
|
|
184
|
+
### `abort()` helpers
|
|
185
|
+
|
|
186
|
+
Throw an `HttpException` from anywhere — routes, services, middleware:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { abort, abort_if, abort_unless } from '@rudderjs/core'
|
|
190
|
+
|
|
191
|
+
abort(404) // throws HttpException(404, 'Not Found')
|
|
192
|
+
abort(403, 'Insufficient permissions')
|
|
193
|
+
abort(402, 'Payment required', { 'X-Upgrade-URL': '/billing' })
|
|
194
|
+
|
|
195
|
+
abort_if(!user, 401) // abort if condition is true
|
|
196
|
+
abort_unless(user.isAdmin, 403) // abort if condition is false
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`HttpException` is caught automatically and rendered as JSON or HTML based on the request's `Accept` header — no `try/catch` needed.
|
|
200
|
+
|
|
201
|
+
### `report()` helpers
|
|
202
|
+
|
|
203
|
+
Manually report an error without aborting the request:
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
import { report, report_if } from '@rudderjs/core'
|
|
207
|
+
|
|
208
|
+
report(new Error('Stripe webhook failed'))
|
|
209
|
+
report_if(payment.failed, payment.error)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
When `@rudderjs/log` is installed, `report()` routes through the log channel automatically. Otherwise it falls back to `console.error`.
|
|
213
|
+
|
|
214
|
+
### `withExceptions` configurator
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
.withExceptions((e) => {
|
|
218
|
+
// Custom error type → custom Response
|
|
219
|
+
e.render(PaymentError, (err, req) =>
|
|
220
|
+
Response.json({ code: err.code }, { status: 402 })
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
// Override the reporter (default: @rudderjs/log or console.error)
|
|
224
|
+
e.reportUsing((err) => Sentry.captureException(err))
|
|
225
|
+
|
|
226
|
+
// Re-throw to the server's native fallback handler
|
|
227
|
+
e.ignore(DebugOnlyError)
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Built-in handling (no configuration needed)
|
|
232
|
+
|
|
233
|
+
| Error type | Response |
|
|
234
|
+
|---|---|
|
|
235
|
+
| `ValidationError` | `422` JSON `{ message, errors }` |
|
|
236
|
+
| `HttpException` | Status from `statusCode`, JSON or HTML based on `Accept` |
|
|
237
|
+
| Unhandled error | Reported via reporter, then `500` (with stack in debug mode) |
|
|
238
|
+
|
|
239
|
+
## Notes
|
|
240
|
+
|
|
241
|
+
- `Application.create()` is singleton-based and can recreate in development/local mode when config is passed.
|
|
242
|
+
- `RudderJS.boot()` boots providers; `RudderJS.handleRequest()` lazily creates the HTTP handler.
|
|
243
|
+
- `ValidationError` is always caught and returned as 422 JSON — no try/catch needed in routes.
|
|
244
|
+
- `HttpException` is always caught and rendered with its status code — no try/catch needed in routes.
|
|
245
|
+
- Unhandled errors are auto-reported and render as 500. In `debug` mode the response includes the exception message and stack trace.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# @rudderjs/core
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@rudderjs/core` is the foundation of a RudderJS application. It provides the Application class, a Laravel-style DI container, service provider lifecycle, event dispatching, form request validation (via Zod), exception handling, and typed configuration. It re-exports essentials from `@rudderjs/support`, `@rudderjs/contracts`, and `@rudderjs/rudder` so most apps only need to import from `@rudderjs/core`.
|
|
6
|
+
|
|
7
|
+
## Key Patterns
|
|
8
|
+
|
|
9
|
+
### Application Bootstrap
|
|
10
|
+
|
|
11
|
+
Every RudderJS app is wired in `bootstrap/app.ts` using the builder pattern:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import 'reflect-metadata'
|
|
15
|
+
import 'dotenv/config'
|
|
16
|
+
import { Application } from '@rudderjs/core'
|
|
17
|
+
import { hono } from '@rudderjs/server-hono'
|
|
18
|
+
import configs from '../config/index.ts'
|
|
19
|
+
import providers from './providers.ts'
|
|
20
|
+
|
|
21
|
+
export default Application.configure({
|
|
22
|
+
server: hono(configs.server), config: configs, providers,
|
|
23
|
+
})
|
|
24
|
+
.withRouting({
|
|
25
|
+
web: () => import('../routes/web.ts'),
|
|
26
|
+
api: () => import('../routes/api.ts'),
|
|
27
|
+
commands: () => import('../routes/console.ts'),
|
|
28
|
+
})
|
|
29
|
+
.withMiddleware((m) => m.use(RateLimit.perMinute(60).toHandler()))
|
|
30
|
+
.withExceptions((e) => e.reportUsing((err) => Sentry.captureException(err)))
|
|
31
|
+
.create()
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
There is no `rudderjs.config.ts` -- `bootstrap/app.ts` is the framework wiring file.
|
|
35
|
+
|
|
36
|
+
### Service Providers
|
|
37
|
+
|
|
38
|
+
Providers follow a two-phase lifecycle: `register()` binds into the container, `boot()` runs after all providers are registered.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { ServiceProvider, app } from '@rudderjs/core'
|
|
42
|
+
|
|
43
|
+
export class AppServiceProvider extends ServiceProvider {
|
|
44
|
+
register(): void {
|
|
45
|
+
this.app.singleton('userService', () => new UserService())
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async boot(): Promise<void> {
|
|
49
|
+
// All bindings are available here
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Many packages export a **factory function** that returns a provider class (e.g., `cache(config)`, `queue(config)`). These are used in `bootstrap/providers.ts`:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { cache } from '@rudderjs/cache'
|
|
58
|
+
export default [cache(cacheConfig), AppServiceProvider]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Providers can be registered dynamically at runtime via `app().register(ProviderClass)`. Duplicates are silently skipped (guarded by class reference and class name).
|
|
62
|
+
|
|
63
|
+
Deferred providers define `provides()` returning token strings -- they are lazily booted on first container resolve of those tokens.
|
|
64
|
+
|
|
65
|
+
### Dependency Injection
|
|
66
|
+
|
|
67
|
+
The DI container supports several binding types:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// Transient -- new instance each time
|
|
71
|
+
app().bind('mailer', (c) => new Mailer(c.make('config')))
|
|
72
|
+
|
|
73
|
+
// Singleton -- created once, cached forever
|
|
74
|
+
app().singleton('db', (c) => new Database(c.make('config')))
|
|
75
|
+
|
|
76
|
+
// Scoped -- one instance per request (requires ScopeMiddleware)
|
|
77
|
+
app().scoped('cart', () => new ShoppingCart())
|
|
78
|
+
|
|
79
|
+
// Instance -- store an already-created value
|
|
80
|
+
app().instance('config', configRepo)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Resolve with `app().make<T>(token)` or the global `resolve<T>(token)` helper.
|
|
84
|
+
|
|
85
|
+
Auto-resolution works for classes decorated with `@Injectable()`. Use `@Inject('token')` to override specific constructor parameters:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
@Injectable()
|
|
89
|
+
class PhotoController {
|
|
90
|
+
constructor(
|
|
91
|
+
private storage: StorageService, // auto-resolved by type
|
|
92
|
+
@Inject('s3') private backup: Storage, // resolved by token
|
|
93
|
+
) {}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Contextual bindings let you override a dependency for a specific consumer:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
container.when(PhotoController).needs('storage').give(() => new S3Storage())
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Middleware
|
|
104
|
+
|
|
105
|
+
Middleware is configured in `bootstrap/app.ts` via `withMiddleware()`. Each handler receives a `MiddlewareHandler` signature from `@rudderjs/contracts`:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
.withMiddleware((m) => {
|
|
109
|
+
m.use(RateLimit.perMinute(60).toHandler())
|
|
110
|
+
m.use(cors({ origins: ['https://example.com'] }))
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Exception Handling
|
|
115
|
+
|
|
116
|
+
Use `abort(status, message?)`, `abort_if(condition, status)`, and `abort_unless(condition, status)` to throw `HttpException`. Configure custom renderers via `withExceptions()` in `bootstrap/app.ts`. Use `report(err)` to log without throwing.
|
|
117
|
+
|
|
118
|
+
### Events
|
|
119
|
+
|
|
120
|
+
Extend `Listener` and call `dispatch(new MyEvent(data))`. Register listeners in a provider's `boot()`.
|
|
121
|
+
|
|
122
|
+
### Validation
|
|
123
|
+
|
|
124
|
+
Extend `FormRequest` and define a `rules()` method returning a Zod schema (`z.object({...})`). `z` is re-exported from `@rudderjs/core`.
|
|
125
|
+
|
|
126
|
+
## Common Pitfalls
|
|
127
|
+
|
|
128
|
+
- **Missing `reflect-metadata`**: Must be imported at the very top of `bootstrap/app.ts` before any other imports. Install as a `dependency`, not `devDependency`.
|
|
129
|
+
- **Provider boot order matters**: `DatabaseServiceProvider` must come before any provider that uses ORM models. Order your `providers` array accordingly.
|
|
130
|
+
- **Scoped bindings outside request scope**: Calling `app().make('scopedToken')` outside of `container.runScoped()` throws. Ensure `ScopeMiddleware` is registered or wrap the call manually.
|
|
131
|
+
- **Dynamic provider duplicates**: `app().register()` is safe to call multiple times with the same class -- duplicates are skipped. But factory functions create anonymous classes, so use consistent references.
|
|
132
|
+
- **Circular dependency with `@rudderjs/router`**: Core loads router at runtime via dynamic `import()`. Never add `@rudderjs/core` to router's `dependencies` -- use `peerDependencies` only.
|
|
133
|
+
|
|
134
|
+
## Key Imports
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { Application, app, resolve, ServiceProvider, Injectable, Inject } from '@rudderjs/core'
|
|
138
|
+
import { FormRequest, ValidationError, z } from '@rudderjs/core'
|
|
139
|
+
import { Listener, dispatch, events } from '@rudderjs/core'
|
|
140
|
+
import { HttpException, abort, abort_if, report } from '@rudderjs/core'
|
|
141
|
+
import { Collection, Env, env, config, sleep } from '@rudderjs/core'
|
|
142
|
+
import { rudder, Command } from '@rudderjs/core'
|
|
143
|
+
import type { AppRequest, AppResponse, MiddlewareHandler } from '@rudderjs/core'
|
|
144
|
+
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Container, ContextualBindingBuilder } from './di.js';
|
|
2
|
+
import { ServiceProvider } from './service-provider.js';
|
|
3
|
+
import type { ServerAdapterProvider, MiddlewareHandler, AppRequest } from '@rudderjs/contracts';
|
|
4
|
+
export interface BootConfig {
|
|
5
|
+
name?: string;
|
|
6
|
+
env?: string;
|
|
7
|
+
debug?: boolean;
|
|
8
|
+
providers?: (new (app: Application) => ServiceProvider)[];
|
|
9
|
+
/** Config values loaded from config/ files — bound to the container as 'config' */
|
|
10
|
+
config?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export type ProviderClass = new (app: Application) => ServiceProvider;
|
|
13
|
+
export declare class Application {
|
|
14
|
+
private static instance;
|
|
15
|
+
readonly container: Container;
|
|
16
|
+
private providers;
|
|
17
|
+
private booted;
|
|
18
|
+
private _booting;
|
|
19
|
+
private _bootedProviders;
|
|
20
|
+
/** Tracks registered provider classes to prevent duplicates. */
|
|
21
|
+
private _registeredClasses;
|
|
22
|
+
/** Tracks registered provider names to prevent duplicates from factory functions. */
|
|
23
|
+
private _registeredNames;
|
|
24
|
+
/** Deferred providers — token → ProviderClass (lazily booted on first resolve). */
|
|
25
|
+
private _deferredProviders;
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly env: string;
|
|
28
|
+
readonly debug: boolean;
|
|
29
|
+
private constructor();
|
|
30
|
+
/** Track a provider class for duplicate detection. */
|
|
31
|
+
private _trackProvider;
|
|
32
|
+
/** Check whether a provider class (or its name) has already been registered. */
|
|
33
|
+
private _isDuplicate;
|
|
34
|
+
static create(config?: BootConfig): Application;
|
|
35
|
+
static getInstance(): Application;
|
|
36
|
+
bind(token: Parameters<Container['bind']>[0], factory: Parameters<Container['bind']>[1]): this;
|
|
37
|
+
singleton(token: Parameters<Container['singleton']>[0], factory: Parameters<Container['singleton']>[1]): this;
|
|
38
|
+
instance<T>(token: Parameters<Container['instance']>[0], value: T): this;
|
|
39
|
+
make<T>(token: Parameters<Container['make']>[0]): T;
|
|
40
|
+
scoped(token: Parameters<Container['scoped']>[0], factory: Parameters<Container['scoped']>[1]): this;
|
|
41
|
+
runScoped<T>(fn: () => T): T;
|
|
42
|
+
when(concrete: Parameters<Container['when']>[0]): ContextualBindingBuilder;
|
|
43
|
+
/**
|
|
44
|
+
* Dynamically register a service provider at runtime.
|
|
45
|
+
*
|
|
46
|
+
* - Calls `register()` immediately so bindings are available.
|
|
47
|
+
* - If the application is already booted, calls `boot()` too.
|
|
48
|
+
* - Duplicate providers (by class reference or class name) are silently skipped.
|
|
49
|
+
*
|
|
50
|
+
* Works with both provider classes and factory return values:
|
|
51
|
+
* ```ts
|
|
52
|
+
* await this.app.register(MyServiceProvider)
|
|
53
|
+
* await this.app.register(cache(cacheConfig))
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
register(Provider: ProviderClass | ProviderClass[]): Promise<this>;
|
|
57
|
+
private _registerAll;
|
|
58
|
+
private _bootAll;
|
|
59
|
+
bootstrap(): Promise<this>;
|
|
60
|
+
isBooted(): boolean;
|
|
61
|
+
isProduction(): boolean;
|
|
62
|
+
isDevelopment(): boolean;
|
|
63
|
+
static configure(options: ConfigureOptions): AppBuilder;
|
|
64
|
+
/** @internal — testing only */
|
|
65
|
+
static resetForTesting(): void;
|
|
66
|
+
}
|
|
67
|
+
export interface ConfigureOptions {
|
|
68
|
+
server: ServerAdapterProvider;
|
|
69
|
+
config?: Record<string, unknown>;
|
|
70
|
+
providers?: (new (app: Application) => ServiceProvider)[];
|
|
71
|
+
}
|
|
72
|
+
export interface RoutingOptions {
|
|
73
|
+
web?: () => Promise<unknown>;
|
|
74
|
+
api?: () => Promise<unknown>;
|
|
75
|
+
commands?: () => Promise<unknown>;
|
|
76
|
+
channels?: () => Promise<unknown>;
|
|
77
|
+
}
|
|
78
|
+
export declare class MiddlewareConfigurator {
|
|
79
|
+
private _handlers;
|
|
80
|
+
use(handler: MiddlewareHandler): this;
|
|
81
|
+
getHandlers(): MiddlewareHandler[];
|
|
82
|
+
}
|
|
83
|
+
export type ErrorRenderer = (err: unknown, req: AppRequest) => Response | Promise<Response>;
|
|
84
|
+
export declare class ExceptionConfigurator {
|
|
85
|
+
private _renders;
|
|
86
|
+
private _ignored;
|
|
87
|
+
/**
|
|
88
|
+
* Register a custom renderer for a specific error type.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* e.render(PaymentError, (err, req) =>
|
|
92
|
+
* new Response(JSON.stringify({ code: err.code }), { status: 402, headers: { 'Content-Type': 'application/json' } })
|
|
93
|
+
* )
|
|
94
|
+
*/
|
|
95
|
+
render<T extends Error>(type: new (...args: any[]) => T, fn: (err: T, req: AppRequest) => Response | Promise<Response>): this;
|
|
96
|
+
/**
|
|
97
|
+
* Ignore an error type — re-throws it so the server's native handler sees it.
|
|
98
|
+
*/
|
|
99
|
+
ignore(type: new (...args: any[]) => unknown): this;
|
|
100
|
+
/**
|
|
101
|
+
* Override the global exception reporter for unhandled errors.
|
|
102
|
+
* By default, `@rudderjs/log` wires this automatically when installed.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* e.reportUsing((err) => Sentry.captureException(err))
|
|
106
|
+
*/
|
|
107
|
+
reportUsing(fn: (err: unknown) => void): this;
|
|
108
|
+
/** @internal — called by RudderJS to produce the combined error handler */
|
|
109
|
+
buildHandler(): ErrorRenderer;
|
|
110
|
+
}
|
|
111
|
+
export declare class AppBuilder {
|
|
112
|
+
private readonly _options;
|
|
113
|
+
private _loaders;
|
|
114
|
+
private _mwFn?;
|
|
115
|
+
private _excFn?;
|
|
116
|
+
constructor(_options: ConfigureOptions);
|
|
117
|
+
withRouting(routes: RoutingOptions): this;
|
|
118
|
+
withMiddleware(fn: (m: MiddlewareConfigurator) => void): this;
|
|
119
|
+
withExceptions(fn: (e: ExceptionConfigurator) => void): this;
|
|
120
|
+
create(): RudderJS;
|
|
121
|
+
}
|
|
122
|
+
export declare class RudderJS {
|
|
123
|
+
private readonly _app;
|
|
124
|
+
private readonly _server;
|
|
125
|
+
private readonly _loaders;
|
|
126
|
+
private readonly _mwFn?;
|
|
127
|
+
private readonly _excFn?;
|
|
128
|
+
/** Phase 1: providers only — safe to await in CLI (no Vike virtual imports) */
|
|
129
|
+
private _providerBoot;
|
|
130
|
+
/** Phase 2: provider boot + HTTP handler — created lazily on first handleRequest call */
|
|
131
|
+
private _boot;
|
|
132
|
+
private _handler;
|
|
133
|
+
constructor(_app: Application, _server: ServerAdapterProvider, _loaders: Array<() => Promise<unknown>>, _mwFn?: ((m: MiddlewareConfigurator) => void) | undefined, _excFn?: ((e: ExceptionConfigurator) => void) | undefined);
|
|
134
|
+
private _suppressVikeNoise;
|
|
135
|
+
/** Phase 1 — boot providers + routes. Safe in CLI (no Vike virtual URLs). */
|
|
136
|
+
private _bootstrapProviders;
|
|
137
|
+
/** Phase 2 — create the HTTP fetch handler. Requires Vite context (virtual: URLs). */
|
|
138
|
+
private _createHandler;
|
|
139
|
+
/** Boot providers without starting an HTTP server — used by the CLI */
|
|
140
|
+
boot(): Promise<void>;
|
|
141
|
+
handleRequest(request: Request, env?: unknown, ctx?: unknown): Promise<Response>;
|
|
142
|
+
readonly fetch: (request: Request, env?: unknown, ctx?: unknown) => Promise<Response>;
|
|
143
|
+
}
|
|
144
|
+
export declare const app: () => Application;
|
|
145
|
+
export declare const resolve: <T>(token: Parameters<Container["make"]>[0]) => T;
|
|
146
|
+
export declare function defineConfig<T>(config: T): T;
|
|
147
|
+
//# sourceMappingURL=application.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../src/application.ts"],"names":[],"mappings":"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"}
|