@velajs/vela 1.14.0 → 1.16.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.
- package/CHANGELOG.md +25 -0
- package/dist/application.d.ts +10 -1
- package/dist/application.js +12 -0
- package/dist/config/config.module.d.ts +8 -1
- package/dist/config/config.module.js +89 -42
- package/dist/config/config.service.d.ts +17 -4
- package/dist/config/config.service.js +18 -20
- package/dist/config/config.store.d.ts +46 -0
- package/dist/config/config.store.js +119 -0
- package/dist/config/config.tokens.d.ts +11 -0
- package/dist/config/config.tokens.js +12 -0
- package/dist/config/config.types.d.ts +37 -1
- package/dist/config/config.types.js +4 -1
- package/dist/config/index.d.ts +5 -2
- package/dist/config/index.js +3 -1
- package/dist/config/register-as.d.ts +52 -0
- package/dist/config/register-as.js +39 -0
- package/dist/container/container.d.ts +8 -1
- package/dist/container/container.js +39 -1
- package/dist/container/index.d.ts +2 -2
- package/dist/container/index.js +1 -1
- package/dist/container/types.d.ts +23 -0
- package/dist/container/types.js +6 -1
- package/dist/{storage → crypto}/signed-url.js +5 -0
- package/dist/factory/bootstrap.js +10 -0
- package/dist/http/decorators.d.ts +18 -9
- package/dist/http/decorators.js +4 -1
- package/dist/http/index.d.ts +4 -0
- package/dist/http/index.js +2 -0
- package/dist/http/route-map.d.ts +30 -0
- package/dist/http/route-map.js +27 -0
- package/dist/http/route.manager.d.ts +24 -0
- package/dist/http/route.manager.js +28 -1
- package/dist/http/types.d.ts +2 -0
- package/dist/http/url/index.d.ts +4 -0
- package/dist/http/url/index.js +3 -0
- package/dist/http/url/signed-url.guard.d.ts +27 -0
- package/dist/http/url/signed-url.guard.js +62 -0
- package/dist/http/url/signing-secret.d.ts +20 -0
- package/dist/http/url/signing-secret.js +24 -0
- package/dist/http/url/url-generator.service.d.ts +52 -0
- package/dist/http/url/url-generator.service.js +104 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.js +5 -3
- package/dist/openapi/document.js +2 -1
- package/dist/registry/types.d.ts +2 -0
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +4 -1
- package/package.json +6 -2
- /package/dist/{storage → crypto}/signed-url.d.ts +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { RouteManager } from '../route.manager';
|
|
2
|
+
import type { RouteName, RouteParams } from '../route-map';
|
|
3
|
+
/** Value accepted for a path param or query entry. */
|
|
4
|
+
type UrlParamValue = string | number | boolean;
|
|
5
|
+
/** Extra options for {@link UrlGeneratorService.urlFor}. */
|
|
6
|
+
export interface UrlForOptions {
|
|
7
|
+
/** Additional query-string entries merged after any leftover params. */
|
|
8
|
+
query?: Record<string, UrlParamValue>;
|
|
9
|
+
}
|
|
10
|
+
/** Options for {@link UrlGeneratorService.signedUrl}. */
|
|
11
|
+
export interface SignedUrlGenerateOptions {
|
|
12
|
+
/** Time-to-live in seconds; enforced on verification via the `expires` param. */
|
|
13
|
+
expiresIn?: number;
|
|
14
|
+
/** Override the signing secret (else the `URL_SIGNING_SECRET` token / `CONFIG_ENV`). */
|
|
15
|
+
secret?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Builds URLs for named routes (Laravel-flavoured `route()` ergonomics).
|
|
19
|
+
*
|
|
20
|
+
* Route descriptions are read LAZILY from the {@link RouteManager} on first use
|
|
21
|
+
* — post-build, so composition (global prefix + version + controller prefix) is
|
|
22
|
+
* already baked into each path — and it never instantiates controllers, so it
|
|
23
|
+
* plays nicely with lazy modules. Registered as an app-level singleton by
|
|
24
|
+
* `bootstrap`, so it is injectable anywhere.
|
|
25
|
+
*/
|
|
26
|
+
export declare class UrlGeneratorService {
|
|
27
|
+
private readonly routeManager;
|
|
28
|
+
private readonly secretToken?;
|
|
29
|
+
private readonly env;
|
|
30
|
+
private routeMap;
|
|
31
|
+
constructor(routeManager: RouteManager, secretToken?: string | undefined, env?: Record<string, unknown>);
|
|
32
|
+
/**
|
|
33
|
+
* Build the path for a named route, filling `:param` placeholders from
|
|
34
|
+
* `params`. Params that don't match a placeholder become query-string
|
|
35
|
+
* entries; `opts.query` is merged after them.
|
|
36
|
+
*
|
|
37
|
+
* @throws if no route carries `name`, or a required `:param` is missing.
|
|
38
|
+
*/
|
|
39
|
+
urlFor<N extends RouteName>(name: N, params?: RouteParams<N>, opts?: UrlForOptions): string;
|
|
40
|
+
/**
|
|
41
|
+
* Build a named-route URL and HMAC-sign it (path + query). The secret comes
|
|
42
|
+
* from `options.secret`, else the {@link URL_SIGNING_SECRET} token, else
|
|
43
|
+
* `CONFIG_ENV`; a descriptive error is thrown when none is available.
|
|
44
|
+
*/
|
|
45
|
+
signedUrl<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUrlGenerateOptions): Promise<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Lazily index named route descriptions. Rebuilt while empty (routes may not
|
|
48
|
+
* be built yet), cached once populated.
|
|
49
|
+
*/
|
|
50
|
+
private routes;
|
|
51
|
+
}
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
}
|
|
7
|
+
function _ts_metadata(k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
}
|
|
10
|
+
function _ts_param(paramIndex, decorator) {
|
|
11
|
+
return function(target, key) {
|
|
12
|
+
decorator(target, key, paramIndex);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
import { Injectable, Inject, Optional } from "../../container/decorators.js";
|
|
16
|
+
import { CONFIG_ENV } from "../../config/config.tokens.js";
|
|
17
|
+
import { signUrl } from "../../crypto/signed-url.js";
|
|
18
|
+
import { RouteManager } from "../route.manager.js";
|
|
19
|
+
import { URL_SIGNING_SECRET, resolveSigningSecret } from "./signing-secret.js";
|
|
20
|
+
export class UrlGeneratorService {
|
|
21
|
+
routeManager;
|
|
22
|
+
secretToken;
|
|
23
|
+
env;
|
|
24
|
+
routeMap = null;
|
|
25
|
+
constructor(routeManager, secretToken, env = {}){
|
|
26
|
+
this.routeManager = routeManager;
|
|
27
|
+
this.secretToken = secretToken;
|
|
28
|
+
this.env = env;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build the path for a named route, filling `:param` placeholders from
|
|
32
|
+
* `params`. Params that don't match a placeholder become query-string
|
|
33
|
+
* entries; `opts.query` is merged after them.
|
|
34
|
+
*
|
|
35
|
+
* @throws if no route carries `name`, or a required `:param` is missing.
|
|
36
|
+
*/ urlFor(name, params, opts) {
|
|
37
|
+
const description = this.routes().get(name);
|
|
38
|
+
if (!description) {
|
|
39
|
+
throw new Error(`No route named "${String(name)}" was found. Give the route a name ` + `via \`@Get(path, { name: '${String(name)}' })\`.`);
|
|
40
|
+
}
|
|
41
|
+
const provided = {
|
|
42
|
+
...params ?? {}
|
|
43
|
+
};
|
|
44
|
+
const consumed = new Set();
|
|
45
|
+
const path = description.path.replace(/:([A-Za-z0-9_]+)/g, (_match, key)=>{
|
|
46
|
+
const value = provided[key];
|
|
47
|
+
if (value === undefined || value === null) {
|
|
48
|
+
throw new Error(`Missing route param "${key}" for route "${String(name)}".`);
|
|
49
|
+
}
|
|
50
|
+
consumed.add(key);
|
|
51
|
+
return encodeURIComponent(String(value));
|
|
52
|
+
});
|
|
53
|
+
const query = new URLSearchParams();
|
|
54
|
+
for (const [key, value] of Object.entries(provided)){
|
|
55
|
+
if (consumed.has(key) || value === undefined || value === null) continue;
|
|
56
|
+
query.set(key, String(value));
|
|
57
|
+
}
|
|
58
|
+
for (const [key, value] of Object.entries(opts?.query ?? {})){
|
|
59
|
+
if (value === undefined || value === null) continue;
|
|
60
|
+
query.set(key, String(value));
|
|
61
|
+
}
|
|
62
|
+
const qs = query.toString();
|
|
63
|
+
return qs ? `${path}?${qs}` : path;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build a named-route URL and HMAC-sign it (path + query). The secret comes
|
|
67
|
+
* from `options.secret`, else the {@link URL_SIGNING_SECRET} token, else
|
|
68
|
+
* `CONFIG_ENV`; a descriptive error is thrown when none is available.
|
|
69
|
+
*/ async signedUrl(name, params, options = {}) {
|
|
70
|
+
const url = this.urlFor(name, params);
|
|
71
|
+
const secret = resolveSigningSecret(options.secret, this.secretToken, this.env);
|
|
72
|
+
return signUrl(url, secret, options.expiresIn !== undefined ? {
|
|
73
|
+
expiresIn: options.expiresIn
|
|
74
|
+
} : undefined);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Lazily index named route descriptions. Rebuilt while empty (routes may not
|
|
78
|
+
* be built yet), cached once populated.
|
|
79
|
+
*/ routes() {
|
|
80
|
+
if (this.routeMap && this.routeMap.size > 0) return this.routeMap;
|
|
81
|
+
const map = new Map();
|
|
82
|
+
for (const description of this.routeManager.getRouteDescriptions()){
|
|
83
|
+
if (description.name && !map.has(description.name)) {
|
|
84
|
+
map.set(description.name, description);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.routeMap = map;
|
|
88
|
+
return map;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
UrlGeneratorService = _ts_decorate([
|
|
92
|
+
Injectable(),
|
|
93
|
+
_ts_param(0, Inject(RouteManager)),
|
|
94
|
+
_ts_param(1, Optional()),
|
|
95
|
+
_ts_param(1, Inject(URL_SIGNING_SECRET)),
|
|
96
|
+
_ts_param(2, Optional()),
|
|
97
|
+
_ts_param(2, Inject(CONFIG_ENV)),
|
|
98
|
+
_ts_metadata("design:type", Function),
|
|
99
|
+
_ts_metadata("design:paramtypes", [
|
|
100
|
+
typeof RouteManager === "undefined" ? Object : RouteManager,
|
|
101
|
+
String,
|
|
102
|
+
typeof Record === "undefined" ? Object : Record
|
|
103
|
+
])
|
|
104
|
+
], UrlGeneratorService);
|
package/dist/index.d.ts
CHANGED
|
@@ -6,17 +6,21 @@ export { bootstrap } from './factory/bootstrap';
|
|
|
6
6
|
export type { BootstrapOptions, BootstrapResult } from './factory/bootstrap';
|
|
7
7
|
export { createOpenApiDocument, ApiDoc, ApiTags, ApiResponse, zodToJsonSchema, } from './openapi/index';
|
|
8
8
|
export type { OpenApiDocument, OpenApiInfo, OpenApiOperation, OpenApiParameter, OpenApiPathItem, OpenApiRequestBody, OpenApiResponse, ApiDocMetadata, ApiResponseEntry, ApiResponseOptions, CreateOpenApiDocumentOptions, HttpVerb, JsonSchema, } from './openapi/index';
|
|
9
|
-
export { Container, Injectable, Inject, Optional, InjectionToken, ForwardRef, forwardRef, ModuleRef, ModuleVisibilityError, MultipleProvidersFoundError, ROOT_MODULE_ID, mixin, } from './container/index';
|
|
10
|
-
export type { Type, Token, InferToken, InferTokens, InjectableOptions, ProviderOptions, ModuleScope, ContainerOptions, Diagnostics, } from './container/index';
|
|
9
|
+
export { Container, Injectable, Inject, Optional, InjectionToken, ForwardRef, forwardRef, ModuleRef, ModuleVisibilityError, MultipleProvidersFoundError, ROOT_MODULE_ID, mixin, describeToken, } from './container/index';
|
|
10
|
+
export type { Type, Token, InferToken, InferTokens, InjectableOptions, ProviderOptions, ModuleScope, ModuleDescription, ContainerOptions, Diagnostics, } from './container/index';
|
|
11
|
+
export type { RouteDescription } from './http/route.manager';
|
|
11
12
|
export { METADATA_KEYS, HttpMethod, ParamType, Scope } from './constants';
|
|
12
|
-
export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, createLazyParamDecorator, applyDecorators, } from './http/index';
|
|
13
|
+
export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, createLazyParamDecorator, applyDecorators, UrlGeneratorService, SignedUrlGuard, SignedUrl, URL_SIGNING_SECRET, } from './http/index';
|
|
14
|
+
export type { RouteOptions, UrlForOptions, SignedUrlGenerateOptions, VelaRouteMap, RouteName, RouteParams, } from './http/index';
|
|
15
|
+
export { signUrl, verifySignedUrl } from './crypto/signed-url';
|
|
16
|
+
export type { SignedUrlOptions } from './crypto/signed-url';
|
|
13
17
|
export { REQUEST_CONTEXT } from './http/request-context';
|
|
14
18
|
export type { RequestContext } from './http/request-context';
|
|
15
19
|
export { enableAmbientContainer, getCurrentContainer, getCurrentRequestContext, } from './http/ambient';
|
|
16
20
|
export { Logger, LogLevel } from './services/index';
|
|
17
21
|
export type { LoggerService, ContextProvider, Writer, LoggerLevelName } from './services/index';
|
|
18
|
-
export { ConfigModule, ConfigService, CONFIG_OPTIONS } from './config/index';
|
|
19
|
-
export type { ConfigModuleOptions } from './config/index';
|
|
22
|
+
export { ConfigModule, ConfigService, ConfigStore, CONFIG_OPTIONS, CONFIG_ENV, registerAs, } from './config/index';
|
|
23
|
+
export type { ConfigModuleOptions, ConfigSchema, ConfigNamespace, AnyConfigNamespace, InferConfigType, ConfigType, ConfigPath, ConfigPathValue, } from './config/index';
|
|
20
24
|
export { HttpModule, HttpService, HTTP_MODULE_OPTIONS, HttpRequestException } from './fetch/index';
|
|
21
25
|
export type { HttpModuleOptions, HttpResponse, HttpRequestConfig } from './fetch/index';
|
|
22
26
|
export { CorsModule, CORS_OPTIONS } from './cors/index';
|
package/dist/index.js
CHANGED
|
@@ -7,11 +7,13 @@ export { bootstrap } from "./factory/bootstrap.js";
|
|
|
7
7
|
// OpenAPI
|
|
8
8
|
export { createOpenApiDocument, ApiDoc, ApiTags, ApiResponse, zodToJsonSchema } from "./openapi/index.js";
|
|
9
9
|
// DI Container
|
|
10
|
-
export { Container, Injectable, Inject, Optional, InjectionToken, ForwardRef, forwardRef, ModuleRef, ModuleVisibilityError, MultipleProvidersFoundError, ROOT_MODULE_ID, mixin } from "./container/index.js";
|
|
10
|
+
export { Container, Injectable, Inject, Optional, InjectionToken, ForwardRef, forwardRef, ModuleRef, ModuleVisibilityError, MultipleProvidersFoundError, ROOT_MODULE_ID, mixin, describeToken } from "./container/index.js";
|
|
11
11
|
// Constants
|
|
12
12
|
export { METADATA_KEYS, HttpMethod, ParamType, Scope } from "./constants.js";
|
|
13
13
|
// HTTP Decorators
|
|
14
|
-
export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, createLazyParamDecorator, applyDecorators } from "./http/index.js";
|
|
14
|
+
export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, createLazyParamDecorator, applyDecorators, UrlGeneratorService, SignedUrlGuard, SignedUrl, URL_SIGNING_SECRET } from "./http/index.js";
|
|
15
|
+
// Edge-safe HMAC signed-URL primitives (also re-exported from `@velajs/vela/storage`)
|
|
16
|
+
export { signUrl, verifySignedUrl } from "./crypto/signed-url.js";
|
|
15
17
|
// Request-scoped context primitive
|
|
16
18
|
export { REQUEST_CONTEXT } from "./http/request-context.js";
|
|
17
19
|
// Opt-in ambient container access (ALS via hono/context-storage)
|
|
@@ -19,7 +21,7 @@ export { enableAmbientContainer, getCurrentContainer, getCurrentRequestContext }
|
|
|
19
21
|
// Services
|
|
20
22
|
export { Logger, LogLevel } from "./services/index.js";
|
|
21
23
|
// Config
|
|
22
|
-
export { ConfigModule, ConfigService, CONFIG_OPTIONS } from "./config/index.js";
|
|
24
|
+
export { ConfigModule, ConfigService, ConfigStore, CONFIG_OPTIONS, CONFIG_ENV, registerAs } from "./config/index.js";
|
|
23
25
|
// HTTP Client
|
|
24
26
|
export { HttpModule, HttpService, HTTP_MODULE_OPTIONS, HttpRequestException } from "./fetch/index.js";
|
|
25
27
|
// CORS
|
package/dist/openapi/document.js
CHANGED
|
@@ -182,7 +182,8 @@ function buildOperation(controller, route, pathString, registry) {
|
|
|
182
182
|
if (requestBody) operation.requestBody = requestBody;
|
|
183
183
|
if (docMeta?.summary) operation.summary = docMeta.summary;
|
|
184
184
|
if (docMeta?.description) operation.description = docMeta.description;
|
|
185
|
-
|
|
185
|
+
const operationId = docMeta?.operationId ?? route.name;
|
|
186
|
+
if (operationId) operation.operationId = operationId;
|
|
186
187
|
if (docMeta?.deprecated) operation.deprecated = docMeta.deprecated;
|
|
187
188
|
if (mergedTags.length > 0) operation.tags = mergedTags;
|
|
188
189
|
return operation;
|
package/dist/registry/types.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export interface RouteDefinition {
|
|
|
21
21
|
path: string;
|
|
22
22
|
handlerName: string | symbol;
|
|
23
23
|
version?: number | number[];
|
|
24
|
+
/** Route name for URL generation / OpenAPI operationId (`@Get(path, { name })`). */
|
|
25
|
+
name?: string;
|
|
24
26
|
}
|
|
25
27
|
export interface ParameterMetadata {
|
|
26
28
|
index: number;
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { signUrl, verifySignedUrl } from '
|
|
2
|
-
export type { SignedUrlOptions } from '
|
|
1
|
+
export { signUrl, verifySignedUrl } from '../crypto/signed-url';
|
|
2
|
+
export type { SignedUrlOptions } from '../crypto/signed-url';
|
|
3
3
|
export { expandPathTemplate, joinStoragePath } from './path-template';
|
|
4
4
|
export type { StorageBody, StorageDriver, PresignMethod, UploadOptions, UploadResult, DownloadResult, PresignedUrlResult, } from './storage.types';
|
package/dist/storage/index.js
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// The HMAC signed-URL util now lives in `src/crypto/` (core consumes it there
|
|
2
|
+
// for the URL generator + guard). Re-exported here so `@velajs/vela/storage`'s
|
|
3
|
+
// public API is unchanged for existing consumers.
|
|
4
|
+
export { signUrl, verifySignedUrl } from "../crypto/signed-url.js";
|
|
2
5
|
export { expandPathTemplate, joinStoragePath } from "./path-template.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velajs/vela",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "NestJS-compatible framework for edge runtimes, powered by Hono",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -102,6 +102,7 @@
|
|
|
102
102
|
"@vitest/runner": "^4.1.9",
|
|
103
103
|
"@vitest/snapshot": "^4.1.9",
|
|
104
104
|
"intl-messageformat": "^11.2.9",
|
|
105
|
+
"typedoc": "~0.28.19",
|
|
105
106
|
"typescript": "^6.0.3",
|
|
106
107
|
"unplugin-swc": "^1.5.9",
|
|
107
108
|
"vitest": "^4.1.9",
|
|
@@ -112,6 +113,9 @@
|
|
|
112
113
|
"test": "vitest run",
|
|
113
114
|
"test:workers": "vitest run --config vitest.config.workers.ts",
|
|
114
115
|
"test:workers:als": "vitest run --config vitest.config.workers-als.ts",
|
|
115
|
-
"typecheck": "tsc --noEmit"
|
|
116
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.type-tests.json",
|
|
117
|
+
"check:skill": "node scripts/check-skill.mjs",
|
|
118
|
+
"docs": "typedoc",
|
|
119
|
+
"docs:check": "typedoc --emit none"
|
|
116
120
|
}
|
|
117
121
|
}
|
|
File without changes
|