@c9up/ream 0.1.26 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/README.md +65 -0
  2. package/dist/Ignitor.d.ts +115 -7
  3. package/dist/Ignitor.d.ts.map +1 -1
  4. package/dist/Ignitor.js +233 -37
  5. package/dist/Ignitor.js.map +1 -1
  6. package/dist/console/BaseCommand.d.ts +217 -0
  7. package/dist/console/BaseCommand.d.ts.map +1 -0
  8. package/dist/console/BaseCommand.js +340 -0
  9. package/dist/console/BaseCommand.js.map +1 -0
  10. package/dist/console/Console.d.ts +86 -0
  11. package/dist/console/Console.d.ts.map +1 -0
  12. package/dist/console/Console.js +134 -0
  13. package/dist/console/Console.js.map +1 -0
  14. package/dist/console/ExceptionHandler.d.ts +28 -0
  15. package/dist/console/ExceptionHandler.d.ts.map +1 -0
  16. package/dist/console/ExceptionHandler.js +76 -0
  17. package/dist/console/ExceptionHandler.js.map +1 -0
  18. package/dist/console/HelpCommand.d.ts +16 -0
  19. package/dist/console/HelpCommand.d.ts.map +1 -0
  20. package/dist/console/HelpCommand.js +40 -0
  21. package/dist/console/HelpCommand.js.map +1 -0
  22. package/dist/console/IndexGenerator.d.ts +24 -0
  23. package/dist/console/IndexGenerator.d.ts.map +1 -0
  24. package/dist/console/IndexGenerator.js +65 -0
  25. package/dist/console/IndexGenerator.js.map +1 -0
  26. package/dist/console/Kernel.d.ts +298 -0
  27. package/dist/console/Kernel.d.ts.map +1 -0
  28. package/dist/console/Kernel.js +1120 -0
  29. package/dist/console/Kernel.js.map +1 -0
  30. package/dist/console/ListCommand.d.ts +18 -0
  31. package/dist/console/ListCommand.d.ts.map +1 -0
  32. package/dist/console/ListCommand.js +60 -0
  33. package/dist/console/ListCommand.js.map +1 -0
  34. package/dist/console/assertions.d.ts +20 -0
  35. package/dist/console/assertions.d.ts.map +1 -0
  36. package/dist/console/assertions.js +84 -0
  37. package/dist/console/assertions.js.map +1 -0
  38. package/dist/console/cliui.d.ts +248 -0
  39. package/dist/console/cliui.d.ts.map +1 -0
  40. package/dist/console/cliui.js +587 -0
  41. package/dist/console/cliui.js.map +1 -0
  42. package/dist/console/decorators.d.ts +90 -0
  43. package/dist/console/decorators.d.ts.map +1 -0
  44. package/dist/console/decorators.js +142 -0
  45. package/dist/console/decorators.js.map +1 -0
  46. package/dist/console/index.d.ts +32 -0
  47. package/dist/console/index.d.ts.map +1 -0
  48. package/dist/console/index.js +24 -0
  49. package/dist/console/index.js.map +1 -0
  50. package/dist/console/loaders.d.ts +52 -0
  51. package/dist/console/loaders.d.ts.map +1 -0
  52. package/dist/console/loaders.js +131 -0
  53. package/dist/console/loaders.js.map +1 -0
  54. package/dist/console/parser.d.ts +86 -0
  55. package/dist/console/parser.d.ts.map +1 -0
  56. package/dist/console/parser.js +440 -0
  57. package/dist/console/parser.js.map +1 -0
  58. package/dist/console/prompts.d.ts +124 -0
  59. package/dist/console/prompts.d.ts.map +1 -0
  60. package/dist/console/prompts.js +364 -0
  61. package/dist/console/prompts.js.map +1 -0
  62. package/dist/console/tracing.d.ts +17 -0
  63. package/dist/console/tracing.d.ts.map +1 -0
  64. package/dist/console/tracing.js +11 -0
  65. package/dist/console/tracing.js.map +1 -0
  66. package/dist/console/types.d.ts +255 -0
  67. package/dist/console/types.d.ts.map +1 -0
  68. package/dist/console/types.js +25 -0
  69. package/dist/console/types.js.map +1 -0
  70. package/dist/console/ui.d.ts +20 -0
  71. package/dist/console/ui.d.ts.map +1 -0
  72. package/dist/console/ui.js +31 -0
  73. package/dist/console/ui.js.map +1 -0
  74. package/dist/console/utils.d.ts +27 -0
  75. package/dist/console/utils.d.ts.map +1 -0
  76. package/dist/console/utils.js +56 -0
  77. package/dist/console/utils.js.map +1 -0
  78. package/dist/container/Container.d.ts.map +1 -1
  79. package/dist/container/Container.js +40 -12
  80. package/dist/container/Container.js.map +1 -1
  81. package/dist/container/types.d.ts +14 -2
  82. package/dist/container/types.d.ts.map +1 -1
  83. package/dist/decorators/Service.d.ts +7 -0
  84. package/dist/decorators/Service.d.ts.map +1 -1
  85. package/dist/decorators/Service.js +23 -3
  86. package/dist/decorators/Service.js.map +1 -1
  87. package/dist/errors/ReamError.d.ts +25 -0
  88. package/dist/errors/ReamError.d.ts.map +1 -1
  89. package/dist/errors/ReamError.js +5 -0
  90. package/dist/errors/ReamError.js.map +1 -1
  91. package/dist/errors/prettyPrintError.d.ts +9 -0
  92. package/dist/errors/prettyPrintError.d.ts.map +1 -0
  93. package/dist/errors/prettyPrintError.js +22 -0
  94. package/dist/errors/prettyPrintError.js.map +1 -0
  95. package/dist/index.d.ts +14 -4
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +16 -2
  98. package/dist/index.js.map +1 -1
  99. package/dist/middleware/Pipeline.d.ts +29 -8
  100. package/dist/middleware/Pipeline.d.ts.map +1 -1
  101. package/dist/middleware/Pipeline.js +39 -1
  102. package/dist/middleware/Pipeline.js.map +1 -1
  103. package/dist/rpc/RpcRouter.d.ts.map +1 -1
  104. package/dist/rpc/RpcRouter.js +13 -2
  105. package/dist/rpc/RpcRouter.js.map +1 -1
  106. package/dist/services/app.d.ts +1 -1
  107. package/dist/services/app.js +1 -1
  108. package/dist/services/console.d.ts +21 -0
  109. package/dist/services/console.d.ts.map +1 -0
  110. package/dist/services/console.js +35 -0
  111. package/dist/services/console.js.map +1 -0
  112. package/dist/testing/ApiResponse.d.ts +218 -0
  113. package/dist/testing/ApiResponse.d.ts.map +1 -0
  114. package/dist/testing/ApiResponse.js +576 -0
  115. package/dist/testing/ApiResponse.js.map +1 -0
  116. package/dist/testing/RequestBuilder.d.ts +132 -72
  117. package/dist/testing/RequestBuilder.d.ts.map +1 -1
  118. package/dist/testing/RequestBuilder.js +389 -222
  119. package/dist/testing/RequestBuilder.js.map +1 -1
  120. package/dist/testing/TestClient.d.ts +34 -39
  121. package/dist/testing/TestClient.d.ts.map +1 -1
  122. package/dist/testing/TestClient.js +48 -56
  123. package/dist/testing/TestClient.js.map +1 -1
  124. package/dist/utils/Macroable.js +3 -3
  125. package/dist/utils/Macroable.js.map +1 -1
  126. package/events.darwin-arm64.node +0 -0
  127. package/events.darwin-x64.node +0 -0
  128. package/events.linux-arm64-gnu.node +0 -0
  129. package/events.linux-x64-gnu.node +0 -0
  130. package/events.win32-x64-msvc.node +0 -0
  131. package/index.darwin-arm64.node +0 -0
  132. package/index.darwin-x64.node +0 -0
  133. package/index.linux-arm64-gnu.node +0 -0
  134. package/index.linux-x64-gnu.node +0 -0
  135. package/index.win32-x64-msvc.node +0 -0
  136. package/package.json +15 -2
  137. package/scheduler.darwin-arm64.node +0 -0
  138. package/scheduler.darwin-x64.node +0 -0
  139. package/scheduler.linux-arm64-gnu.node +0 -0
  140. package/scheduler.linux-x64-gnu.node +0 -0
  141. package/scheduler.win32-x64-msvc.node +0 -0
  142. package/src/Ignitor.ts +340 -42
  143. package/src/console/BaseCommand.ts +467 -0
  144. package/src/console/Console.ts +174 -0
  145. package/src/console/ExceptionHandler.ts +91 -0
  146. package/src/console/HelpCommand.ts +37 -0
  147. package/src/console/IndexGenerator.ts +79 -0
  148. package/src/console/Kernel.ts +1382 -0
  149. package/src/console/ListCommand.ts +55 -0
  150. package/src/console/assertions.ts +114 -0
  151. package/src/console/cliui.ts +756 -0
  152. package/src/console/decorators.ts +199 -0
  153. package/src/console/index.ts +67 -0
  154. package/src/console/loaders.ts +145 -0
  155. package/src/console/parser.ts +598 -0
  156. package/src/console/prompts.ts +556 -0
  157. package/src/console/tracing.ts +22 -0
  158. package/src/console/types.ts +280 -0
  159. package/src/console/ui.ts +37 -0
  160. package/src/console/utils.ts +69 -0
  161. package/src/container/Container.ts +55 -13
  162. package/src/container/types.ts +15 -2
  163. package/src/decorators/Service.ts +28 -3
  164. package/src/errors/ReamError.ts +31 -0
  165. package/src/errors/prettyPrintError.ts +20 -0
  166. package/src/index.ts +30 -4
  167. package/src/middleware/Pipeline.ts +76 -5
  168. package/src/rpc/RpcRouter.ts +16 -2
  169. package/src/services/app.ts +1 -1
  170. package/src/services/console.ts +42 -0
  171. package/src/testing/ApiResponse.ts +691 -0
  172. package/src/testing/RequestBuilder.ts +498 -275
  173. package/src/testing/TestClient.ts +63 -86
  174. package/src/utils/Macroable.ts +3 -3
  175. package/dist/console/CommandRunner.d.ts +0 -18
  176. package/dist/console/CommandRunner.d.ts.map +0 -1
  177. package/dist/console/CommandRunner.js +0 -65
  178. package/dist/console/CommandRunner.js.map +0 -1
  179. 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 type { Command } from './console/CommandRunner.js'
173
- export { CommandRunner } from './console/CommandRunner.js'
174
- export type { AppEnvironment, HyperServerLike, IgnitorConfig, ReamrcConfig } from './Ignitor.js'
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. A `@c9up/rune` schema matches this
25
- * shape, so ream stays decoupled from the validation engine — any object with a
26
- * `validate(data)` returning `{ valid, errors, data? }` works.
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): { valid: boolean; errors: unknown[]; 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.validate(ctx.request.body())
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
  }
@@ -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
- const outcome = validator.validate(params)
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
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Usage:
5
5
  * import app from '@c9up/ream/services/app'
6
- * const logger = app.container.make('logger')
6
+ * const logger = await app.container.make('logger')
7
7
  * if (app.inProduction) { ... }
8
8
  */
9
9
 
@@ -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