@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/Ignitor.ts
CHANGED
|
@@ -14,9 +14,13 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { Application } from './Application.js'
|
|
17
|
+
import type { Console } from './console/Console.js'
|
|
18
|
+
import type { CommandLoader, Kernel as ConsoleKernelInstance } from './console/Kernel.js'
|
|
19
|
+
import { type CommandClass, isCommandClass } from './console/types.js'
|
|
17
20
|
import type { ErrorEvent } from './ErrorBoundary.js'
|
|
18
21
|
import { ErrorBoundary } from './ErrorBoundary.js'
|
|
19
22
|
import { loadEnvFiles } from './env/loadEnvFiles.js'
|
|
23
|
+
import { prettyPrintError } from './errors/prettyPrintError.js'
|
|
20
24
|
import { ReamError } from './errors/ReamError.js'
|
|
21
25
|
import type { Emitter } from './events/Emitter.js'
|
|
22
26
|
import type { ShutdownHandle } from './GracefulShutdown.js'
|
|
@@ -30,6 +34,8 @@ import { MiddlewareRegistry } from './middleware/Pipeline.js'
|
|
|
30
34
|
import type { AppContext, ProviderContract } from './Provider.js'
|
|
31
35
|
import { callProviderPhase } from './Provider.js'
|
|
32
36
|
import { Router } from './router/Router.js'
|
|
37
|
+
import { CookieSigner } from './security/CookieSigner.js'
|
|
38
|
+
import { SignedUrl } from './security/SignedUrl.js'
|
|
33
39
|
import { Server } from './server/Server.js'
|
|
34
40
|
import { clearApp, setApp } from './services/app.js'
|
|
35
41
|
import { clearRouter, setRouter } from './services/router.js'
|
|
@@ -57,12 +63,84 @@ export interface ReamrcConfig {
|
|
|
57
63
|
}
|
|
58
64
|
>
|
|
59
65
|
commands?: Array<() => Promise<unknown>>
|
|
66
|
+
/**
|
|
67
|
+
* Command shorthands — Console's `commandsAliases`. The value is the command the
|
|
68
|
+
* alias stands for, flags included:
|
|
69
|
+
* `{ resource: 'make:controller --resource' }`
|
|
70
|
+
*/
|
|
71
|
+
commandsAliases?: Record<string, string>
|
|
60
72
|
modules?: {
|
|
61
73
|
/** Path to the modules directory (relative to app root). Default: './app/modules' */
|
|
62
74
|
path?: string
|
|
63
75
|
/** Auto-loaded files in each module directory. Default: ['routes'] */
|
|
64
76
|
autoload?: string[]
|
|
65
77
|
}
|
|
78
|
+
/** Test suites and runner settings — the `tests` block of adonisrc.ts. */
|
|
79
|
+
tests?: TestsConfig
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One test suite, as declared in the rc file (AdonisJS `tests.suites[]`). */
|
|
83
|
+
export interface TestSuiteConfig {
|
|
84
|
+
/** Suite name — what `ream test <name>` selects. */
|
|
85
|
+
name: string
|
|
86
|
+
/**
|
|
87
|
+
* The suite's files: a glob, several, or a callback returning their URLs
|
|
88
|
+
* (Japa `TestFiles`).
|
|
89
|
+
*/
|
|
90
|
+
files: string | string[] | (() => URL[] | Promise<URL[]>)
|
|
91
|
+
/** Per-test timeout for this suite, in ms. */
|
|
92
|
+
timeout?: number
|
|
93
|
+
/** Extra attempts on failure for this suite. */
|
|
94
|
+
retries?: number
|
|
95
|
+
/**
|
|
96
|
+
* Configure the suite before it runs (Japa `TestSuite.configure`). Receives
|
|
97
|
+
* the same handle as the bootstrap's `configureSuite`, and runs after it.
|
|
98
|
+
*
|
|
99
|
+
* Costs an import of the rc file in every worker, since a function cannot
|
|
100
|
+
* cross a process boundary — `configureSuite` in `tests/bootstrap.ts` does
|
|
101
|
+
* the same job for free, and is what AdonisJS itself uses.
|
|
102
|
+
*/
|
|
103
|
+
configure?: (suite: TestSuiteHandle) => void
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* What a suite's `configure` receives — helix's `SuiteHandle`, re-declared here
|
|
108
|
+
* so the rc file types without ream depending on the runner at type level.
|
|
109
|
+
*/
|
|
110
|
+
export interface TestSuiteHandle {
|
|
111
|
+
readonly name: string
|
|
112
|
+
setup(fn: () => void | Promise<void>): TestSuiteHandle
|
|
113
|
+
teardown(fn: () => void | Promise<void>): TestSuiteHandle
|
|
114
|
+
onTest(callback: (test: unknown) => void): TestSuiteHandle
|
|
115
|
+
onGroup(callback: (group: unknown) => void): TestSuiteHandle
|
|
116
|
+
bail(toggle?: boolean): TestSuiteHandle
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The `tests` block of the rc file — AdonisJS `adonisrc.ts` `tests`, field for
|
|
121
|
+
* field. The runner that consumes it is helix; ream reads the file, exactly as
|
|
122
|
+
* `@adonisjs/core` reads adonisrc and hands the suites to Japa.
|
|
123
|
+
*/
|
|
124
|
+
export interface TestsConfig {
|
|
125
|
+
/** Named suites. `ream test` with no argument runs them all, in order. */
|
|
126
|
+
suites?: TestSuiteConfig[]
|
|
127
|
+
/** Default per-test timeout, in ms. */
|
|
128
|
+
timeout?: number
|
|
129
|
+
/** `process.exit()` once the run ends instead of draining the event loop. */
|
|
130
|
+
forceExit?: boolean
|
|
131
|
+
/**
|
|
132
|
+
* Ream particularity: the bootstrap module's path. AdonisJS hardcodes
|
|
133
|
+
* `tests/bootstrap.ts`; that stays the default here, and this overrides it.
|
|
134
|
+
*/
|
|
135
|
+
bootstrap?: string
|
|
136
|
+
/**
|
|
137
|
+
* Point `@japa/runner/core` at helix's shim in every worker, so official Japa
|
|
138
|
+
* plugins (`@japa/assert`, …) instrument the runner that is actually running.
|
|
139
|
+
*
|
|
140
|
+
* Off by default: redirecting a package specifier is not something to do
|
|
141
|
+
* behind a user's back, and a project with no Japa plugin gains nothing.
|
|
142
|
+
*/
|
|
143
|
+
japaPlugins?: boolean
|
|
66
144
|
}
|
|
67
145
|
|
|
68
146
|
/** defineConfig helper — like AdonisJS defineConfig(). */
|
|
@@ -132,6 +210,7 @@ export class Ignitor {
|
|
|
132
210
|
private phase: 'created' | 'registered' | 'booted' | 'started' | 'ready' | 'shutdown' = 'created'
|
|
133
211
|
private hotReloadCleanup?: () => void
|
|
134
212
|
#shutdownHandle?: ShutdownHandle
|
|
213
|
+
#console?: Console
|
|
135
214
|
|
|
136
215
|
// Inline configuration (for simple use or testing)
|
|
137
216
|
private inlineRoutes?: (router: Router) => void
|
|
@@ -179,6 +258,26 @@ export class Ignitor {
|
|
|
179
258
|
this.app.setAppRoot(root)
|
|
180
259
|
}
|
|
181
260
|
|
|
261
|
+
// Encryption / cookie-signing service (AdonisJS `APP_KEY` idiom). Registered
|
|
262
|
+
// only when APP_KEY is set; HttpContext hands it to Response/Request so
|
|
263
|
+
// `cookie()` can sign, `encryptedCookie()` can encrypt and `request.cookie()`
|
|
264
|
+
// can verify. Without APP_KEY, cookies stay plain (unsigned).
|
|
265
|
+
const appKey = process.env.APP_KEY
|
|
266
|
+
if (appKey) {
|
|
267
|
+
if (appKey.length < 16) {
|
|
268
|
+
throw new Error(
|
|
269
|
+
'APP_KEY is too short — use at least a 16-character (ideally 32-byte) random key for cookie signing/encryption.',
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
const signer = new CookieSigner(appKey)
|
|
273
|
+
this.app.container.singleton('encryption', () => signer)
|
|
274
|
+
// Signed-URL helper (same APP_KEY): the router signs via makeSignedUrl,
|
|
275
|
+
// HttpContext hands it to the request so hasValidSignature() can verify.
|
|
276
|
+
const signedUrl = new SignedUrl({ secret: appKey })
|
|
277
|
+
this.app.container.singleton('signedUrl', () => signedUrl)
|
|
278
|
+
this.router.setSignedUrl(signedUrl)
|
|
279
|
+
}
|
|
280
|
+
|
|
182
281
|
// Set service singletons so route/kernel files can import them
|
|
183
282
|
setApp(this.app)
|
|
184
283
|
setRouter(this.router)
|
|
@@ -289,6 +388,12 @@ export class Ignitor {
|
|
|
289
388
|
await this.phaseRegister()
|
|
290
389
|
await this.phaseBoot()
|
|
291
390
|
await this.phaseStart()
|
|
391
|
+
// Console documents its `consoleApp` service as available once the application has
|
|
392
|
+
// booted, so the locator is installed here rather than on first use —
|
|
393
|
+
// `import consoleApp from '@c9up/ream/services/console'` must not throw in a running
|
|
394
|
+
// app. Only the façade is built (three small modules); loading the
|
|
395
|
+
// commands themselves stays lazy, inside `consoleApp.boot()`.
|
|
396
|
+
await this.consoleApp()
|
|
292
397
|
await this.phaseReady()
|
|
293
398
|
} catch (err) {
|
|
294
399
|
// A throw mid-boot (e.g. a provider ready() failing AFTER the HTTP port
|
|
@@ -307,7 +412,7 @@ export class Ignitor {
|
|
|
307
412
|
|
|
308
413
|
/**
|
|
309
414
|
* Load `.env` files into `process.env` before config and providers boot —
|
|
310
|
-
* mirroring AdonisJS, which loads env in BOTH the HTTP and the
|
|
415
|
+
* mirroring AdonisJS, which loads env in BOTH the HTTP and the consoleApp (console)
|
|
311
416
|
* flows. Without this, `ream migrate` and other console commands booted in a
|
|
312
417
|
* clean subprocess never saw the `.env` the web server got from the shell.
|
|
313
418
|
*
|
|
@@ -495,9 +600,8 @@ export class Ignitor {
|
|
|
495
600
|
// Core domain event: the app finished booting (all providers ready).
|
|
496
601
|
// Emitted once through the bus when events are wired — zero hot-path cost.
|
|
497
602
|
if (this.app.container.has('events')) {
|
|
498
|
-
this.app.container
|
|
499
|
-
|
|
500
|
-
.emit('app:ready', { environment: this.environment })
|
|
603
|
+
const bus = await this.app.container.resolve<Emitter>('events')
|
|
604
|
+
bus.emit('app:ready', { environment: this.environment })
|
|
501
605
|
}
|
|
502
606
|
|
|
503
607
|
// Dev-mode change watcher. IMPORTANT: this does NOT attempt an in-process
|
|
@@ -614,6 +718,20 @@ export class Ignitor {
|
|
|
614
718
|
*/
|
|
615
719
|
async stop(): Promise<void> {
|
|
616
720
|
const errors: unknown[] = []
|
|
721
|
+
|
|
722
|
+
// Release the consoleApp locator first — ownership-guarded, so a second Ignitor
|
|
723
|
+
// having rebound it is left alone.
|
|
724
|
+
if (this.#console !== undefined) {
|
|
725
|
+
const consoleApp = this.#console
|
|
726
|
+
this.#console = undefined
|
|
727
|
+
try {
|
|
728
|
+
const { clearConsole } = await import('./services/console.js')
|
|
729
|
+
clearConsole(consoleApp)
|
|
730
|
+
} catch {
|
|
731
|
+
/* the module never loaded — nothing to clear */
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
617
735
|
const attempt = async (step: () => void | Promise<void>): Promise<void> => {
|
|
618
736
|
try {
|
|
619
737
|
await step()
|
|
@@ -662,6 +780,51 @@ export class Ignitor {
|
|
|
662
780
|
return this.app
|
|
663
781
|
}
|
|
664
782
|
|
|
783
|
+
/**
|
|
784
|
+
* The application root passed to `new Ignitor(new URL('../', import.meta.url))`.
|
|
785
|
+
* Undefined for inline/test ignitors created without one.
|
|
786
|
+
*/
|
|
787
|
+
getAppRoot(): URL | undefined {
|
|
788
|
+
return this.appRoot
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/** Has the application already been started? */
|
|
792
|
+
isStarted(): boolean {
|
|
793
|
+
return this.phase === 'started' || this.phase === 'ready'
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* The `consoleApp` façade — the programmatic console.
|
|
798
|
+
*
|
|
799
|
+
* Built on demand: the console modules are only imported when something
|
|
800
|
+
* actually reaches for them, so an HTTP-only boot does not pay for the CLI.
|
|
801
|
+
*/
|
|
802
|
+
async consoleApp(): Promise<Console> {
|
|
803
|
+
if (this.#console !== undefined) return this.#console
|
|
804
|
+
|
|
805
|
+
const [{ Console }, { setConsole }] = await Promise.all([
|
|
806
|
+
import('./console/Console.js'),
|
|
807
|
+
import('./services/console.js'),
|
|
808
|
+
])
|
|
809
|
+
const { kernel, load } = await new ConsoleKernel(this).build()
|
|
810
|
+
const consoleApp = new Console({ kernel, load })
|
|
811
|
+
|
|
812
|
+
this.#console = consoleApp
|
|
813
|
+
setConsole(consoleApp)
|
|
814
|
+
this.app.container.singleton('console', () => consoleApp)
|
|
815
|
+
return consoleApp
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/** The loaded rc file, if `useRcFile()` was called. */
|
|
819
|
+
getRcFile(): ReamrcConfig | undefined {
|
|
820
|
+
return this.reamrc
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/** The custom module importer, when the app provided one. */
|
|
824
|
+
getImporter(): ((filePath: string) => Promise<unknown>) | undefined {
|
|
825
|
+
return this.config.importer
|
|
826
|
+
}
|
|
827
|
+
|
|
665
828
|
getRouter(): Router {
|
|
666
829
|
return this.router
|
|
667
830
|
}
|
|
@@ -723,65 +886,221 @@ export class Ignitor {
|
|
|
723
886
|
}
|
|
724
887
|
}
|
|
725
888
|
|
|
726
|
-
|
|
727
|
-
* Pretty-print an error (like AdonisJS prettyPrintError).
|
|
728
|
-
*/
|
|
729
|
-
export function prettyPrintError(error: unknown): void {
|
|
730
|
-
if (error instanceof ReamError) {
|
|
731
|
-
console.error(error.toDevString())
|
|
732
|
-
} else if (error instanceof Error) {
|
|
733
|
-
console.error(`\n ${error.message}\n`)
|
|
734
|
-
if (error.stack) console.error(error.stack)
|
|
735
|
-
} else {
|
|
736
|
-
console.error(error)
|
|
737
|
-
}
|
|
738
|
-
}
|
|
889
|
+
export { prettyPrintError }
|
|
739
890
|
|
|
740
891
|
/**
|
|
741
|
-
* ConsoleKernel —
|
|
742
|
-
*
|
|
892
|
+
* ConsoleKernel — boots the app in console mode and dispatches a command.
|
|
893
|
+
*
|
|
894
|
+
* Console parity: `new Ignitor(...).console().handle(process.argv.slice(2))`.
|
|
895
|
+
*
|
|
896
|
+
* Commands come from two places, as in Console:
|
|
897
|
+
* 1. the app's own `commands/` directory, discovered automatically;
|
|
898
|
+
* 2. `reamrc.commands[]`, which registers commands shipped by packages.
|
|
899
|
+
*
|
|
900
|
+
* The application is booted lazily — only for a command declaring
|
|
901
|
+
* `options.startApp`. A generator has no reason to open a database
|
|
902
|
+
* connection, and paying the boot cost on every `--help` is worse than
|
|
903
|
+
* pointless: it fails on a machine where the DB is simply not running.
|
|
743
904
|
*/
|
|
744
905
|
export class ConsoleKernel {
|
|
745
|
-
|
|
906
|
+
#ignitor: Ignitor
|
|
907
|
+
#started = false
|
|
746
908
|
|
|
747
909
|
constructor(ignitor: Ignitor) {
|
|
748
|
-
this
|
|
910
|
+
this.#ignitor = ignitor
|
|
749
911
|
}
|
|
750
912
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
913
|
+
/**
|
|
914
|
+
* Build the console kernel and the function that fills it.
|
|
915
|
+
*
|
|
916
|
+
* Shared by `handle()` (the CLI) and the `consoleApp` façade (programmatic use), so
|
|
917
|
+
* both see exactly the same commands — discovery plus `reamrc.commands` —
|
|
918
|
+
* instead of two loaders drifting apart.
|
|
919
|
+
*/
|
|
920
|
+
async build(): Promise<{ kernel: ConsoleKernelInstance; load: () => Promise<void> }> {
|
|
921
|
+
const { Kernel } = await import('./console/Kernel.js')
|
|
922
|
+
|
|
923
|
+
const kernel = new Kernel({
|
|
924
|
+
binaryName: 'ream',
|
|
925
|
+
// A `staysAlive` command ends itself through `this.terminate()`; the
|
|
926
|
+
// kernel deliberately does not tear the app down for those.
|
|
927
|
+
onTerminate: async () => {
|
|
928
|
+
if (this.#started) await this.#ignitor.stop()
|
|
929
|
+
},
|
|
930
|
+
startApp: async () => {
|
|
931
|
+
// The façade can be used from an already-running application; starting
|
|
932
|
+
// it a second time would re-register providers.
|
|
933
|
+
if (!this.#ignitor.isStarted()) {
|
|
934
|
+
await this.#ignitor.start()
|
|
935
|
+
this.#started = true
|
|
936
|
+
}
|
|
937
|
+
const app = this.#ignitor.getApp()
|
|
938
|
+
app.container.singleton('consoleKernel', () => kernel)
|
|
939
|
+
return app
|
|
940
|
+
},
|
|
941
|
+
})
|
|
942
|
+
|
|
943
|
+
// Discovery is registered as a LOADER, not run beside the kernel: `boot()`
|
|
944
|
+
// is then the single moment commands come in, whether they were found on
|
|
945
|
+
// disk, declared in the rc file, or added by an application's own loader.
|
|
946
|
+
kernel.addLoader(this.#commandLoader(kernel))
|
|
947
|
+
|
|
948
|
+
const load = async (): Promise<void> => {
|
|
949
|
+
const aliases = this.#ignitor.getRcFile()?.commandsAliases
|
|
950
|
+
if (aliases !== undefined) {
|
|
951
|
+
for (const [alias, expansion] of Object.entries(aliases)) {
|
|
952
|
+
kernel.addAlias(alias, expansion)
|
|
772
953
|
}
|
|
773
954
|
}
|
|
955
|
+
await kernel.boot()
|
|
774
956
|
}
|
|
775
957
|
|
|
776
|
-
|
|
958
|
+
return { kernel, load }
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
async handle(argv: string[]): Promise<void> {
|
|
962
|
+
const { kernel, load } = await this.build()
|
|
963
|
+
await load()
|
|
964
|
+
|
|
965
|
+
let staysAlive = false
|
|
777
966
|
try {
|
|
778
|
-
|
|
967
|
+
// `process.execArgv` IS what node was started with — Console's `nodeArgs`,
|
|
968
|
+
// which a command reads to know how the process was launched.
|
|
969
|
+
const result = await kernel.handle(argv, process.execArgv)
|
|
970
|
+
staysAlive = result.staysAlive
|
|
779
971
|
} finally {
|
|
780
972
|
// A throwing command must still release the Ignitor's resources
|
|
781
973
|
// (scheduler tickers, watchers) — otherwise the CLI process hangs.
|
|
782
|
-
|
|
974
|
+
// A `staysAlive` command keeps them on purpose.
|
|
975
|
+
if (this.#started && !staysAlive) await this.#ignitor.stop()
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* The application's commands, as a loader the kernel consumes at boot.
|
|
981
|
+
*
|
|
982
|
+
* Two sources, one collection: the `commands/` directory and the rc file's
|
|
983
|
+
* `commands[]`. Collecting them together is what lets a command listed in
|
|
984
|
+
* both be reported as the duplicate it is.
|
|
985
|
+
*/
|
|
986
|
+
#commandLoader(kernel: ConsoleCommandKernel): CommandLoader {
|
|
987
|
+
const found = new Map<string, CommandClass>()
|
|
988
|
+
|
|
989
|
+
return {
|
|
990
|
+
getMetaData: async () => {
|
|
991
|
+
await this.#discoverAppCommands(kernel, found)
|
|
992
|
+
await this.#loadPackageCommands(found)
|
|
993
|
+
// Imported here, not at the top of the file: the console stack is only
|
|
994
|
+
// loaded for a console dispatch, and a static import would pull it into
|
|
995
|
+
// every HTTP boot.
|
|
996
|
+
const { serializeCommand } = await import('./console/Kernel.js')
|
|
997
|
+
return [...found.values()].map(serializeCommand)
|
|
998
|
+
},
|
|
999
|
+
getCommand: async (metadata) => found.get(metadata.commandName) ?? null,
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Load every command in the app's `commands/` directory.
|
|
1005
|
+
*
|
|
1006
|
+
* Tolerant by design: a module that does not default-export a command is
|
|
1007
|
+
* reported and skipped rather than aborting the whole CLI. Discovery scans a
|
|
1008
|
+
* conventional directory, so a stray helper file there must not make
|
|
1009
|
+
* `ream list` unusable. Explicitly declared entries (`reamrc.commands`) are
|
|
1010
|
+
* held to a stricter standard — see {@link #loadPackageCommands}.
|
|
1011
|
+
*/
|
|
1012
|
+
async #discoverAppCommands(
|
|
1013
|
+
kernel: ConsoleCommandKernel,
|
|
1014
|
+
found: Map<string, CommandClass>,
|
|
1015
|
+
): Promise<void> {
|
|
1016
|
+
const root = this.#ignitor.getAppRoot()
|
|
1017
|
+
if (root === undefined) return
|
|
1018
|
+
|
|
1019
|
+
// The framework's own `FsLoader`, with the application's importer plugged
|
|
1020
|
+
// in: scanning a directory for commands is written once, and an app that
|
|
1021
|
+
// compiles its sources differently only replaces the import.
|
|
1022
|
+
const { FsLoader } = await import('./console/loaders.js')
|
|
1023
|
+
const importModule = (file: URL): Promise<unknown> => this.#importModule(file)
|
|
1024
|
+
|
|
1025
|
+
const loader = new (class extends FsLoader {
|
|
1026
|
+
protected override import(file: URL): Promise<unknown> {
|
|
1027
|
+
return importModule(file)
|
|
1028
|
+
}
|
|
1029
|
+
})(new URL('commands/', root)).onSkipped((fileName) => {
|
|
1030
|
+
// Tolerant by design: discovery scans a conventional directory, so a
|
|
1031
|
+
// stray helper there must not make `ream list` unusable.
|
|
1032
|
+
kernel.logger.warning(`Skipped ${fileName} in commands/ — no default-exported command class.`)
|
|
1033
|
+
})
|
|
1034
|
+
|
|
1035
|
+
for (const metadata of await loader.getMetaData()) {
|
|
1036
|
+
const command = await loader.getCommand(metadata)
|
|
1037
|
+
if (command !== null) found.set(command.commandName, command)
|
|
783
1038
|
}
|
|
784
1039
|
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Register commands declared in `reamrc.commands[]` — the channel for
|
|
1043
|
+
* commands shipped by packages, which discovery cannot see.
|
|
1044
|
+
*
|
|
1045
|
+
* Strict: an entry listed by hand that does not resolve to a command is a
|
|
1046
|
+
* configuration error, and silently ignoring it is how a command "disappears"
|
|
1047
|
+
* with no explanation.
|
|
1048
|
+
*/
|
|
1049
|
+
async #loadPackageCommands(found: Map<string, CommandClass>): Promise<void> {
|
|
1050
|
+
const declared = this.#ignitor.getRcFile()?.commands
|
|
1051
|
+
if (!declared) return
|
|
1052
|
+
|
|
1053
|
+
for (const entry of declared) {
|
|
1054
|
+
const command = commandOf(await entry())
|
|
1055
|
+
if (command === undefined) {
|
|
1056
|
+
throw new ReamError(
|
|
1057
|
+
'E_CONSOLE_INVALID_COMMAND',
|
|
1058
|
+
'An entry of reamrc.ts `commands` does not default-export a command class.',
|
|
1059
|
+
{
|
|
1060
|
+
hint: 'Expected `export default class X { static commandName = "..."; static description = "..."; run() {} }`.',
|
|
1061
|
+
},
|
|
1062
|
+
)
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// The most likely duplicate after the move to auto-discovery: a command
|
|
1066
|
+
// living in `commands/` AND still listed by hand. Say so, rather than
|
|
1067
|
+
// leaving the user to guess which two registrations collided.
|
|
1068
|
+
const existing = found.get(command.commandName)
|
|
1069
|
+
if (existing !== undefined && existing !== command) {
|
|
1070
|
+
throw new ReamError(
|
|
1071
|
+
'E_CONSOLE_DUPLICATE_COMMAND',
|
|
1072
|
+
`Two commands claim the name "${command.commandName}".`,
|
|
1073
|
+
{
|
|
1074
|
+
hint: 'Commands in commands/ are discovered automatically — remove this entry from reamrc.ts `commands`, which is only for commands shipped by packages.',
|
|
1075
|
+
},
|
|
1076
|
+
)
|
|
1077
|
+
}
|
|
1078
|
+
found.set(command.commandName, command)
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/** Honour the app's custom importer when it provided one. */
|
|
1083
|
+
async #importModule(file: URL): Promise<unknown> {
|
|
1084
|
+
const importer = this.#ignitor.getImporter()
|
|
1085
|
+
if (importer === undefined) return import(file.href)
|
|
1086
|
+
|
|
1087
|
+
const root = this.#ignitor.getAppRoot()
|
|
1088
|
+
const relative = root === undefined ? file.href : `./${file.href.slice(root.href.length)}`
|
|
1089
|
+
return importer(relative)
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/** The slice of the console kernel this class drives. */
|
|
1094
|
+
interface ConsoleCommandKernel {
|
|
1095
|
+
addAlias(alias: string, expansion: string): unknown
|
|
1096
|
+
logger: { warning(message: string): void }
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/** The command a module default-exports, or undefined when it exports none. */
|
|
1100
|
+
function commandOf(mod: unknown): CommandClass | undefined {
|
|
1101
|
+
if (typeof mod !== 'object' || mod === null) return undefined
|
|
1102
|
+
const value = Reflect.get(mod, 'default')
|
|
1103
|
+
return isCommandClass(value) ? value : undefined
|
|
785
1104
|
}
|
|
786
1105
|
|
|
787
1106
|
async function findAvailablePort(desired: number): Promise<number> {
|