@c9up/ream 0.1.26 → 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/Ignitor.d.ts +115 -7
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +233 -37
- 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.map +1 -1
- package/dist/container/Container.js +40 -12
- 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/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/index.d.ts +14 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -2
- 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 +39 -1
- package/dist/middleware/Pipeline.js.map +1 -1
- package/dist/rpc/RpcRouter.d.ts.map +1 -1
- package/dist/rpc/RpcRouter.js +13 -2
- package/dist/rpc/RpcRouter.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/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 +132 -72
- package/dist/testing/RequestBuilder.d.ts.map +1 -1
- package/dist/testing/RequestBuilder.js +389 -222
- package/dist/testing/RequestBuilder.js.map +1 -1
- package/dist/testing/TestClient.d.ts +34 -39
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +48 -56
- package/dist/testing/TestClient.js.map +1 -1
- package/dist/utils/Macroable.js +3 -3
- package/dist/utils/Macroable.js.map +1 -1
- 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 +15 -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/Ignitor.ts +340 -42
- 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 +55 -13
- package/src/container/types.ts +15 -2
- package/src/decorators/Service.ts +28 -3
- package/src/errors/ReamError.ts +31 -0
- package/src/errors/prettyPrintError.ts +20 -0
- package/src/index.ts +30 -4
- package/src/middleware/Pipeline.ts +76 -5
- package/src/rpc/RpcRouter.ts +16 -2
- package/src/services/app.ts +1 -1
- package/src/services/console.ts +42 -0
- package/src/testing/ApiResponse.ts +691 -0
- package/src/testing/RequestBuilder.ts +498 -275
- package/src/testing/TestClient.ts +63 -86
- package/src/utils/Macroable.ts +3 -3
- 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/src/console/CommandRunner.ts +0 -82
package/src/index.ts
CHANGED
|
@@ -169,9 +169,35 @@ export { resolveMiddlewareEntry, Server } from './server/Server.js'
|
|
|
169
169
|
|
|
170
170
|
// ─── Ignitor ────────────────────────────────────────────────
|
|
171
171
|
|
|
172
|
-
export
|
|
173
|
-
export {
|
|
174
|
-
export
|
|
172
|
+
export { BaseCommand } from './console/BaseCommand.js'
|
|
173
|
+
export { Logger, Ui } from './console/cliui.js'
|
|
174
|
+
export { args, flags } from './console/decorators.js'
|
|
175
|
+
// Renamed at the root: Ream already exports an HTTP `ExceptionHandler`, and
|
|
176
|
+
// two different things under one name is worse than a longer one. It keeps its
|
|
177
|
+
// Console name on the console entry point.
|
|
178
|
+
export { ExceptionHandler as ConsoleExceptionHandler } from './console/ExceptionHandler.js'
|
|
179
|
+
export { default as HelpCommand } from './console/HelpCommand.js'
|
|
180
|
+
export { IndexGenerator } from './console/IndexGenerator.js'
|
|
181
|
+
export { Kernel } from './console/Kernel.js'
|
|
182
|
+
export { default as ListCommand } from './console/ListCommand.js'
|
|
183
|
+
export { FsLoader, ListLoader } from './console/loaders.js'
|
|
184
|
+
export { Parser } from './console/parser.js'
|
|
185
|
+
export { Prompt, PromptTrap } from './console/prompts.js'
|
|
186
|
+
export type {
|
|
187
|
+
ArgumentMetaData,
|
|
188
|
+
CommandClass,
|
|
189
|
+
CommandInstance,
|
|
190
|
+
CommandOptions,
|
|
191
|
+
FlagMetaData,
|
|
192
|
+
} from './console/types.js'
|
|
193
|
+
export type {
|
|
194
|
+
AppEnvironment,
|
|
195
|
+
HyperServerLike,
|
|
196
|
+
IgnitorConfig,
|
|
197
|
+
ReamrcConfig,
|
|
198
|
+
TestSuiteConfig,
|
|
199
|
+
TestsConfig,
|
|
200
|
+
} from './Ignitor.js'
|
|
175
201
|
export { ConsoleKernel, defineConfig, Ignitor, prettyPrintError } from './Ignitor.js'
|
|
176
202
|
|
|
177
203
|
// ─── Providers ──────────────────────────────────────────────
|
|
@@ -205,7 +231,7 @@ export {
|
|
|
205
231
|
PIPELINE_STAGES,
|
|
206
232
|
validatePipelineConfig,
|
|
207
233
|
} from './errors/PipelineStageError.js'
|
|
208
|
-
export { ReamError } from './errors/ReamError.js'
|
|
234
|
+
export { isReamError, ReamError } from './errors/ReamError.js'
|
|
209
235
|
|
|
210
236
|
// ─── Utilities ──────────────────────────────────────────────
|
|
211
237
|
|
|
@@ -20,13 +20,84 @@ export type MiddlewareFunction = (
|
|
|
20
20
|
next: () => Promise<void>,
|
|
21
21
|
) => Promise<void> | void
|
|
22
22
|
|
|
23
|
+
/** What a route validator must hand back, whichever method it exposes. */
|
|
24
|
+
export interface RuntimeValidationResult {
|
|
25
|
+
valid: boolean
|
|
26
|
+
errors: unknown[]
|
|
27
|
+
data?: unknown
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
/**
|
|
24
|
-
* Structural contract for a route validator.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
31
|
+
* Structural contract for a route validator. ream stays decoupled from the
|
|
32
|
+
* validation engine — any object exposing a result-returning check works.
|
|
33
|
+
*
|
|
34
|
+
* Three spellings are accepted because `@c9up/rune` follows VineJS: `validate()`
|
|
35
|
+
* is async and throws, `validateResult()` is synchronous and never throws, and
|
|
36
|
+
* `validateResultAsync()` is the async result-based form.
|
|
37
|
+
*
|
|
38
|
+
* `validateResultAsync` is preferred. The synchronous `validateResult()` cannot
|
|
39
|
+
* run async rules — with `unique`, `exists` or `useAsync` in the schema it
|
|
40
|
+
* throws a plain Error, which would surface as a 500 instead of a 422.
|
|
27
41
|
*/
|
|
28
42
|
export interface RuntimeValidator {
|
|
29
|
-
validate(data: unknown):
|
|
43
|
+
validate?(data: unknown): RuntimeValidationResult | Promise<unknown>
|
|
44
|
+
validateResult?(data: unknown): RuntimeValidationResult
|
|
45
|
+
validateResultAsync?(data: unknown): Promise<RuntimeValidationResult>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A thrown validation failure, as raised by rune/VineJS `validate()`. */
|
|
49
|
+
interface ThrownValidationFailure {
|
|
50
|
+
messages: unknown[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isThrownValidationFailure(value: unknown): value is ThrownValidationFailure {
|
|
54
|
+
return (
|
|
55
|
+
value instanceof Error && 'messages' in value && Array.isArray(Reflect.get(value, 'messages'))
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isValidationResult(value: unknown): value is RuntimeValidationResult {
|
|
60
|
+
return typeof value === 'object' && value !== null && 'valid' in value
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Run a validator whatever contract it exposes, and always come back with a
|
|
65
|
+
* result object.
|
|
66
|
+
*
|
|
67
|
+
* Order matters: the async result form first (it is the only one that can run
|
|
68
|
+
* `unique` / `exists`), then the synchronous one, then VineJS's throwing
|
|
69
|
+
* `validate()` — awaited, and with its `E_VALIDATION_ERROR` translated back
|
|
70
|
+
* into a result so callers keep a single shape to handle.
|
|
71
|
+
*/
|
|
72
|
+
export async function runValidator(
|
|
73
|
+
validator: RuntimeValidator,
|
|
74
|
+
data: unknown,
|
|
75
|
+
): Promise<RuntimeValidationResult> {
|
|
76
|
+
if (typeof validator.validateResultAsync === 'function') {
|
|
77
|
+
return validator.validateResultAsync(data)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (typeof validator.validateResult === 'function') {
|
|
81
|
+
return validator.validateResult(data)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof validator.validate === 'function') {
|
|
85
|
+
try {
|
|
86
|
+
const outcome = await validator.validate(data)
|
|
87
|
+
// A result-returning `validate()` (not the VineJS contract) is honoured
|
|
88
|
+
// as-is; the throwing contract resolves to the validated payload.
|
|
89
|
+
return isValidationResult(outcome) ? outcome : { valid: true, errors: [], data: outcome }
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (isThrownValidationFailure(err)) {
|
|
92
|
+
return { valid: false, errors: err.messages }
|
|
93
|
+
}
|
|
94
|
+
throw err
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
throw new TypeError(
|
|
99
|
+
'Route validator exposes none of validateResultAsync(), validateResult() or validate().',
|
|
100
|
+
)
|
|
30
101
|
}
|
|
31
102
|
|
|
32
103
|
/** Named middleware registry. */
|
|
@@ -174,7 +245,7 @@ function createGuardMiddleware(
|
|
|
174
245
|
function createValidationMiddleware(validators: RuntimeValidator[]): MiddlewareFunction {
|
|
175
246
|
return async (ctx, next) => {
|
|
176
247
|
for (const validator of validators) {
|
|
177
|
-
const result = validator
|
|
248
|
+
const result = await runValidator(validator, ctx.request.body())
|
|
178
249
|
if (!result.valid) {
|
|
179
250
|
throw new E_VALIDATION_ERROR(result.errors)
|
|
180
251
|
}
|
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
|
|
|
@@ -286,7 +286,21 @@ export class RpcRouter {
|
|
|
286
286
|
)
|
|
287
287
|
}
|
|
288
288
|
const validator = await this.#container.resolve<RuntimeValidator>(token)
|
|
289
|
-
|
|
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
|
+
}
|
|
290
304
|
if (!outcome.valid) return rpcError(-32602, 'Invalid params', id, outcome.errors)
|
|
291
305
|
effectiveParams = outcome.data ?? params
|
|
292
306
|
}
|
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
|