@c9up/ream 0.1.25 → 0.1.27
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 +65 -0
- package/dist/ConfigLoader.d.ts +46 -5
- package/dist/ConfigLoader.d.ts.map +1 -1
- package/dist/ConfigLoader.js +60 -9
- package/dist/ConfigLoader.js.map +1 -1
- package/dist/HttpKernel.d.ts.map +1 -1
- package/dist/HttpKernel.js +46 -6
- package/dist/HttpKernel.js.map +1 -1
- package/dist/Ignitor.d.ts +115 -7
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +254 -40
- package/dist/Ignitor.js.map +1 -1
- package/dist/console/BaseCommand.d.ts +217 -0
- package/dist/console/BaseCommand.d.ts.map +1 -0
- package/dist/console/BaseCommand.js +340 -0
- package/dist/console/BaseCommand.js.map +1 -0
- package/dist/console/Console.d.ts +86 -0
- package/dist/console/Console.d.ts.map +1 -0
- package/dist/console/Console.js +134 -0
- package/dist/console/Console.js.map +1 -0
- package/dist/console/ExceptionHandler.d.ts +28 -0
- package/dist/console/ExceptionHandler.d.ts.map +1 -0
- package/dist/console/ExceptionHandler.js +76 -0
- package/dist/console/ExceptionHandler.js.map +1 -0
- package/dist/console/HelpCommand.d.ts +16 -0
- package/dist/console/HelpCommand.d.ts.map +1 -0
- package/dist/console/HelpCommand.js +40 -0
- package/dist/console/HelpCommand.js.map +1 -0
- package/dist/console/IndexGenerator.d.ts +24 -0
- package/dist/console/IndexGenerator.d.ts.map +1 -0
- package/dist/console/IndexGenerator.js +65 -0
- package/dist/console/IndexGenerator.js.map +1 -0
- package/dist/console/Kernel.d.ts +298 -0
- package/dist/console/Kernel.d.ts.map +1 -0
- package/dist/console/Kernel.js +1120 -0
- package/dist/console/Kernel.js.map +1 -0
- package/dist/console/ListCommand.d.ts +18 -0
- package/dist/console/ListCommand.d.ts.map +1 -0
- package/dist/console/ListCommand.js +60 -0
- package/dist/console/ListCommand.js.map +1 -0
- package/dist/console/assertions.d.ts +20 -0
- package/dist/console/assertions.d.ts.map +1 -0
- package/dist/console/assertions.js +84 -0
- package/dist/console/assertions.js.map +1 -0
- package/dist/console/cliui.d.ts +248 -0
- package/dist/console/cliui.d.ts.map +1 -0
- package/dist/console/cliui.js +587 -0
- package/dist/console/cliui.js.map +1 -0
- package/dist/console/decorators.d.ts +90 -0
- package/dist/console/decorators.d.ts.map +1 -0
- package/dist/console/decorators.js +142 -0
- package/dist/console/decorators.js.map +1 -0
- package/dist/console/index.d.ts +32 -0
- package/dist/console/index.d.ts.map +1 -0
- package/dist/console/index.js +24 -0
- package/dist/console/index.js.map +1 -0
- package/dist/console/loaders.d.ts +52 -0
- package/dist/console/loaders.d.ts.map +1 -0
- package/dist/console/loaders.js +131 -0
- package/dist/console/loaders.js.map +1 -0
- package/dist/console/parser.d.ts +86 -0
- package/dist/console/parser.d.ts.map +1 -0
- package/dist/console/parser.js +440 -0
- package/dist/console/parser.js.map +1 -0
- package/dist/console/prompts.d.ts +124 -0
- package/dist/console/prompts.d.ts.map +1 -0
- package/dist/console/prompts.js +356 -0
- package/dist/console/prompts.js.map +1 -0
- package/dist/console/tracing.d.ts +17 -0
- package/dist/console/tracing.d.ts.map +1 -0
- package/dist/console/tracing.js +11 -0
- package/dist/console/tracing.js.map +1 -0
- package/dist/console/types.d.ts +255 -0
- package/dist/console/types.d.ts.map +1 -0
- package/dist/console/types.js +25 -0
- package/dist/console/types.js.map +1 -0
- package/dist/console/ui.d.ts +20 -0
- package/dist/console/ui.d.ts.map +1 -0
- package/dist/console/ui.js +31 -0
- package/dist/console/ui.js.map +1 -0
- package/dist/console/utils.d.ts +27 -0
- package/dist/console/utils.d.ts.map +1 -0
- package/dist/console/utils.js +56 -0
- package/dist/console/utils.js.map +1 -0
- package/dist/container/Container.d.ts +23 -3
- package/dist/container/Container.d.ts.map +1 -1
- package/dist/container/Container.js +177 -70
- package/dist/container/Container.js.map +1 -1
- package/dist/container/types.d.ts +14 -2
- package/dist/container/types.d.ts.map +1 -1
- package/dist/decorators/Service.d.ts +7 -0
- package/dist/decorators/Service.d.ts.map +1 -1
- package/dist/decorators/Service.js +23 -3
- package/dist/decorators/Service.js.map +1 -1
- package/dist/env/Env.d.ts +29 -4
- package/dist/env/Env.d.ts.map +1 -1
- package/dist/env/Env.js +27 -4
- package/dist/env/Env.js.map +1 -1
- package/dist/env/Secret.d.ts +11 -0
- package/dist/env/Secret.d.ts.map +1 -0
- package/dist/env/Secret.js +36 -0
- package/dist/env/Secret.js.map +1 -0
- package/dist/env/interpolate.d.ts +26 -0
- package/dist/env/interpolate.d.ts.map +1 -0
- package/dist/env/interpolate.js +48 -0
- package/dist/env/interpolate.js.map +1 -0
- package/dist/env/loadEnvFiles.d.ts.map +1 -1
- package/dist/env/loadEnvFiles.js +14 -4
- package/dist/env/loadEnvFiles.js.map +1 -1
- package/dist/env/schema.d.ts +23 -6
- package/dist/env/schema.d.ts.map +1 -1
- package/dist/env/schema.js +67 -33
- package/dist/env/schema.js.map +1 -1
- package/dist/errors/ReamError.d.ts +25 -0
- package/dist/errors/ReamError.d.ts.map +1 -1
- package/dist/errors/ReamError.js +5 -0
- package/dist/errors/ReamError.js.map +1 -1
- package/dist/errors/prettyPrintError.d.ts +9 -0
- package/dist/errors/prettyPrintError.d.ts.map +1 -0
- package/dist/errors/prettyPrintError.js +22 -0
- package/dist/errors/prettyPrintError.js.map +1 -0
- package/dist/events/Emitter.d.ts +1 -1
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +1 -1
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/EventsProvider.d.ts +2 -2
- package/dist/events/EventsProvider.d.ts.map +1 -1
- package/dist/events/EventsProvider.js +3 -3
- package/dist/events/EventsProvider.js.map +1 -1
- package/dist/graphql/GraphQLEngine.d.ts +1 -1
- package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
- package/dist/graphql/GraphQLEngine.js +2 -2
- package/dist/graphql/GraphQLEngine.js.map +1 -1
- package/dist/graphql/GraphQLProvider.d.ts.map +1 -1
- package/dist/graphql/GraphQLProvider.js +7 -3
- package/dist/graphql/GraphQLProvider.js.map +1 -1
- package/dist/http/Exception.d.ts +63 -1
- package/dist/http/Exception.d.ts.map +1 -1
- package/dist/http/Exception.js +185 -48
- package/dist/http/Exception.js.map +1 -1
- package/dist/http/HttpContext.d.ts +53 -7
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/HttpContext.js +56 -15
- package/dist/http/HttpContext.js.map +1 -1
- package/dist/http/RedirectBuilder.d.ts.map +1 -1
- package/dist/http/RedirectBuilder.js +4 -1
- package/dist/http/RedirectBuilder.js.map +1 -1
- package/dist/http/Request.d.ts +141 -10
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +244 -34
- package/dist/http/Request.js.map +1 -1
- package/dist/http/Response.d.ts +176 -9
- package/dist/http/Response.d.ts.map +1 -1
- package/dist/http/Response.js +404 -16
- package/dist/http/Response.js.map +1 -1
- package/dist/index.d.ts +19 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/middleware/Pipeline.d.ts +29 -8
- package/dist/middleware/Pipeline.d.ts.map +1 -1
- package/dist/middleware/Pipeline.js +40 -2
- package/dist/middleware/Pipeline.js.map +1 -1
- package/dist/openapi/OpenApiProvider.js +4 -4
- package/dist/openapi/OpenApiProvider.js.map +1 -1
- package/dist/router/Router.d.ts +223 -31
- package/dist/router/Router.d.ts.map +1 -1
- package/dist/router/Router.js +520 -102
- package/dist/router/Router.js.map +1 -1
- package/dist/rpc/RpcProvider.d.ts +1 -0
- package/dist/rpc/RpcProvider.d.ts.map +1 -1
- package/dist/rpc/RpcProvider.js +7 -3
- package/dist/rpc/RpcProvider.js.map +1 -1
- package/dist/rpc/RpcRouter.d.ts +2 -2
- package/dist/rpc/RpcRouter.d.ts.map +1 -1
- package/dist/rpc/RpcRouter.js +17 -5
- package/dist/rpc/RpcRouter.js.map +1 -1
- package/dist/scheduler/ScheduleProvider.d.ts.map +1 -1
- package/dist/scheduler/ScheduleProvider.js +7 -15
- package/dist/scheduler/ScheduleProvider.js.map +1 -1
- package/dist/server/Server.d.ts +17 -4
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/Server.js +41 -7
- package/dist/server/Server.js.map +1 -1
- package/dist/services/app.d.ts +1 -1
- package/dist/services/app.js +1 -1
- package/dist/services/console.d.ts +21 -0
- package/dist/services/console.d.ts.map +1 -0
- package/dist/services/console.js +35 -0
- package/dist/services/console.js.map +1 -0
- package/dist/session/SessionMiddleware.js +3 -3
- package/dist/session/SessionMiddleware.js.map +1 -1
- package/dist/storage/StaticProvider.js +1 -1
- package/dist/storage/StaticProvider.js.map +1 -1
- package/dist/testing/ApiResponse.d.ts +218 -0
- package/dist/testing/ApiResponse.d.ts.map +1 -0
- package/dist/testing/ApiResponse.js +576 -0
- package/dist/testing/ApiResponse.js.map +1 -0
- package/dist/testing/RequestBuilder.d.ts +155 -35
- package/dist/testing/RequestBuilder.d.ts.map +1 -1
- package/dist/testing/RequestBuilder.js +455 -109
- package/dist/testing/RequestBuilder.js.map +1 -1
- package/dist/testing/TestClient.d.ts +53 -37
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +84 -52
- package/dist/testing/TestClient.js.map +1 -1
- package/dist/utils/Macroable.d.ts +30 -0
- package/dist/utils/Macroable.d.ts.map +1 -0
- package/dist/utils/Macroable.js +43 -0
- package/dist/utils/Macroable.js.map +1 -0
- package/dist/utils/inflect.d.ts +17 -0
- package/dist/utils/inflect.d.ts.map +1 -0
- package/dist/utils/inflect.js +32 -0
- package/dist/utils/inflect.js.map +1 -0
- package/dist/utils/objectPath.d.ts +57 -0
- package/dist/utils/objectPath.d.ts.map +1 -0
- package/dist/utils/objectPath.js +141 -0
- package/dist/utils/objectPath.js.map +1 -0
- package/events.darwin-arm64.node +0 -0
- package/events.darwin-x64.node +0 -0
- package/events.linux-arm64-gnu.node +0 -0
- package/events.linux-x64-gnu.node +0 -0
- package/events.win32-x64-msvc.node +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +20 -2
- package/scheduler.darwin-arm64.node +0 -0
- package/scheduler.darwin-x64.node +0 -0
- package/scheduler.linux-arm64-gnu.node +0 -0
- package/scheduler.linux-x64-gnu.node +0 -0
- package/scheduler.win32-x64-msvc.node +0 -0
- package/src/ConfigLoader.ts +72 -9
- package/src/HttpKernel.ts +53 -15
- package/src/Ignitor.ts +364 -45
- package/src/console/BaseCommand.ts +467 -0
- package/src/console/Console.ts +174 -0
- package/src/console/ExceptionHandler.ts +91 -0
- package/src/console/HelpCommand.ts +37 -0
- package/src/console/IndexGenerator.ts +79 -0
- package/src/console/Kernel.ts +1382 -0
- package/src/console/ListCommand.ts +55 -0
- package/src/console/assertions.ts +114 -0
- package/src/console/cliui.ts +756 -0
- package/src/console/decorators.ts +199 -0
- package/src/console/index.ts +67 -0
- package/src/console/loaders.ts +145 -0
- package/src/console/parser.ts +598 -0
- package/src/console/prompts.ts +548 -0
- package/src/console/tracing.ts +22 -0
- package/src/console/types.ts +280 -0
- package/src/console/ui.ts +37 -0
- package/src/console/utils.ts +69 -0
- package/src/container/Container.ts +198 -72
- package/src/container/types.ts +15 -2
- package/src/decorators/Service.ts +28 -3
- package/src/env/Env.ts +49 -5
- package/src/env/Secret.ts +41 -0
- package/src/env/interpolate.ts +54 -0
- package/src/env/loadEnvFiles.ts +12 -4
- package/src/env/schema.ts +109 -35
- package/src/errors/ReamError.ts +31 -0
- package/src/errors/prettyPrintError.ts +20 -0
- package/src/events/Emitter.ts +2 -2
- package/src/events/EventsProvider.ts +5 -5
- package/src/graphql/GraphQLEngine.ts +4 -4
- package/src/graphql/GraphQLProvider.ts +7 -3
- package/src/http/Exception.ts +214 -37
- package/src/http/HttpContext.ts +87 -18
- package/src/http/RedirectBuilder.ts +4 -1
- package/src/http/Request.ts +264 -34
- package/src/http/Response.ts +478 -27
- package/src/index.ts +41 -6
- package/src/middleware/Pipeline.ts +77 -6
- package/src/openapi/OpenApiProvider.ts +4 -4
- package/src/router/Router.ts +631 -113
- package/src/rpc/RpcProvider.ts +6 -2
- package/src/rpc/RpcRouter.ts +22 -7
- package/src/scheduler/ScheduleProvider.ts +7 -15
- package/src/server/Server.ts +49 -10
- package/src/services/app.ts +1 -1
- package/src/services/console.ts +42 -0
- package/src/session/SessionMiddleware.ts +4 -4
- package/src/storage/StaticProvider.ts +1 -1
- package/src/testing/ApiResponse.ts +691 -0
- package/src/testing/RequestBuilder.ts +577 -137
- package/src/testing/TestClient.ts +110 -77
- package/src/utils/Macroable.ts +54 -0
- package/src/utils/inflect.ts +29 -0
- package/src/utils/objectPath.ts +142 -0
- package/dist/console/CommandRunner.d.ts +0 -18
- package/dist/console/CommandRunner.d.ts.map +0 -1
- package/dist/console/CommandRunner.js +0 -65
- package/dist/console/CommandRunner.js.map +0 -1
- package/dist/decorators/Lazy.d.ts +0 -19
- package/dist/decorators/Lazy.d.ts.map +0 -1
- package/dist/decorators/Lazy.js +0 -53
- package/dist/decorators/Lazy.js.map +0 -1
- package/src/console/CommandRunner.ts +0 -82
- package/src/decorators/Lazy.ts +0 -57
package/src/rpc/RpcProvider.ts
CHANGED
|
@@ -42,6 +42,7 @@ export interface RpcConfig {
|
|
|
42
42
|
|
|
43
43
|
export class RpcProvider extends Provider {
|
|
44
44
|
readonly rpc: RpcRouter
|
|
45
|
+
#registered = false
|
|
45
46
|
|
|
46
47
|
constructor(app: AppContext, options: RpcProviderOptions = {}) {
|
|
47
48
|
super(app)
|
|
@@ -51,7 +52,9 @@ export class RpcProvider extends Provider {
|
|
|
51
52
|
override register(): void {
|
|
52
53
|
const container = this.app.container
|
|
53
54
|
if (container.has('rpc')) {
|
|
54
|
-
|
|
55
|
+
// Idempotent re-register: tracked with a flag rather than
|
|
56
|
+
// `container.resolve('rpc')` because resolution is now async.
|
|
57
|
+
if (this.#registered) return
|
|
55
58
|
throw new ReamError(
|
|
56
59
|
'RPC_PROVIDER_ALREADY_REGISTERED',
|
|
57
60
|
"Container token 'rpc' is already bound to a different instance",
|
|
@@ -62,12 +65,13 @@ export class RpcProvider extends Provider {
|
|
|
62
65
|
}
|
|
63
66
|
this.rpc.useContainer(container)
|
|
64
67
|
container.singleton('rpc', () => this.rpc)
|
|
68
|
+
this.#registered = true
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
override async boot(): Promise<void> {
|
|
68
72
|
const config = this.app.config.get<RpcConfig>('rpc')
|
|
69
73
|
const path = config?.path ?? '/rpc'
|
|
70
|
-
const router = this.app.container.make<Router>('router')
|
|
74
|
+
const router = await this.app.container.make<Router>('router')
|
|
71
75
|
// RpcRouter.handle() reads the registered methods at request time, so the
|
|
72
76
|
// mount can happen before apps finish registering methods.
|
|
73
77
|
const route = router.post(path, (ctx: HttpContext) => this.rpc.handle(ctx))
|
package/src/rpc/RpcRouter.ts
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from '@c9up/comet'
|
|
21
21
|
import type { HttpContext } from '../http/HttpContext.js'
|
|
22
22
|
import type { MiddlewareRegistry, RuntimeValidator } from '../middleware/Pipeline.js'
|
|
23
|
-
import { compose } from '../middleware/Pipeline.js'
|
|
23
|
+
import { compose, runValidator } from '../middleware/Pipeline.js'
|
|
24
24
|
|
|
25
25
|
export type RpcHandler = (ctx: HttpContext, params: unknown) => Promise<unknown> | unknown
|
|
26
26
|
|
|
@@ -29,8 +29,8 @@ export type RpcHandler = (ctx: HttpContext, params: unknown) => Promise<unknown>
|
|
|
29
29
|
* the shared `'middleware'` registry, and `validator:<name>` schemas.
|
|
30
30
|
*/
|
|
31
31
|
interface RpcContainer {
|
|
32
|
-
make<T>(target: new (...args: unknown[]) => T): T
|
|
33
|
-
resolve<T>(token: string): T
|
|
32
|
+
make<T>(target: new (...args: unknown[]) => T): Promise<T>
|
|
33
|
+
resolve<T>(token: string): Promise<T>
|
|
34
34
|
has(token: string): boolean
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -101,7 +101,7 @@ function checkRpcAuthorization(
|
|
|
101
101
|
def: RpcMethodDefinition,
|
|
102
102
|
): { code: number; message: string } | undefined {
|
|
103
103
|
const needsAuth = def.guards.length > 0 || def.roles.length > 0 || def.permissions.length > 0
|
|
104
|
-
if (needsAuth && !ctx.auth?.
|
|
104
|
+
if (needsAuth && !ctx.auth?.isAuthenticated) {
|
|
105
105
|
return { code: -32003, message: 'Unauthorized' }
|
|
106
106
|
}
|
|
107
107
|
if (def.roles.length > 0) {
|
|
@@ -163,7 +163,7 @@ export class RpcRouter {
|
|
|
163
163
|
this.method(`${prefix}.${methodName}`, async (ctx, params) => {
|
|
164
164
|
// Resolve through the container on every call (fresh DI per request,
|
|
165
165
|
// like GraphQLEngine), falling back to a bare `new` when unset.
|
|
166
|
-
const instance = this.#container ? this.#container.make(controller) : new controller()
|
|
166
|
+
const instance = this.#container ? await this.#container.make(controller) : new controller()
|
|
167
167
|
return instance[methodName](ctx, params)
|
|
168
168
|
})
|
|
169
169
|
}
|
|
@@ -238,7 +238,7 @@ export class RpcRouter {
|
|
|
238
238
|
*/
|
|
239
239
|
async #runMiddleware(ctx: HttpContext, names: string[]): Promise<void> {
|
|
240
240
|
const registry = this.#container?.has('middleware')
|
|
241
|
-
? this.#container.resolve<MiddlewareRegistry>('middleware')
|
|
241
|
+
? await this.#container.resolve<MiddlewareRegistry>('middleware')
|
|
242
242
|
: undefined
|
|
243
243
|
if (!registry) {
|
|
244
244
|
throw new Error(
|
|
@@ -285,7 +285,22 @@ export class RpcRouter {
|
|
|
285
285
|
id,
|
|
286
286
|
)
|
|
287
287
|
}
|
|
288
|
-
const
|
|
288
|
+
const validator = await this.#container.resolve<RuntimeValidator>(token)
|
|
289
|
+
// `runValidator` picks the async result form first — the synchronous
|
|
290
|
+
// one cannot run `unique` / `exists` and throws outright when the schema
|
|
291
|
+
// carries them.
|
|
292
|
+
let outcome: Awaited<ReturnType<typeof runValidator>>
|
|
293
|
+
try {
|
|
294
|
+
outcome = await runValidator(validator, params)
|
|
295
|
+
} catch (err) {
|
|
296
|
+
return rpcError(
|
|
297
|
+
-32603,
|
|
298
|
+
err instanceof TypeError
|
|
299
|
+
? `Validator '${def.validator}' exposes no usable validate method.`
|
|
300
|
+
: `Validator '${def.validator}' failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
301
|
+
id,
|
|
302
|
+
)
|
|
303
|
+
}
|
|
289
304
|
if (!outcome.valid) return rpcError(-32602, 'Invalid params', id, outcome.errors)
|
|
290
305
|
effectiveParams = outcome.data ?? params
|
|
291
306
|
}
|
|
@@ -41,6 +41,7 @@ let activeProvider: ScheduleProvider | undefined
|
|
|
41
41
|
export class ScheduleProvider extends Provider {
|
|
42
42
|
readonly scheduler: Scheduler
|
|
43
43
|
#booted = false
|
|
44
|
+
#registered = false
|
|
44
45
|
|
|
45
46
|
constructor(app: AppContext, options: ScheduleProviderOptions = {}) {
|
|
46
47
|
super(app)
|
|
@@ -65,20 +66,10 @@ export class ScheduleProvider extends Provider {
|
|
|
65
66
|
override register(): void {
|
|
66
67
|
const scheduler = this.scheduler
|
|
67
68
|
const container = this.app.container
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
existing = container.resolve('scheduler')
|
|
74
|
-
} catch {
|
|
75
|
-
existing = undefined
|
|
76
|
-
}
|
|
77
|
-
if (existing !== undefined) {
|
|
78
|
-
if (existing === scheduler) {
|
|
79
|
-
// Same provider re-running its register phase — no-op.
|
|
80
|
-
return
|
|
81
|
-
}
|
|
69
|
+
if (container.has('scheduler')) {
|
|
70
|
+
// Idempotent re-register: tracked with a flag rather than
|
|
71
|
+
// `container.resolve('scheduler')` because resolution is now async.
|
|
72
|
+
if (this.#registered) return
|
|
82
73
|
throw new ReamError(
|
|
83
74
|
'SCHEDULE_PROVIDER_ALREADY_REGISTERED',
|
|
84
75
|
"Container token 'scheduler' is already bound to a different instance",
|
|
@@ -88,6 +79,7 @@ export class ScheduleProvider extends Provider {
|
|
|
88
79
|
)
|
|
89
80
|
}
|
|
90
81
|
container.singleton('scheduler', () => scheduler)
|
|
82
|
+
this.#registered = true
|
|
91
83
|
}
|
|
92
84
|
|
|
93
85
|
override async boot(): Promise<void> {
|
|
@@ -130,7 +122,7 @@ export class ScheduleProvider extends Provider {
|
|
|
130
122
|
this.scheduler.register(taskName, cronExpr, async () => {
|
|
131
123
|
// Resolve from the container on every fire so transient
|
|
132
124
|
// services get a fresh instance each run.
|
|
133
|
-
const instance = this.app.container.make<Record<string, unknown>>(target)
|
|
125
|
+
const instance = await this.app.container.make<Record<string, unknown>>(target)
|
|
134
126
|
const method = instance[methodName]
|
|
135
127
|
if (typeof method !== 'function') {
|
|
136
128
|
throw new ReamError(
|
package/src/server/Server.ts
CHANGED
|
@@ -12,11 +12,12 @@ import type { MiddlewareFunction } from '../middleware/Pipeline.js'
|
|
|
12
12
|
import type { Router } from '../router/Router.js'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* A middleware class with a handle method.
|
|
16
|
-
*
|
|
15
|
+
* A middleware class with a handle method. The optional third argument carries
|
|
16
|
+
* per-route configuration passed through a named-middleware factory (AdonisJS
|
|
17
|
+
* `handle(ctx, next, args)`).
|
|
17
18
|
*/
|
|
18
19
|
export interface MiddlewareClass {
|
|
19
|
-
handle(ctx: HttpContext, next: () => Promise<void
|
|
20
|
+
handle(ctx: HttpContext, next: () => Promise<void>, args?: unknown): Promise<void> | void
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/** Lazy import returning a module with a default export. */
|
|
@@ -109,7 +110,11 @@ export class Server {
|
|
|
109
110
|
|
|
110
111
|
/**
|
|
111
112
|
* Convert a MiddlewareEntry (lazy import or function) into a MiddlewareFunction.
|
|
112
|
-
*
|
|
113
|
+
* The imported class is cached on first call; the INSTANCE is resolved through
|
|
114
|
+
* the request's IoC container so `@inject()` constructor dependencies are wired
|
|
115
|
+
* (AdonisJS resolves middleware via the container — a plain `new Class()` gives
|
|
116
|
+
* every injected dependency `undefined`). Falls back to `new Class()` only when
|
|
117
|
+
* no container is present (mock contexts in unit tests).
|
|
113
118
|
*/
|
|
114
119
|
export function resolveMiddlewareEntry(entry: MiddlewareEntry): MiddlewareFunction {
|
|
115
120
|
// Direct middleware function (2 params: ctx, next)
|
|
@@ -117,16 +122,50 @@ export function resolveMiddlewareEntry(entry: MiddlewareEntry): MiddlewareFuncti
|
|
|
117
122
|
return entry
|
|
118
123
|
}
|
|
119
124
|
|
|
120
|
-
// Lazy import of a middleware class —
|
|
121
|
-
//
|
|
125
|
+
// Lazy import of a middleware class — cache the CLASS on first invocation,
|
|
126
|
+
// then resolve the instance per request through the container (DI). The
|
|
127
|
+
// container's own singleton bindings still cache instances where desired.
|
|
122
128
|
const lazyImport = entry
|
|
123
|
-
let
|
|
129
|
+
let cachedClass: MiddlewareClassConstructor | undefined
|
|
124
130
|
return async (ctx: HttpContext, next: () => Promise<void>) => {
|
|
125
|
-
if (!
|
|
131
|
+
if (!cachedClass) {
|
|
126
132
|
const mod = await lazyImport()
|
|
127
|
-
|
|
133
|
+
cachedClass = mod.default
|
|
134
|
+
}
|
|
135
|
+
const instance = ctx.containerResolver
|
|
136
|
+
? await ctx.containerResolver.make<MiddlewareClass>(cachedClass)
|
|
137
|
+
: new cachedClass()
|
|
138
|
+
await instance.handle(ctx, next)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Turn a middleware entry into a FACTORY `(args?) => MiddlewareFunction`
|
|
144
|
+
* (AdonisJS named-middleware factories). The returned function bakes `args` in
|
|
145
|
+
* and forwards them to the class's `handle(ctx, next, args)`. A plain function
|
|
146
|
+
* middleware ignores `args` (it has no third parameter). Class resolution +
|
|
147
|
+
* caching mirror {@link resolveMiddlewareEntry} (imported once, instance via DI).
|
|
148
|
+
*/
|
|
149
|
+
export function resolveParametrizedMiddlewareEntry(
|
|
150
|
+
entry: MiddlewareEntry,
|
|
151
|
+
): (args?: unknown) => MiddlewareFunction {
|
|
152
|
+
if (isMiddlewareFunction(entry)) {
|
|
153
|
+
return () => entry
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const lazyImport = entry
|
|
157
|
+
let cachedClass: MiddlewareClassConstructor | undefined
|
|
158
|
+
return (args?: unknown): MiddlewareFunction => {
|
|
159
|
+
return async (ctx: HttpContext, next: () => Promise<void>) => {
|
|
160
|
+
if (!cachedClass) {
|
|
161
|
+
const mod = await lazyImport()
|
|
162
|
+
cachedClass = mod.default
|
|
163
|
+
}
|
|
164
|
+
const instance = ctx.containerResolver
|
|
165
|
+
? await ctx.containerResolver.make<MiddlewareClass>(cachedClass)
|
|
166
|
+
: new cachedClass()
|
|
167
|
+
await instance.handle(ctx, next, args)
|
|
128
168
|
}
|
|
129
|
-
await cached.handle(ctx, next)
|
|
130
169
|
}
|
|
131
170
|
}
|
|
132
171
|
|
package/src/services/app.ts
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console singleton service.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import consoleApp from '@c9up/ream/services/console'
|
|
6
|
+
* if (await consoleApp.hasCommand('make:controller')) {
|
|
7
|
+
* const command = await consoleApp.exec('make:controller', ['user', '--resource'])
|
|
8
|
+
* }
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Console } from '../console/Console.js'
|
|
12
|
+
|
|
13
|
+
let instance: Console | undefined
|
|
14
|
+
|
|
15
|
+
/** @internal Set the consoleApp instance (called by Ignitor). */
|
|
16
|
+
export function setConsole(consoleApp: Console): void {
|
|
17
|
+
instance = consoleApp
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @internal Unset the locator IF it still points at `consoleApp` (called by
|
|
22
|
+
* Ignitor.stop()) — same ownership guard as the app service: a second Ignitor
|
|
23
|
+
* rebinding the locator must not be torn down by the first one stopping.
|
|
24
|
+
*/
|
|
25
|
+
export function clearConsole(consoleApp: Console): void {
|
|
26
|
+
if (instance === consoleApp) instance = undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const consoleApp: Console = new Proxy({} as Console, {
|
|
30
|
+
get(_target, prop) {
|
|
31
|
+
if (!instance) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
'Console accessed before initialization. ' +
|
|
34
|
+
'Ensure this code runs during or after the boot phase.',
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
const value = Reflect.get(instance, prop, instance)
|
|
38
|
+
return typeof value === 'function' ? value.bind(instance) : value
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
export default consoleApp
|
|
@@ -56,7 +56,7 @@ export default class SessionMiddleware {
|
|
|
56
56
|
const isProduction = process.env.NODE_ENV === 'production'
|
|
57
57
|
|
|
58
58
|
// Read session ID from cookie — pre-parsed by the Rust HyperServer.
|
|
59
|
-
let sessionId = ctx.request.
|
|
59
|
+
let sessionId = ctx.request.plainCookie(cookieName)
|
|
60
60
|
const hadIncomingCookie = sessionId !== null
|
|
61
61
|
|
|
62
62
|
// Cookie driver: the cookie value IS the session data (encrypted)
|
|
@@ -65,7 +65,7 @@ export default class SessionMiddleware {
|
|
|
65
65
|
sessionId = sessionId ?? generateSessionId()
|
|
66
66
|
const session = new Session(sessionId, data)
|
|
67
67
|
ctx.store.set('session', session)
|
|
68
|
-
|
|
68
|
+
ctx.session = session
|
|
69
69
|
|
|
70
70
|
await next()
|
|
71
71
|
|
|
@@ -85,7 +85,7 @@ export default class SessionMiddleware {
|
|
|
85
85
|
'Switch to a server-side driver (memory/redis) or reduce session data.\n',
|
|
86
86
|
)
|
|
87
87
|
}
|
|
88
|
-
ctx.response.
|
|
88
|
+
ctx.response.plainCookie(cookieName, encoded, {
|
|
89
89
|
maxAge: this.#config.clearWithBrowser ? undefined : maxAge,
|
|
90
90
|
path: '/',
|
|
91
91
|
httpOnly: true,
|
|
@@ -145,7 +145,7 @@ export default class SessionMiddleware {
|
|
|
145
145
|
// defeats HTTP caching, and leaks a Set-Cookie to CDNs. This mirrors
|
|
146
146
|
// the cookie-driver path above (which already omits `isNew`).
|
|
147
147
|
if (session.isDirty() || regenerated || (rolling && hadIncomingCookie)) {
|
|
148
|
-
ctx.response.
|
|
148
|
+
ctx.response.plainCookie(cookieName, session.sessionId, {
|
|
149
149
|
maxAge: this.#config.clearWithBrowser ? undefined : maxAge,
|
|
150
150
|
path: '/',
|
|
151
151
|
httpOnly: true,
|
|
@@ -34,7 +34,7 @@ export class StaticProvider extends Provider {
|
|
|
34
34
|
const config = this.app.config.get<StaticConfig>('static')
|
|
35
35
|
const middleware = this.#override ?? (config?.root ? new StaticMiddleware(config) : undefined)
|
|
36
36
|
if (!middleware) return // not configured — opt-out
|
|
37
|
-
const server = this.app.container.make<Server>('server')
|
|
37
|
+
const server = await this.app.container.make<Server>('server')
|
|
38
38
|
server.use([(ctx, next) => middleware.handle(ctx, next)])
|
|
39
39
|
}
|
|
40
40
|
}
|