@velajs/vela 1.8.8 → 1.10.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 +20 -0
- package/dist/__tests__/workers-als/entry-als.d.ts +9 -0
- package/dist/application.d.ts +10 -0
- package/dist/application.js +25 -0
- package/dist/cache/cache.module.d.ts +5 -7
- package/dist/cache/cache.module.js +44 -66
- package/dist/cache/cache.types.d.ts +26 -0
- package/dist/cache/cache.types.js +1 -1
- package/dist/cache/index.d.ts +2 -1
- package/dist/cache/index.js +1 -0
- package/dist/cache/tiered-cache.store.d.ts +19 -0
- package/dist/cache/tiered-cache.store.js +40 -0
- package/dist/config/config.module.d.ts +6 -5
- package/dist/config/config.module.js +46 -49
- package/dist/container/container.d.ts +33 -0
- package/dist/container/container.js +156 -7
- package/dist/container/disposable.d.ts +5 -0
- package/dist/container/disposable.js +33 -0
- package/dist/container/types.d.ts +8 -0
- package/dist/factory/bootstrap.js +10 -0
- package/dist/fetch/fetch.module.d.ts +5 -6
- package/dist/fetch/fetch.module.js +9 -42
- package/dist/http/ambient.d.ts +17 -0
- package/dist/http/ambient.js +44 -0
- package/dist/http/execution-context.js +4 -1
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +1 -0
- package/dist/http/route.manager.d.ts +19 -0
- package/dist/http/route.manager.js +84 -0
- package/dist/i18n/deep-merge.d.ts +2 -0
- package/dist/i18n/deep-merge.js +15 -0
- package/dist/i18n/i18n.middleware.d.ts +15 -0
- package/dist/i18n/i18n.middleware.js +94 -0
- package/dist/i18n/i18n.module.d.ts +13 -0
- package/dist/i18n/i18n.module.js +61 -0
- package/dist/i18n/i18n.options.d.ts +30 -0
- package/dist/i18n/i18n.options.js +16 -0
- package/dist/i18n/i18n.service.d.ts +20 -0
- package/dist/i18n/i18n.service.js +49 -0
- package/dist/i18n/i18n.tokens.d.ts +6 -0
- package/dist/i18n/i18n.tokens.js +3 -0
- package/dist/i18n/i18n.types.d.ts +6 -0
- package/dist/i18n/i18n.types.js +1 -0
- package/dist/i18n/index.d.ts +10 -0
- package/dist/i18n/index.js +8 -0
- package/dist/i18n/message-loader.service.d.ts +21 -0
- package/dist/i18n/message-loader.service.js +90 -0
- package/dist/i18n/message-registry.d.ts +16 -0
- package/dist/i18n/message-registry.js +49 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +6 -2
- package/dist/module/configurable-module.builder.d.ts +44 -0
- package/dist/module/configurable-module.builder.js +177 -0
- package/dist/module/configurable-module.types.d.ts +93 -0
- package/dist/module/configurable-module.types.js +5 -0
- package/dist/module/index.d.ts +2 -0
- package/dist/module/index.js +1 -0
- package/dist/openapi/document.js +20 -2
- package/dist/openapi/types.d.ts +54 -0
- package/dist/pipeline/types.d.ts +21 -4
- package/dist/registry/metadata.registry.d.ts +16 -16
- package/dist/registry/metadata.registry.js +90 -32
- package/dist/seeder/index.d.ts +5 -0
- package/dist/seeder/index.js +4 -0
- package/dist/seeder/seeder.decorator.d.ts +7 -0
- package/dist/seeder/seeder.decorator.js +15 -0
- package/dist/seeder/seeder.module.d.ts +18 -0
- package/dist/seeder/seeder.module.js +40 -0
- package/dist/seeder/seeder.registry.d.ts +23 -0
- package/dist/seeder/seeder.registry.js +83 -0
- package/dist/seeder/seeder.tokens.d.ts +2 -0
- package/dist/seeder/seeder.tokens.js +1 -0
- package/dist/seeder/seeder.types.d.ts +20 -0
- package/dist/seeder/seeder.types.js +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/path-template.d.ts +9 -0
- package/dist/storage/path-template.js +20 -0
- package/dist/storage/signed-url.d.ts +12 -0
- package/dist/storage/signed-url.js +55 -0
- package/dist/storage/storage.types.d.ts +41 -0
- package/dist/storage/storage.types.js +5 -0
- package/dist/throttler/throttler.module.d.ts +5 -8
- package/dist/throttler/throttler.module.js +27 -55
- package/dist/websocket/index.d.ts +12 -0
- package/dist/websocket/index.js +16 -0
- package/dist/websocket/websocket.decorators.d.ts +33 -0
- package/dist/websocket/websocket.decorators.js +58 -0
- package/dist/websocket/websocket.module.d.ts +18 -0
- package/dist/websocket/websocket.module.js +52 -0
- package/dist/websocket/websocket.tokens.d.ts +22 -0
- package/dist/websocket/websocket.tokens.js +20 -0
- package/dist/websocket/websocket.types.d.ts +86 -0
- package/dist/websocket/websocket.types.js +4 -0
- package/dist/websocket/ws-argument-resolver.d.ts +13 -0
- package/dist/websocket/ws-argument-resolver.js +40 -0
- package/dist/websocket/ws-dispatcher.d.ts +33 -0
- package/dist/websocket/ws-dispatcher.js +253 -0
- package/dist/websocket/ws-exception.d.ts +16 -0
- package/dist/websocket/ws-exception.js +32 -0
- package/dist/websocket/ws-execution-context.d.ts +9 -0
- package/dist/websocket/ws-execution-context.js +24 -0
- package/dist/websocket/ws-server.d.ts +31 -0
- package/dist/websocket/ws-server.js +74 -0
- package/dist/websocket/ws-sync.d.ts +47 -0
- package/dist/websocket/ws-sync.js +74 -0
- package/dist/websocket-node/index.d.ts +4 -0
- package/dist/websocket-node/index.js +5 -0
- package/dist/websocket-node/node-ws-client.d.ts +24 -0
- package/dist/websocket-node/node-ws-client.js +49 -0
- package/dist/websocket-node/redis-sync.d.ts +33 -0
- package/dist/websocket-node/redis-sync.js +56 -0
- package/dist/websocket-node/register-gateways.d.ts +20 -0
- package/dist/websocket-node/register-gateways.js +61 -0
- package/package.json +31 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Context, Next } from 'hono';
|
|
2
|
+
import type { NestMiddleware } from '../pipeline/types';
|
|
3
|
+
import { type I18nModuleOptions } from './i18n.options';
|
|
4
|
+
/**
|
|
5
|
+
* Detects the request locale and stashes it on the per-request RequestContext
|
|
6
|
+
* bag under {@link I18N_LOCALE_KEY}, where {@link I18nService} reads it.
|
|
7
|
+
* Registered globally via APP_MIDDLEWARE by {@link I18nModule}. Holds no
|
|
8
|
+
* per-request state (reads the RequestContext off the request container each
|
|
9
|
+
* call), so a singleton instance is safe.
|
|
10
|
+
*/
|
|
11
|
+
export declare class I18nLocaleMiddleware implements NestMiddleware {
|
|
12
|
+
private readonly resolved;
|
|
13
|
+
constructor(options: I18nModuleOptions);
|
|
14
|
+
use(c: Context, next: Next): Promise<Response | void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
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 { Inject, Injectable } from "../container/decorators.js";
|
|
16
|
+
import { REQUEST_CONTEXT } from "../http/request-context.js";
|
|
17
|
+
import { resolveI18nOptions } from "./i18n.options.js";
|
|
18
|
+
import { I18N_LOCALE_KEY, I18N_OPTIONS } from "./i18n.tokens.js";
|
|
19
|
+
export class I18nLocaleMiddleware {
|
|
20
|
+
resolved;
|
|
21
|
+
constructor(options){
|
|
22
|
+
this.resolved = resolveI18nOptions(options);
|
|
23
|
+
}
|
|
24
|
+
async use(c, next) {
|
|
25
|
+
const container = c.get('container');
|
|
26
|
+
if (container) {
|
|
27
|
+
const ctx = container.resolve(REQUEST_CONTEXT);
|
|
28
|
+
ctx.set(I18N_LOCALE_KEY, detectLocale(c, this.resolved));
|
|
29
|
+
}
|
|
30
|
+
return next();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
I18nLocaleMiddleware = _ts_decorate([
|
|
34
|
+
Injectable(),
|
|
35
|
+
_ts_param(0, Inject(I18N_OPTIONS)),
|
|
36
|
+
_ts_metadata("design:type", Function),
|
|
37
|
+
_ts_metadata("design:paramtypes", [
|
|
38
|
+
typeof I18nModuleOptions === "undefined" ? Object : I18nModuleOptions
|
|
39
|
+
])
|
|
40
|
+
], I18nLocaleMiddleware);
|
|
41
|
+
function detectLocale(c, resolved) {
|
|
42
|
+
if (!resolved.detection.enabled) return resolved.defaultLocale;
|
|
43
|
+
const { strategy, lookupKey } = resolved.detection;
|
|
44
|
+
// Candidate tags in preference order.
|
|
45
|
+
const candidates = strategy === 'query' ? [
|
|
46
|
+
new URL(c.req.url).searchParams.get(lookupKey) ?? ''
|
|
47
|
+
] : strategy === 'cookie' ? [
|
|
48
|
+
readCookie(c.req.raw.headers.get('cookie'), lookupKey) ?? ''
|
|
49
|
+
] : parseAcceptLanguage(c.req.raw.headers.get('accept-language'));
|
|
50
|
+
for (const candidate of candidates){
|
|
51
|
+
const match = matchLocale(candidate, resolved.locales);
|
|
52
|
+
if (match) return match;
|
|
53
|
+
}
|
|
54
|
+
return resolved.defaultLocale;
|
|
55
|
+
}
|
|
56
|
+
/** Case-insensitive locale match with region fallback (en-US -> en); returns the configured casing. */ function matchLocale(candidate, locales) {
|
|
57
|
+
if (!candidate) return undefined;
|
|
58
|
+
const lc = candidate.toLowerCase();
|
|
59
|
+
const exact = locales.find((l)=>l.toLowerCase() === lc);
|
|
60
|
+
if (exact) return exact;
|
|
61
|
+
const base = lc.split('-')[0];
|
|
62
|
+
return locales.find((l)=>l.toLowerCase().split('-')[0] === base);
|
|
63
|
+
}
|
|
64
|
+
/** Parse Accept-Language into tags ordered by descending q-value (RFC 7231). */ function parseAcceptLanguage(header) {
|
|
65
|
+
if (!header) return [];
|
|
66
|
+
return header.split(',').map((part)=>{
|
|
67
|
+
const [tag, ...params] = part.trim().split(';');
|
|
68
|
+
let q = 1;
|
|
69
|
+
for (const p of params){
|
|
70
|
+
const m = p.trim().match(/^q=([\d.]+)$/);
|
|
71
|
+
if (m) q = Number.parseFloat(m[1]);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
tag: (tag ?? '').trim(),
|
|
75
|
+
q: Number.isNaN(q) ? 0 : q
|
|
76
|
+
};
|
|
77
|
+
}).filter((e)=>e.tag && e.tag !== '*').sort((a, b)=>b.q - a.q).map((e)=>e.tag);
|
|
78
|
+
}
|
|
79
|
+
function readCookie(header, name) {
|
|
80
|
+
if (!header) return undefined;
|
|
81
|
+
for (const part of header.split(';')){
|
|
82
|
+
const [rawKey, ...rest] = part.split('=');
|
|
83
|
+
if (rawKey?.trim() === name) {
|
|
84
|
+
const raw = rest.join('=').trim();
|
|
85
|
+
try {
|
|
86
|
+
return decodeURIComponent(raw);
|
|
87
|
+
} catch {
|
|
88
|
+
// Malformed percent-encoding must not crash locale detection.
|
|
89
|
+
return raw;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DynamicModule } from '../module/types';
|
|
2
|
+
import type { I18nModuleOptions } from './i18n.options';
|
|
3
|
+
declare const ConfigurableModuleClass: import("..").ConfigurableModuleClassType<I18nModuleOptions, "forRoot", "create", {
|
|
4
|
+
isGlobal?: boolean;
|
|
5
|
+
}>;
|
|
6
|
+
export declare class I18nModule extends ConfigurableModuleClass {
|
|
7
|
+
/**
|
|
8
|
+
* forFeature-style: contribute a message tree (`{ [locale]: { ...messages } }`).
|
|
9
|
+
* Contributions are collected statically at module-load and deep-merged.
|
|
10
|
+
*/
|
|
11
|
+
static registerMessages(messages: Record<string, Record<string, unknown>>): DynamicModule;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
import { Module } from "../module/decorators.js";
|
|
8
|
+
import { ConfigurableModuleBuilder } from "../module/configurable-module.builder.js";
|
|
9
|
+
import { stableHash } from "../module/stable-hash.js";
|
|
10
|
+
import { APP_MIDDLEWARE } from "../pipeline/tokens.js";
|
|
11
|
+
import { I18nLocaleMiddleware } from "./i18n.middleware.js";
|
|
12
|
+
import { I18nService } from "./i18n.service.js";
|
|
13
|
+
import { I18N_OPTIONS } from "./i18n.tokens.js";
|
|
14
|
+
import { MessageLoaderService } from "./message-loader.service.js";
|
|
15
|
+
import { MessageRegistry } from "./message-registry.js";
|
|
16
|
+
const { ConfigurableModuleClass } = new ConfigurableModuleBuilder({
|
|
17
|
+
moduleName: 'I18n',
|
|
18
|
+
optionsInjectionToken: I18N_OPTIONS
|
|
19
|
+
}).build();
|
|
20
|
+
// Empty marker module for `registerMessages`. The contribution is a side-effect
|
|
21
|
+
// on the global MessageRegistry; this carries NO providers so it never
|
|
22
|
+
// duplicates I18nModule's providers (which would trip vela's multi-instance
|
|
23
|
+
// encapsulation → MultipleProvidersFoundError).
|
|
24
|
+
let I18nMessagesModule = class I18nMessagesModule {
|
|
25
|
+
};
|
|
26
|
+
I18nMessagesModule = _ts_decorate([
|
|
27
|
+
Module({})
|
|
28
|
+
], I18nMessagesModule);
|
|
29
|
+
export class I18nModule extends ConfigurableModuleClass {
|
|
30
|
+
/**
|
|
31
|
+
* forFeature-style: contribute a message tree (`{ [locale]: { ...messages } }`).
|
|
32
|
+
* Contributions are collected statically at module-load and deep-merged.
|
|
33
|
+
*/ static registerMessages(messages) {
|
|
34
|
+
MessageRegistry.addMessages(messages);
|
|
35
|
+
return {
|
|
36
|
+
module: I18nMessagesModule,
|
|
37
|
+
key: `messages:${stableHash(messages)}`,
|
|
38
|
+
providers: []
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
I18nModule = _ts_decorate([
|
|
43
|
+
Module({
|
|
44
|
+
providers: [
|
|
45
|
+
MessageRegistry,
|
|
46
|
+
MessageLoaderService,
|
|
47
|
+
I18nService,
|
|
48
|
+
I18nLocaleMiddleware,
|
|
49
|
+
// Register the locale middleware globally (NestJS APP_MIDDLEWARE convention).
|
|
50
|
+
{
|
|
51
|
+
provide: APP_MIDDLEWARE,
|
|
52
|
+
useExisting: I18nLocaleMiddleware
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
exports: [
|
|
56
|
+
I18nService,
|
|
57
|
+
MessageLoaderService,
|
|
58
|
+
I18N_OPTIONS
|
|
59
|
+
]
|
|
60
|
+
})
|
|
61
|
+
], I18nModule);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** How the request locale is detected. */
|
|
2
|
+
export type DetectionStrategy = 'header' | 'query' | 'cookie';
|
|
3
|
+
export interface I18nModuleOptions {
|
|
4
|
+
/** Default locale. @default 'en' */
|
|
5
|
+
defaultLocale?: string;
|
|
6
|
+
/** Fallback when a translation is missing. @default defaultLocale */
|
|
7
|
+
fallbackLocale?: string;
|
|
8
|
+
/** Supported locales; request locales outside this list fall back to default. @default ['en'] */
|
|
9
|
+
locales?: string[];
|
|
10
|
+
/** Locale detection config. */
|
|
11
|
+
detection?: {
|
|
12
|
+
/** Set false to disable detection (always use defaultLocale). @default true */
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
/** @default 'header' (Accept-Language) */
|
|
15
|
+
strategy?: DetectionStrategy;
|
|
16
|
+
/** Cookie/query parameter name. @default 'locale' */
|
|
17
|
+
lookupKey?: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface ResolvedI18nOptions {
|
|
21
|
+
defaultLocale: string;
|
|
22
|
+
fallbackLocale: string;
|
|
23
|
+
locales: string[];
|
|
24
|
+
detection: {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
strategy: DetectionStrategy;
|
|
27
|
+
lookupKey: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function resolveI18nOptions(options?: I18nModuleOptions): ResolvedI18nOptions;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** How the request locale is detected. */ export function resolveI18nOptions(options) {
|
|
2
|
+
const detection = options?.detection;
|
|
3
|
+
const defaultLocale = options?.defaultLocale ?? 'en';
|
|
4
|
+
return {
|
|
5
|
+
defaultLocale,
|
|
6
|
+
fallbackLocale: options?.fallbackLocale ?? defaultLocale,
|
|
7
|
+
locales: options?.locales ?? [
|
|
8
|
+
'en'
|
|
9
|
+
],
|
|
10
|
+
detection: {
|
|
11
|
+
enabled: detection?.enabled !== false,
|
|
12
|
+
strategy: detection?.strategy ?? 'header',
|
|
13
|
+
lookupKey: detection?.lookupKey ?? 'locale'
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type RequestContext } from '../http/request-context';
|
|
2
|
+
import type { I18nModuleOptions } from './i18n.options';
|
|
3
|
+
import type { II18nService } from './i18n.types';
|
|
4
|
+
import { MessageLoaderService } from './message-loader.service';
|
|
5
|
+
/**
|
|
6
|
+
* Request-scoped translation facade. Reads the locale resolved by
|
|
7
|
+
* {@link I18nLocaleMiddleware} from the per-request RequestContext.
|
|
8
|
+
*
|
|
9
|
+
* Injecting it into a controller/service is safe: vela's request-scope bubbling
|
|
10
|
+
* promotes the consumer to request scope automatically, so no captive-dependency
|
|
11
|
+
* hazard and no `ambientContainer` flag required.
|
|
12
|
+
*/
|
|
13
|
+
export declare class I18nService implements II18nService {
|
|
14
|
+
private readonly loader;
|
|
15
|
+
private readonly ctx;
|
|
16
|
+
private readonly options;
|
|
17
|
+
constructor(loader: MessageLoaderService, ctx: RequestContext, options: I18nModuleOptions);
|
|
18
|
+
t(key: string, params?: Record<string, unknown>): string;
|
|
19
|
+
getLocale(): string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
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 { Scope } from "../constants.js";
|
|
16
|
+
import { Inject, Injectable } from "../container/decorators.js";
|
|
17
|
+
import { REQUEST_CONTEXT } from "../http/request-context.js";
|
|
18
|
+
import { I18N_LOCALE_KEY, I18N_OPTIONS } from "./i18n.tokens.js";
|
|
19
|
+
import { MessageLoaderService } from "./message-loader.service.js";
|
|
20
|
+
export class I18nService {
|
|
21
|
+
loader;
|
|
22
|
+
ctx;
|
|
23
|
+
options;
|
|
24
|
+
constructor(loader, ctx, options){
|
|
25
|
+
this.loader = loader;
|
|
26
|
+
this.ctx = ctx;
|
|
27
|
+
this.options = options;
|
|
28
|
+
}
|
|
29
|
+
t(key, params) {
|
|
30
|
+
return this.loader.translate(this.getLocale(), key, params);
|
|
31
|
+
}
|
|
32
|
+
getLocale() {
|
|
33
|
+
return this.ctx.get(I18N_LOCALE_KEY) ?? this.options.defaultLocale ?? 'en';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
I18nService = _ts_decorate([
|
|
37
|
+
Injectable({
|
|
38
|
+
scope: Scope.REQUEST
|
|
39
|
+
}),
|
|
40
|
+
_ts_param(0, Inject(MessageLoaderService)),
|
|
41
|
+
_ts_param(1, Inject(REQUEST_CONTEXT)),
|
|
42
|
+
_ts_param(2, Inject(I18N_OPTIONS)),
|
|
43
|
+
_ts_metadata("design:type", Function),
|
|
44
|
+
_ts_metadata("design:paramtypes", [
|
|
45
|
+
typeof MessageLoaderService === "undefined" ? Object : MessageLoaderService,
|
|
46
|
+
typeof RequestContext === "undefined" ? Object : RequestContext,
|
|
47
|
+
typeof I18nModuleOptions === "undefined" ? Object : I18nModuleOptions
|
|
48
|
+
])
|
|
49
|
+
], I18nService);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { InjectionToken } from '../container/types';
|
|
2
|
+
import type { I18nModuleOptions } from './i18n.options';
|
|
3
|
+
/** Options bag from `I18nModule.forRoot()` (the ConfigurableModuleBuilder options token). */
|
|
4
|
+
export declare const I18N_OPTIONS: InjectionToken<I18nModuleOptions>;
|
|
5
|
+
/** Key under which the resolved locale is stashed on the per-request RequestContext bag. */
|
|
6
|
+
export declare const I18N_LOCALE_KEY: unique symbol;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { InjectionToken } from "../container/types.js";
|
|
2
|
+
/** Options bag from `I18nModule.forRoot()` (the ConfigurableModuleBuilder options token). */ export const I18N_OPTIONS = new InjectionToken('I18N_OPTIONS');
|
|
3
|
+
/** Key under which the resolved locale is stashed on the per-request RequestContext bag. */ export const I18N_LOCALE_KEY = Symbol.for('vela:i18n:locale');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { I18nModule } from './i18n.module';
|
|
2
|
+
export { I18nService } from './i18n.service';
|
|
3
|
+
export { MessageLoaderService } from './message-loader.service';
|
|
4
|
+
export { MessageRegistry } from './message-registry';
|
|
5
|
+
export { I18nLocaleMiddleware } from './i18n.middleware';
|
|
6
|
+
export { I18N_OPTIONS, I18N_LOCALE_KEY } from './i18n.tokens';
|
|
7
|
+
export { resolveI18nOptions } from './i18n.options';
|
|
8
|
+
export { deepMerge } from './deep-merge';
|
|
9
|
+
export type { I18nModuleOptions, ResolvedI18nOptions, DetectionStrategy } from './i18n.options';
|
|
10
|
+
export type { II18nService } from './i18n.types';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { I18nModule } from "./i18n.module.js";
|
|
2
|
+
export { I18nService } from "./i18n.service.js";
|
|
3
|
+
export { MessageLoaderService } from "./message-loader.service.js";
|
|
4
|
+
export { MessageRegistry } from "./message-registry.js";
|
|
5
|
+
export { I18nLocaleMiddleware } from "./i18n.middleware.js";
|
|
6
|
+
export { I18N_OPTIONS, I18N_LOCALE_KEY } from "./i18n.tokens.js";
|
|
7
|
+
export { resolveI18nOptions } from "./i18n.options.js";
|
|
8
|
+
export { deepMerge } from "./deep-merge.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { I18nModuleOptions } from './i18n.options';
|
|
2
|
+
import { MessageRegistry } from './message-registry';
|
|
3
|
+
/**
|
|
4
|
+
* Compiles and caches ICU messages (via `intl-messageformat`). Singleton: reads
|
|
5
|
+
* the merged registry once at construction (all `registerMessages` calls run at
|
|
6
|
+
* module-load, before providers are instantiated), flattens each locale to
|
|
7
|
+
* dot-paths, and compiles lazily per locale.
|
|
8
|
+
*/
|
|
9
|
+
export declare class MessageLoaderService {
|
|
10
|
+
private readonly cache;
|
|
11
|
+
private readonly compiledCache;
|
|
12
|
+
private readonly defaultLocale;
|
|
13
|
+
private readonly fallbackLocale;
|
|
14
|
+
constructor(registry: MessageRegistry, options: I18nModuleOptions);
|
|
15
|
+
translate(locale: string, key: string, params?: Record<string, unknown>): string;
|
|
16
|
+
getAvailableLocales(): string[];
|
|
17
|
+
isLocaleSupported(locale: string): boolean;
|
|
18
|
+
getDefaultLocale(): string;
|
|
19
|
+
private getCompiledMessages;
|
|
20
|
+
private flattenMessages;
|
|
21
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
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 IntlMessageFormat from "intl-messageformat";
|
|
16
|
+
import { Inject, Injectable } from "../container/decorators.js";
|
|
17
|
+
import { I18N_OPTIONS } from "./i18n.tokens.js";
|
|
18
|
+
import { MessageRegistry } from "./message-registry.js";
|
|
19
|
+
export class MessageLoaderService {
|
|
20
|
+
cache = new Map();
|
|
21
|
+
compiledCache = new Map();
|
|
22
|
+
defaultLocale;
|
|
23
|
+
fallbackLocale;
|
|
24
|
+
constructor(registry, options){
|
|
25
|
+
this.defaultLocale = options?.defaultLocale ?? 'en';
|
|
26
|
+
this.fallbackLocale = options?.fallbackLocale ?? this.defaultLocale;
|
|
27
|
+
const merged = registry.getMergedMessages();
|
|
28
|
+
for (const locale of Object.keys(merged)){
|
|
29
|
+
this.cache.set(locale, merged[locale]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
translate(locale, key, params) {
|
|
33
|
+
const primary = this.getCompiledMessages(locale)[key];
|
|
34
|
+
if (primary) return primary(params);
|
|
35
|
+
// Per-key fallback: a supported locale missing an individual key falls back
|
|
36
|
+
// to fallbackLocale before giving up (returning the raw key).
|
|
37
|
+
if (this.fallbackLocale !== locale) {
|
|
38
|
+
const fallback = this.getCompiledMessages(this.fallbackLocale)[key];
|
|
39
|
+
if (fallback) return fallback(params);
|
|
40
|
+
}
|
|
41
|
+
return key; // missing everywhere → return the key (dev-friendly)
|
|
42
|
+
}
|
|
43
|
+
getAvailableLocales() {
|
|
44
|
+
return [
|
|
45
|
+
...this.cache.keys()
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
isLocaleSupported(locale) {
|
|
49
|
+
return this.cache.has(locale);
|
|
50
|
+
}
|
|
51
|
+
getDefaultLocale() {
|
|
52
|
+
return this.defaultLocale;
|
|
53
|
+
}
|
|
54
|
+
getCompiledMessages(locale) {
|
|
55
|
+
const effectiveLocale = this.cache.has(locale) ? locale : this.defaultLocale;
|
|
56
|
+
const cached = this.compiledCache.get(effectiveLocale);
|
|
57
|
+
if (cached) return cached;
|
|
58
|
+
const flattened = this.flattenMessages(this.cache.get(effectiveLocale) ?? {});
|
|
59
|
+
const compiled = {};
|
|
60
|
+
for (const [key, value] of Object.entries(flattened)){
|
|
61
|
+
const msg = new IntlMessageFormat(value, effectiveLocale);
|
|
62
|
+
compiled[key] = (params)=>String(msg.format(params));
|
|
63
|
+
}
|
|
64
|
+
this.compiledCache.set(effectiveLocale, compiled);
|
|
65
|
+
return compiled;
|
|
66
|
+
}
|
|
67
|
+
flattenMessages(messages, prefix = '') {
|
|
68
|
+
const result = {};
|
|
69
|
+
for (const key of Object.keys(messages)){
|
|
70
|
+
const value = messages[key];
|
|
71
|
+
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
72
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
73
|
+
Object.assign(result, this.flattenMessages(value, newKey));
|
|
74
|
+
} else {
|
|
75
|
+
result[newKey] = String(value);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
MessageLoaderService = _ts_decorate([
|
|
82
|
+
Injectable(),
|
|
83
|
+
_ts_param(0, Inject(MessageRegistry)),
|
|
84
|
+
_ts_param(1, Inject(I18N_OPTIONS)),
|
|
85
|
+
_ts_metadata("design:type", Function),
|
|
86
|
+
_ts_metadata("design:paramtypes", [
|
|
87
|
+
typeof MessageRegistry === "undefined" ? Object : MessageRegistry,
|
|
88
|
+
typeof I18nModuleOptions === "undefined" ? Object : I18nModuleOptions
|
|
89
|
+
])
|
|
90
|
+
], MessageLoaderService);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type Contribution = Record<string, Record<string, unknown>>;
|
|
2
|
+
/**
|
|
3
|
+
* Accumulates i18n messages from multiple `I18nModule.registerMessages()` calls
|
|
4
|
+
* (statically, at module import time), deep-merged on read by
|
|
5
|
+
* {@link MessageLoaderService}. Later registrations override earlier ones at the
|
|
6
|
+
* leaf level.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MessageRegistry {
|
|
9
|
+
/** Called by `I18nModule.registerMessages()`. */
|
|
10
|
+
static addMessages(messages: Contribution): void;
|
|
11
|
+
/** All contributions deep-merged, per locale, in registration order. */
|
|
12
|
+
getMergedMessages(): Record<string, Record<string, unknown>>;
|
|
13
|
+
/** @internal — testing */
|
|
14
|
+
static reset(): void;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
import { Injectable } from "../container/decorators.js";
|
|
8
|
+
import { deepMerge } from "./deep-merge.js";
|
|
9
|
+
// Shared contributions store anchored on globalThis so bundler-inlined copies
|
|
10
|
+
// (portal/symlink) and Vite HMR re-eval share ONE store. Content-keyed so
|
|
11
|
+
// re-registering identical messages (HMR) dedups instead of accumulating.
|
|
12
|
+
const CONTRIBUTIONS_KEY = Symbol.for('vela:i18n:message-registry:contributions');
|
|
13
|
+
function getContributions() {
|
|
14
|
+
const g = globalThis;
|
|
15
|
+
return g[CONTRIBUTIONS_KEY] ??= new Map();
|
|
16
|
+
}
|
|
17
|
+
function contentKey(value) {
|
|
18
|
+
if (Array.isArray(value)) return `[${value.map(contentKey).join(',')}]`;
|
|
19
|
+
if (typeof value === 'object' && value !== null) {
|
|
20
|
+
const entries = Object.keys(value).sort().map((key)=>`${JSON.stringify(key)}:${contentKey(value[key])}`);
|
|
21
|
+
return `{${entries.join(',')}}`;
|
|
22
|
+
}
|
|
23
|
+
return JSON.stringify(value) ?? 'undefined';
|
|
24
|
+
}
|
|
25
|
+
export class MessageRegistry {
|
|
26
|
+
/** Called by `I18nModule.registerMessages()`. */ static addMessages(messages) {
|
|
27
|
+
if (messages && typeof messages === 'object' && Object.keys(messages).length > 0) {
|
|
28
|
+
// set() dedups by content-key AND preserves insertion order for an existing
|
|
29
|
+
// key. (A prior delete+set moved re-registered content to the end, flipping
|
|
30
|
+
// deep-merge precedence under HMR re-eval.)
|
|
31
|
+
getContributions().set(contentKey(messages), messages);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** All contributions deep-merged, per locale, in registration order. */ getMergedMessages() {
|
|
35
|
+
const merged = {};
|
|
36
|
+
for (const contribution of getContributions().values()){
|
|
37
|
+
for (const locale of Object.keys(contribution)){
|
|
38
|
+
merged[locale] = deepMerge(merged[locale] ?? {}, contribution[locale]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return merged;
|
|
42
|
+
}
|
|
43
|
+
/** @internal — testing */ static reset() {
|
|
44
|
+
globalThis[CONTRIBUTIONS_KEY] = new Map();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
MessageRegistry = _ts_decorate([
|
|
48
|
+
Injectable()
|
|
49
|
+
], MessageRegistry);
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { METADATA_KEYS, HttpMethod, ParamType, Scope } from './constants';
|
|
|
12
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
13
|
export { REQUEST_CONTEXT } from './http/request-context';
|
|
14
14
|
export type { RequestContext } from './http/request-context';
|
|
15
|
+
export { enableAmbientContainer, getCurrentContainer, getCurrentRequestContext, } from './http/ambient';
|
|
15
16
|
export { Logger, LogLevel } from './services/index';
|
|
16
17
|
export type { LoggerService, ContextProvider, Writer, LoggerLevelName } from './services/index';
|
|
17
18
|
export { ConfigModule, ConfigService, CONFIG_OPTIONS } from './config/index';
|
|
@@ -20,18 +21,20 @@ export { HttpModule, HttpService, HTTP_MODULE_OPTIONS, HttpRequestException } fr
|
|
|
20
21
|
export type { HttpModuleOptions, HttpResponse, HttpRequestConfig } from './fetch/index';
|
|
21
22
|
export { CorsModule, CORS_OPTIONS } from './cors/index';
|
|
22
23
|
export type { CorsOptions } from './cors/index';
|
|
23
|
-
export { CacheModule, CacheService, CacheInterceptor, MemoryCacheStore, CacheKey, CacheTTL, CACHE_MANAGER, CACHE_MODULE_OPTIONS, CACHE_KEY_METADATA, CACHE_TTL_METADATA, } from './cache/index';
|
|
24
|
-
export type { CacheModuleOptions, CacheStore, CacheEntry } from './cache/index';
|
|
24
|
+
export { CacheModule, CacheService, CacheInterceptor, MemoryCacheStore, TieredCacheStore, CacheKey, CacheTTL, CACHE_MANAGER, CACHE_MODULE_OPTIONS, CACHE_KEY_METADATA, CACHE_TTL_METADATA, } from './cache/index';
|
|
25
|
+
export type { Awaitable, CacheModuleOptions, CacheStore, AsyncCacheStore, AnyCacheStore, CacheEntry, } from './cache/index';
|
|
25
26
|
export { EventEmitterModule, EventEmitter, EventEmitterSubscriber, OnEvent, ON_EVENT_METADATA, } from './event-emitter/index';
|
|
26
27
|
export type { EventHandler, OnEventMetadata } from './event-emitter/index';
|
|
27
28
|
export { ScheduleModule, ScheduleRegistry, Cron, Interval, parseCron, CRON_METADATA, INTERVAL_METADATA, } from './schedule/index';
|
|
28
29
|
export type { RegisteredCronJob, RegisteredIntervalJob, CronMetadata, IntervalMetadata, CronMatcher, } from './schedule/index';
|
|
30
|
+
export { WebSocketModule, WebSocketGateway, SubscribeMessage, MessageBody, ConnectedSocket, WebSocketServer, WsDispatcher, WsException, WS_SERVER, } from './websocket/index';
|
|
31
|
+
export type { WebSocketModuleOptions, WsClient, WsServer, WsMessage, WsResponse, WsExecutionContext, WsArgumentsHost, BroadcastCommand, SyncDriver, RoomRegistry, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect, } from './websocket/index';
|
|
29
32
|
export { HealthModule, HealthCheckService, HealthIndicatorService, HttpHealthIndicator, } from './health/index';
|
|
30
33
|
export type { HealthCheckResult, HealthCheckStatus, HealthIndicatorResult, HealthIndicatorFunction, ResponseCheckCallback, HttpPingOptions, } from './health/index';
|
|
31
34
|
export { ThrottlerModule, ThrottlerGuard, ThrottlerStorage, Throttle, SkipThrottle, THROTTLER_OPTIONS, THROTTLER_STORAGE, THROTTLE_METADATA, SKIP_THROTTLE_METADATA, } from './throttler/index';
|
|
32
35
|
export type { ThrottlerModuleOptions, ThrottleConfig, ThrottlerStore, ThrottlerStorageRecord, RateLimitInfo, } from './throttler/index';
|
|
33
|
-
export { Global, Module, defineDynamicModule, stableHash, } from './module/index';
|
|
34
|
-
export type { ModuleOptions, DynamicModule, AsyncModuleOptions, ModuleImport } from './module/index';
|
|
36
|
+
export { Global, Module, defineDynamicModule, stableHash, ConfigurableModuleBuilder, defineConfigurableModule, } from './module/index';
|
|
37
|
+
export type { ModuleOptions, DynamicModule, AsyncModuleOptions, ModuleImport, ConfigurableModuleAsyncOptions, ConfigurableModuleBuilderOptions, ConfigurableModuleClassType, ConfigurableModuleExtras, ConfigurableModuleExtrasTransform, ConfigurableModuleHost, ConfigurableModuleOptionsFactory, DefineConfigurableModuleSpec, } from './module/index';
|
|
35
38
|
export type { MiddlewareConsumer, NestModule, RouteInfo } from './http/index';
|
|
36
39
|
export { definePlugin, composePlugins, PluginRegistry, PluginRootModule, PLUGIN_REGISTRY_TOKEN, } from './plugin/plugin';
|
|
37
40
|
export type { Plugin } from './plugin/plugin';
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,8 @@ export { METADATA_KEYS, HttpMethod, ParamType, Scope } from "./constants.js";
|
|
|
14
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";
|
|
15
15
|
// Request-scoped context primitive
|
|
16
16
|
export { REQUEST_CONTEXT } from "./http/request-context.js";
|
|
17
|
+
// Opt-in ambient container access (ALS via hono/context-storage)
|
|
18
|
+
export { enableAmbientContainer, getCurrentContainer, getCurrentRequestContext } from "./http/ambient.js";
|
|
17
19
|
// Services
|
|
18
20
|
export { Logger, LogLevel } from "./services/index.js";
|
|
19
21
|
// Config
|
|
@@ -23,17 +25,19 @@ export { HttpModule, HttpService, HTTP_MODULE_OPTIONS, HttpRequestException } fr
|
|
|
23
25
|
// CORS
|
|
24
26
|
export { CorsModule, CORS_OPTIONS } from "./cors/index.js";
|
|
25
27
|
// Cache
|
|
26
|
-
export { CacheModule, CacheService, CacheInterceptor, MemoryCacheStore, CacheKey, CacheTTL, CACHE_MANAGER, CACHE_MODULE_OPTIONS, CACHE_KEY_METADATA, CACHE_TTL_METADATA } from "./cache/index.js";
|
|
28
|
+
export { CacheModule, CacheService, CacheInterceptor, MemoryCacheStore, TieredCacheStore, CacheKey, CacheTTL, CACHE_MANAGER, CACHE_MODULE_OPTIONS, CACHE_KEY_METADATA, CACHE_TTL_METADATA } from "./cache/index.js";
|
|
27
29
|
// Event Emitter
|
|
28
30
|
export { EventEmitterModule, EventEmitter, EventEmitterSubscriber, OnEvent, ON_EVENT_METADATA } from "./event-emitter/index.js";
|
|
29
31
|
// Schedule
|
|
30
32
|
export { ScheduleModule, ScheduleRegistry, Cron, Interval, parseCron, CRON_METADATA, INTERVAL_METADATA } from "./schedule/index.js";
|
|
33
|
+
// WebSocket (edge-safe core; transport-facing internals live at @velajs/vela/websocket)
|
|
34
|
+
export { WebSocketModule, WebSocketGateway, SubscribeMessage, MessageBody, ConnectedSocket, WebSocketServer, WsDispatcher, WsException, WS_SERVER } from "./websocket/index.js";
|
|
31
35
|
// Health
|
|
32
36
|
export { HealthModule, HealthCheckService, HealthIndicatorService, HttpHealthIndicator } from "./health/index.js";
|
|
33
37
|
// Throttler
|
|
34
38
|
export { ThrottlerModule, ThrottlerGuard, ThrottlerStorage, Throttle, SkipThrottle, THROTTLER_OPTIONS, THROTTLER_STORAGE, THROTTLE_METADATA, SKIP_THROTTLE_METADATA } from "./throttler/index.js";
|
|
35
39
|
// Module
|
|
36
|
-
export { Global, Module, defineDynamicModule, stableHash } from "./module/index.js";
|
|
40
|
+
export { Global, Module, defineDynamicModule, stableHash, ConfigurableModuleBuilder, defineConfigurableModule } from "./module/index.js";
|
|
37
41
|
// Plugin manifest + composer
|
|
38
42
|
export { definePlugin, composePlugins, PluginRegistry, PluginRootModule, PLUGIN_REGISTRY_TOKEN } from "./plugin/plugin.js";
|
|
39
43
|
// Pipeline Decorators
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { DynamicModule } from '../registry/types';
|
|
2
|
+
import type { ConfigurableModuleBuilderOptions, ConfigurableModuleExtras, ConfigurableModuleExtrasTransform, ConfigurableModuleHost, DefineConfigurableModuleSpec } from './configurable-module.types';
|
|
3
|
+
/**
|
|
4
|
+
* NestJS-parity builder that generates `forRoot`/`forRootAsync` (and `key`,
|
|
5
|
+
* `global`, factory-param inference) from a tiny spec — so a module is just its
|
|
6
|
+
* tokens + options type + service + a `@Module({...})` bag, while vela keeps its
|
|
7
|
+
* encapsulation (`exports`/visibility) and multi-instance `key` dedup.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
|
|
12
|
+
* new ConfigurableModuleBuilder<FooOptions>({ moduleName: 'Foo' }).build();
|
|
13
|
+
*
|
|
14
|
+
* @Module({
|
|
15
|
+
* providers: [FooService], // derived providers inject MODULE_OPTIONS_TOKEN
|
|
16
|
+
* exports: [FooService],
|
|
17
|
+
* })
|
|
18
|
+
* export class FooModule extends ConfigurableModuleClass {}
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare class ConfigurableModuleBuilder<Opts, MethodKey extends string = 'forRoot', FactoryMethodKey extends string = 'create', Extras extends ConfigurableModuleExtras = {
|
|
22
|
+
isGlobal?: boolean;
|
|
23
|
+
}> {
|
|
24
|
+
private readonly options;
|
|
25
|
+
private classMethodName;
|
|
26
|
+
private factoryMethodName;
|
|
27
|
+
private extrasDefaults;
|
|
28
|
+
private extrasTransform;
|
|
29
|
+
constructor(options?: ConfigurableModuleBuilderOptions);
|
|
30
|
+
/** Declare extra call-site keys (e.g. `isGlobal`) + how they reshape the definition. */
|
|
31
|
+
setExtras<NewExtras extends ConfigurableModuleExtras>(defaults: NewExtras, transform: ConfigurableModuleExtrasTransform<NewExtras>): ConfigurableModuleBuilder<Opts, MethodKey, FactoryMethodKey, NewExtras>;
|
|
32
|
+
/** Rename the sync static (default `forRoot`); the async static becomes `<name>Async`. */
|
|
33
|
+
setClassMethodName<NewMethodKey extends string>(name: NewMethodKey): ConfigurableModuleBuilder<Opts, NewMethodKey, FactoryMethodKey, Extras>;
|
|
34
|
+
/** Rename the method a `useClass`/`useExisting` options factory must implement (default `create`). */
|
|
35
|
+
setFactoryMethodName<NewFactoryMethodKey extends string>(name: NewFactoryMethodKey): ConfigurableModuleBuilder<Opts, MethodKey, NewFactoryMethodKey, Extras>;
|
|
36
|
+
build(): ConfigurableModuleHost<Opts, MethodKey, FactoryMethodKey, Extras>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Lower-level engine for cases a class-mixin can't express — chiefly a
|
|
40
|
+
* runtime-generated module class whose providers depend on a call-time arg
|
|
41
|
+
* (Cloudflare binding modules). Returns an object with a single static named by
|
|
42
|
+
* `spec.methodName` (default `forRoot`).
|
|
43
|
+
*/
|
|
44
|
+
export declare function defineConfigurableModule<Args>(spec: DefineConfigurableModuleSpec<Args>): Record<string, (args: Args) => DynamicModule>;
|