@velajs/vela 1.17.1 → 1.18.0

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.
@@ -65,7 +65,7 @@ export class ArgumentResolver {
65
65
  const metadata = {
66
66
  type: param.type,
67
67
  data: param.name,
68
- metatype: paramTypes?.[param.index]
68
+ metatype: param.metatype ?? paramTypes?.[param.index]
69
69
  };
70
70
  for (const pipe of pipes){
71
71
  value = await pipe.transform(value, metadata);
@@ -0,0 +1,16 @@
1
+ import type { Context } from 'hono';
2
+ import type { Container } from '../container/container';
3
+ /**
4
+ * Returns the request-scoped child container for the current request.
5
+ *
6
+ * `@Inject(Container)` resolves the ROOT container (request children share the
7
+ * provider map and never rebind `Container`), so module authors who need
8
+ * request-scoped resolution from inside a handler, param-decorator factory, or
9
+ * scoped middleware must read the child seeded by RouteManager instead. The
10
+ * child is created before guards, pipes, params, and handlers run, so it is
11
+ * always present on the Vela request path.
12
+ *
13
+ * Throws outside a Vela-managed request rather than materializing an orphan
14
+ * child (mirrors the REQUEST_CONTEXT fail-fast).
15
+ */
16
+ export declare function getRequestContainer(c: Context): Container;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Returns the request-scoped child container for the current request.
3
+ *
4
+ * `@Inject(Container)` resolves the ROOT container (request children share the
5
+ * provider map and never rebind `Container`), so module authors who need
6
+ * request-scoped resolution from inside a handler, param-decorator factory, or
7
+ * scoped middleware must read the child seeded by RouteManager instead. The
8
+ * child is created before guards, pipes, params, and handlers run, so it is
9
+ * always present on the Vela request path.
10
+ *
11
+ * Throws outside a Vela-managed request rather than materializing an orphan
12
+ * child (mirrors the REQUEST_CONTEXT fail-fast).
13
+ */ export function getRequestContainer(c) {
14
+ const container = c.get('container');
15
+ if (!container) {
16
+ throw new Error('getRequestContainer(c) can only be called inside a Vela-managed request — ' + 'the request child container is seeded by RouteManager when the request enters the pipeline.');
17
+ }
18
+ return container;
19
+ }
@@ -405,7 +405,7 @@ export class RouteManager {
405
405
  // `await import(variable)` as a runtime import Cloudflare Workers cannot
406
406
  // resolve.
407
407
  const contributors = getRouteContributors();
408
- for (const { controller, metadata } of this.controllers){
408
+ for (const { controller, metadata, routes } of this.controllers){
409
409
  for (const contributor of contributors){
410
410
  const meta = getMetadata(contributor.claimsMetaKey, controller);
411
411
  if (meta === undefined) continue;
@@ -419,10 +419,11 @@ export class RouteManager {
419
419
  joinPaths
420
420
  });
421
421
  }
422
- // DX guard for the common mistake: @Crud() metadata present but the
423
- // contributor package never imported.
424
- if (getMetadata('vela:crud', controller) !== undefined && !contributors.some((c)=>c.claimsMetaKey === 'vela:crud')) {
425
- throw new Error("@Crud() requires '@velajs/crud'. Install it: pnpm add @velajs/crud");
422
+ // DX warning for stale setups: @Crud() metadata but nothing produced a
423
+ // route native @velajs/crud (>=1.18) stamps real routes at decoration
424
+ // time, and legacy bridges register a claiming contributor.
425
+ if (getMetadata('vela:crud', controller) !== undefined && routes.length === 0 && !contributors.some((c)=>c.claimsMetaKey === 'vela:crud')) {
426
+ console.warn(`[vela] ${controller.name} carries @Crud() metadata but produced no routes — ` + "install and import '@velajs/crud' (>=1.18), or remove the decorator.");
426
427
  }
427
428
  }
428
429
  return app;
@@ -23,6 +23,12 @@ export interface ParamMetadata {
23
23
  name?: string;
24
24
  pipes?: PipeType[];
25
25
  factory?: (data: unknown, ctx: import('hono').Context) => unknown;
26
+ /**
27
+ * Explicit param type for programmatic routes. Methods synthesized at
28
+ * runtime (e.g. `@Crud()` verb handlers) have no `design:paramtypes`, so
29
+ * ValidationPipe and the OpenAPI walk read this instead when present.
30
+ */
31
+ metatype?: unknown;
26
32
  }
27
33
  export interface ControllerRegistration {
28
34
  controller: Type;
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export { signUrl, verifySignedUrl } from './crypto/signed-url';
16
16
  export type { SignedUrlOptions } from './crypto/signed-url';
17
17
  export { REQUEST_CONTEXT } from './http/request-context';
18
18
  export type { RequestContext } from './http/request-context';
19
+ export { getRequestContainer } from './http/request-container';
19
20
  export { enableAmbientContainer, getCurrentContainer, getCurrentRequestContext, } from './http/ambient';
20
21
  export { Logger, LogLevel } from './services/index';
21
22
  export type { LoggerService, ContextProvider, Writer, LoggerLevelName } from './services/index';
package/dist/index.js CHANGED
@@ -16,6 +16,9 @@ export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All,
16
16
  export { signUrl, verifySignedUrl } from "./crypto/signed-url.js";
17
17
  // Request-scoped context primitive
18
18
  export { REQUEST_CONTEXT } from "./http/request-context.js";
19
+ // Explicit request-child container access (for programmatic-route authors,
20
+ // param-decorator factories, and scoped middleware)
21
+ export { getRequestContainer } from "./http/request-container.js";
19
22
  // Opt-in ambient container access (ALS via hono/context-storage)
20
23
  export { enableAmbientContainer, getCurrentContainer, getCurrentRequestContext } from "./http/ambient.js";
21
24
  // Services
@@ -39,7 +39,7 @@ function isDtoClass(value) {
39
39
  return typeof value === 'function' && value.schema != null;
40
40
  }
41
41
  function getParamSchema(param, paramtypes, registry) {
42
- const metatype = paramtypes?.[param.index];
42
+ const metatype = param.metatype ?? paramtypes?.[param.index];
43
43
  if (!metatype) return undefined;
44
44
  if (isDtoClass(metatype)) {
45
45
  return registry.ref(metatype);
@@ -51,7 +51,7 @@ function getParamSchema(param, paramtypes, registry) {
51
51
  return undefined;
52
52
  }
53
53
  function isParamOptional(param, paramtypes) {
54
- const metatype = paramtypes?.[param.index];
54
+ const metatype = param.metatype ?? paramtypes?.[param.index];
55
55
  if (metatype?.schema) {
56
56
  return isOptional(metatype.schema);
57
57
  }
@@ -30,6 +30,12 @@ export interface ParameterMetadata {
30
30
  name?: string;
31
31
  pipes?: PipeType[];
32
32
  factory?: (data: unknown, ctx: Context) => unknown;
33
+ /**
34
+ * Explicit param type for programmatic routes. Methods synthesized at
35
+ * runtime (e.g. `@Crud()` verb handlers) have no `design:paramtypes`, so
36
+ * ValidationPipe and the OpenAPI walk read this instead when present.
37
+ */
38
+ metatype?: unknown;
33
39
  }
34
40
  export interface HttpHandlerMeta {
35
41
  httpCode?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velajs/vela",
3
- "version": "1.17.1",
3
+ "version": "1.18.0",
4
4
  "description": "NestJS-compatible framework for edge runtimes, powered by Hono",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",