@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.
Files changed (115) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/__tests__/workers-als/entry-als.d.ts +9 -0
  3. package/dist/application.d.ts +10 -0
  4. package/dist/application.js +25 -0
  5. package/dist/cache/cache.module.d.ts +5 -7
  6. package/dist/cache/cache.module.js +44 -66
  7. package/dist/cache/cache.types.d.ts +26 -0
  8. package/dist/cache/cache.types.js +1 -1
  9. package/dist/cache/index.d.ts +2 -1
  10. package/dist/cache/index.js +1 -0
  11. package/dist/cache/tiered-cache.store.d.ts +19 -0
  12. package/dist/cache/tiered-cache.store.js +40 -0
  13. package/dist/config/config.module.d.ts +6 -5
  14. package/dist/config/config.module.js +46 -49
  15. package/dist/container/container.d.ts +33 -0
  16. package/dist/container/container.js +156 -7
  17. package/dist/container/disposable.d.ts +5 -0
  18. package/dist/container/disposable.js +33 -0
  19. package/dist/container/types.d.ts +8 -0
  20. package/dist/factory/bootstrap.js +10 -0
  21. package/dist/fetch/fetch.module.d.ts +5 -6
  22. package/dist/fetch/fetch.module.js +9 -42
  23. package/dist/http/ambient.d.ts +17 -0
  24. package/dist/http/ambient.js +44 -0
  25. package/dist/http/execution-context.js +4 -1
  26. package/dist/http/index.d.ts +1 -0
  27. package/dist/http/index.js +1 -0
  28. package/dist/http/route.manager.d.ts +19 -0
  29. package/dist/http/route.manager.js +84 -0
  30. package/dist/i18n/deep-merge.d.ts +2 -0
  31. package/dist/i18n/deep-merge.js +15 -0
  32. package/dist/i18n/i18n.middleware.d.ts +15 -0
  33. package/dist/i18n/i18n.middleware.js +94 -0
  34. package/dist/i18n/i18n.module.d.ts +13 -0
  35. package/dist/i18n/i18n.module.js +61 -0
  36. package/dist/i18n/i18n.options.d.ts +30 -0
  37. package/dist/i18n/i18n.options.js +16 -0
  38. package/dist/i18n/i18n.service.d.ts +20 -0
  39. package/dist/i18n/i18n.service.js +49 -0
  40. package/dist/i18n/i18n.tokens.d.ts +6 -0
  41. package/dist/i18n/i18n.tokens.js +3 -0
  42. package/dist/i18n/i18n.types.d.ts +6 -0
  43. package/dist/i18n/i18n.types.js +1 -0
  44. package/dist/i18n/index.d.ts +10 -0
  45. package/dist/i18n/index.js +8 -0
  46. package/dist/i18n/message-loader.service.d.ts +21 -0
  47. package/dist/i18n/message-loader.service.js +90 -0
  48. package/dist/i18n/message-registry.d.ts +16 -0
  49. package/dist/i18n/message-registry.js +49 -0
  50. package/dist/index.d.ts +7 -4
  51. package/dist/index.js +6 -2
  52. package/dist/module/configurable-module.builder.d.ts +44 -0
  53. package/dist/module/configurable-module.builder.js +177 -0
  54. package/dist/module/configurable-module.types.d.ts +93 -0
  55. package/dist/module/configurable-module.types.js +5 -0
  56. package/dist/module/index.d.ts +2 -0
  57. package/dist/module/index.js +1 -0
  58. package/dist/openapi/document.js +20 -2
  59. package/dist/openapi/types.d.ts +54 -0
  60. package/dist/pipeline/types.d.ts +21 -4
  61. package/dist/registry/metadata.registry.d.ts +16 -16
  62. package/dist/registry/metadata.registry.js +90 -32
  63. package/dist/seeder/index.d.ts +5 -0
  64. package/dist/seeder/index.js +4 -0
  65. package/dist/seeder/seeder.decorator.d.ts +7 -0
  66. package/dist/seeder/seeder.decorator.js +15 -0
  67. package/dist/seeder/seeder.module.d.ts +18 -0
  68. package/dist/seeder/seeder.module.js +40 -0
  69. package/dist/seeder/seeder.registry.d.ts +23 -0
  70. package/dist/seeder/seeder.registry.js +83 -0
  71. package/dist/seeder/seeder.tokens.d.ts +2 -0
  72. package/dist/seeder/seeder.tokens.js +1 -0
  73. package/dist/seeder/seeder.types.d.ts +20 -0
  74. package/dist/seeder/seeder.types.js +1 -0
  75. package/dist/storage/index.d.ts +4 -0
  76. package/dist/storage/index.js +2 -0
  77. package/dist/storage/path-template.d.ts +9 -0
  78. package/dist/storage/path-template.js +20 -0
  79. package/dist/storage/signed-url.d.ts +12 -0
  80. package/dist/storage/signed-url.js +55 -0
  81. package/dist/storage/storage.types.d.ts +41 -0
  82. package/dist/storage/storage.types.js +5 -0
  83. package/dist/throttler/throttler.module.d.ts +5 -8
  84. package/dist/throttler/throttler.module.js +27 -55
  85. package/dist/websocket/index.d.ts +12 -0
  86. package/dist/websocket/index.js +16 -0
  87. package/dist/websocket/websocket.decorators.d.ts +33 -0
  88. package/dist/websocket/websocket.decorators.js +58 -0
  89. package/dist/websocket/websocket.module.d.ts +18 -0
  90. package/dist/websocket/websocket.module.js +52 -0
  91. package/dist/websocket/websocket.tokens.d.ts +22 -0
  92. package/dist/websocket/websocket.tokens.js +20 -0
  93. package/dist/websocket/websocket.types.d.ts +86 -0
  94. package/dist/websocket/websocket.types.js +4 -0
  95. package/dist/websocket/ws-argument-resolver.d.ts +13 -0
  96. package/dist/websocket/ws-argument-resolver.js +40 -0
  97. package/dist/websocket/ws-dispatcher.d.ts +33 -0
  98. package/dist/websocket/ws-dispatcher.js +253 -0
  99. package/dist/websocket/ws-exception.d.ts +16 -0
  100. package/dist/websocket/ws-exception.js +32 -0
  101. package/dist/websocket/ws-execution-context.d.ts +9 -0
  102. package/dist/websocket/ws-execution-context.js +24 -0
  103. package/dist/websocket/ws-server.d.ts +31 -0
  104. package/dist/websocket/ws-server.js +74 -0
  105. package/dist/websocket/ws-sync.d.ts +47 -0
  106. package/dist/websocket/ws-sync.js +74 -0
  107. package/dist/websocket-node/index.d.ts +4 -0
  108. package/dist/websocket-node/index.js +5 -0
  109. package/dist/websocket-node/node-ws-client.d.ts +24 -0
  110. package/dist/websocket-node/node-ws-client.js +49 -0
  111. package/dist/websocket-node/redis-sync.d.ts +33 -0
  112. package/dist/websocket-node/redis-sync.js +56 -0
  113. package/dist/websocket-node/register-gateways.d.ts +20 -0
  114. package/dist/websocket-node/register-gateways.js +61 -0
  115. package/package.json +31 -1
@@ -0,0 +1,15 @@
1
+ import { Scope } from "../constants.js";
2
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
3
+ import { SEEDER_METADATA } from "./seeder.tokens.js";
4
+ /**
5
+ * Mark a class as a seeder. Also marks it `@Injectable()` (singleton) so it only
6
+ * needs to be listed in a module's providers (or `SeederModule.forRoot({ seeders })`)
7
+ * to be discovered by {@link SeederRegistry} at bootstrap.
8
+ */ export function Seeder(options = {}) {
9
+ return (target)=>{
10
+ const ctor = target;
11
+ MetadataRegistry.markInjectable(ctor);
12
+ MetadataRegistry.setScope(ctor, Scope.SINGLETON);
13
+ MetadataRegistry.setCustomClassMeta(target, SEEDER_METADATA, options);
14
+ };
15
+ }
@@ -0,0 +1,18 @@
1
+ import type { VelaApplication } from '../application';
2
+ import type { DynamicModule } from '../module/types';
3
+ import type { Type } from '../container/types';
4
+ import type { SeederResult } from './seeder.types';
5
+ export declare class SeederModule {
6
+ /**
7
+ * Register seeder classes as providers so they're discovered at bootstrap.
8
+ * (Seeders declared in other modules' providers are also discovered — this is
9
+ * just a convenience to co-locate them.)
10
+ */
11
+ static forRoot(options?: {
12
+ seeders?: Type[];
13
+ }): DynamicModule;
14
+ }
15
+ /** Convenience runner: resolve the registry from a built app and run all seeders. */
16
+ export declare function runSeeders(app: VelaApplication, options?: {
17
+ stopOnError?: boolean;
18
+ }): Promise<SeederResult[]>;
@@ -0,0 +1,40 @@
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 { stableHash } from "../module/stable-hash.js";
9
+ import { SeederRegistry } from "./seeder.registry.js";
10
+ export class SeederModule {
11
+ /**
12
+ * Register seeder classes as providers so they're discovered at bootstrap.
13
+ * (Seeders declared in other modules' providers are also discovered — this is
14
+ * just a convenience to co-locate them.)
15
+ */ static forRoot(options = {}) {
16
+ const seeders = options.seeders ?? [];
17
+ return {
18
+ module: SeederModule,
19
+ key: stableHash({
20
+ seeders: seeders.map((s)=>s.name)
21
+ }),
22
+ providers: [
23
+ ...seeders
24
+ ]
25
+ };
26
+ }
27
+ }
28
+ SeederModule = _ts_decorate([
29
+ Module({
30
+ providers: [
31
+ SeederRegistry
32
+ ],
33
+ exports: [
34
+ SeederRegistry
35
+ ]
36
+ })
37
+ ], SeederModule);
38
+ /** Convenience runner: resolve the registry from a built app and run all seeders. */ export function runSeeders(app, options) {
39
+ return app.get(SeederRegistry).runAll(options);
40
+ }
@@ -0,0 +1,23 @@
1
+ import { Container } from '../container/container';
2
+ import type { OnApplicationBootstrap } from '../lifecycle/index';
3
+ import type { RegisteredSeeder, SeederResult } from './seeder.types';
4
+ /**
5
+ * Discovers `@Seeder()` providers at bootstrap and runs them on demand.
6
+ * Mirrors `ScheduleRegistry`'s discovery (scan container tokens → read metadata).
7
+ */
8
+ export declare class SeederRegistry implements OnApplicationBootstrap {
9
+ private readonly container;
10
+ private seeders;
11
+ constructor(container: Container);
12
+ onApplicationBootstrap(): void;
13
+ /** Registered seeders in run order. */
14
+ list(): RegisteredSeeder[];
15
+ /**
16
+ * Run every seeder in order, each in its own request-scoped child container so
17
+ * request-scoped dependencies resolve. Returns a per-seeder result; when
18
+ * `stopOnError` is true (default) the run aborts on the first failure.
19
+ */
20
+ runAll(options?: {
21
+ stopOnError?: boolean;
22
+ }): Promise<SeederResult[]>;
23
+ }
@@ -0,0 +1,83 @@
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 { Container } from "../container/container.js";
16
+ import { Inject, Injectable } from "../container/index.js";
17
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
18
+ import { SEEDER_METADATA } from "./seeder.tokens.js";
19
+ export class SeederRegistry {
20
+ container;
21
+ seeders = [];
22
+ constructor(container){
23
+ this.container = container;
24
+ }
25
+ onApplicationBootstrap() {
26
+ for (const token of this.container.getTokens()){
27
+ if (typeof token !== 'function') continue;
28
+ const meta = MetadataRegistry.getCustomClassMeta(token, SEEDER_METADATA);
29
+ if (!meta) continue;
30
+ this.seeders.push({
31
+ target: token,
32
+ name: meta.name ?? token.name,
33
+ order: meta.order ?? 0
34
+ });
35
+ }
36
+ this.seeders.sort((a, b)=>a.order - b.order);
37
+ }
38
+ /** Registered seeders in run order. */ list() {
39
+ return [
40
+ ...this.seeders
41
+ ];
42
+ }
43
+ /**
44
+ * Run every seeder in order, each in its own request-scoped child container so
45
+ * request-scoped dependencies resolve. Returns a per-seeder result; when
46
+ * `stopOnError` is true (default) the run aborts on the first failure.
47
+ */ async runAll(options = {}) {
48
+ const stopOnError = options.stopOnError ?? true;
49
+ const results = [];
50
+ for (const seeder of this.seeders){
51
+ const child = this.container.createChild();
52
+ let failed = false;
53
+ try {
54
+ const instance = child.resolve(seeder.target);
55
+ await instance.run();
56
+ results.push({
57
+ name: seeder.name,
58
+ ok: true
59
+ });
60
+ } catch (error) {
61
+ results.push({
62
+ name: seeder.name,
63
+ ok: false,
64
+ error
65
+ });
66
+ failed = true;
67
+ } finally{
68
+ // Dispose the per-seeder child so its request-scoped disposables clean up.
69
+ await child.dispose();
70
+ }
71
+ if (failed && stopOnError) break;
72
+ }
73
+ return results;
74
+ }
75
+ }
76
+ SeederRegistry = _ts_decorate([
77
+ Injectable(),
78
+ _ts_param(0, Inject(Container)),
79
+ _ts_metadata("design:type", Function),
80
+ _ts_metadata("design:paramtypes", [
81
+ typeof Container === "undefined" ? Object : Container
82
+ ])
83
+ ], SeederRegistry);
@@ -0,0 +1,2 @@
1
+ /** Custom class-metadata key for `@Seeder()` (read during bootstrap discovery). */
2
+ export declare const SEEDER_METADATA = "vela:seeder";
@@ -0,0 +1 @@
1
+ /** Custom class-metadata key for `@Seeder()` (read during bootstrap discovery). */ export const SEEDER_METADATA = 'vela:seeder';
@@ -0,0 +1,20 @@
1
+ /** A database seeder. Implement `run()` and tag the class with `@Seeder()`. */
2
+ export interface Seeder {
3
+ run(): void | Promise<void>;
4
+ }
5
+ export interface SeederMetadata {
6
+ /** Display name (defaults to the class name). */
7
+ name?: string;
8
+ /** Ascending run order (default 0). */
9
+ order?: number;
10
+ }
11
+ export interface RegisteredSeeder {
12
+ name: string;
13
+ order: number;
14
+ target: new (...args: any[]) => Seeder;
15
+ }
16
+ export interface SeederResult {
17
+ name: string;
18
+ ok: boolean;
19
+ error?: unknown;
20
+ }
@@ -0,0 +1 @@
1
+ /** A database seeder. Implement `run()` and tag the class with `@Seeder()`. */ export { };
@@ -0,0 +1,4 @@
1
+ export { signUrl, verifySignedUrl } from './signed-url';
2
+ export type { SignedUrlOptions } from './signed-url';
3
+ export { expandPathTemplate, joinStoragePath } from './path-template';
4
+ export type { StorageBody, StorageDriver, PresignMethod, UploadOptions, UploadResult, DownloadResult, PresignedUrlResult, } from './storage.types';
@@ -0,0 +1,2 @@
1
+ export { signUrl, verifySignedUrl } from "./signed-url.js";
2
+ export { expandPathTemplate, joinStoragePath } from "./path-template.js";
@@ -0,0 +1,9 @@
1
+ export declare function expandPathTemplate(template: string, now?: Date): string;
2
+ /**
3
+ * Join a (templated) root with a relative path into a storage key. Segments are
4
+ * sanitized: `.`, `..`, and empty segments are dropped, so a caller-supplied
5
+ * `relativePath` containing `..` can never traverse above the disk root (a real
6
+ * hazard for the presign proxy, where the key flows through `new URL()` which
7
+ * would otherwise normalize `..`). Backslashes are treated as separators too.
8
+ */
9
+ export declare function joinStoragePath(root: string | undefined, relativePath: string, now?: Date): string;
@@ -0,0 +1,20 @@
1
+ // Expand path-template variables in a disk root / key. Supported tokens:
2
+ // {date} → YYYY-MM-DD {year} → YYYY {month} → MM {day} → DD
3
+ // {uuid} → crypto.randomUUID()
4
+ // `now` is injectable for deterministic tests.
5
+ export function expandPathTemplate(template, now = new Date()) {
6
+ const yyyy = now.getUTCFullYear().toString();
7
+ const mm = (now.getUTCMonth() + 1).toString().padStart(2, '0');
8
+ const dd = now.getUTCDate().toString().padStart(2, '0');
9
+ return template.replace(/\{date\}/g, `${yyyy}-${mm}-${dd}`).replace(/\{year\}/g, yyyy).replace(/\{month\}/g, mm).replace(/\{day\}/g, dd).replace(/\{uuid\}/g, ()=>crypto.randomUUID());
10
+ }
11
+ /**
12
+ * Join a (templated) root with a relative path into a storage key. Segments are
13
+ * sanitized: `.`, `..`, and empty segments are dropped, so a caller-supplied
14
+ * `relativePath` containing `..` can never traverse above the disk root (a real
15
+ * hazard for the presign proxy, where the key flows through `new URL()` which
16
+ * would otherwise normalize `..`). Backslashes are treated as separators too.
17
+ */ export function joinStoragePath(root, relativePath, now) {
18
+ const expandedRoot = root ? expandPathTemplate(root, now) : '';
19
+ return `${expandedRoot}/${relativePath}`.split(/[/\\]+/).filter((segment)=>segment !== '' && segment !== '.' && segment !== '..').join('/');
20
+ }
@@ -0,0 +1,12 @@
1
+ export interface SignedUrlOptions {
2
+ /** Time-to-live in seconds; a matching `expires` param is added + enforced. */
3
+ expiresIn?: number;
4
+ }
5
+ /**
6
+ * Sign a URL (or path) with HMAC-SHA256, appending `signature` (and `expires`).
7
+ * The signature covers `pathname + search` (minus the signature param). Returns
8
+ * the full URL for absolute inputs, or `pathname?search` for relative ones.
9
+ */
10
+ export declare function signUrl(url: string, secret: string, options?: SignedUrlOptions): Promise<string>;
11
+ /** Verify a signed URL (timing-safe) and enforce `expires`. */
12
+ export declare function verifySignedUrl(url: string, secret: string): Promise<boolean>;
@@ -0,0 +1,55 @@
1
+ // Signed-URL utilities using HMAC-SHA256 via the Web Crypto API (edge-safe;
2
+ // no node:crypto). Verification uses crypto.subtle.verify for timing-safety.
3
+ // Pattern: https://developers.cloudflare.com/workers/examples/signing-requests/
4
+ async function importKey(secret) {
5
+ return crypto.subtle.importKey('raw', new TextEncoder().encode(secret), {
6
+ name: 'HMAC',
7
+ hash: 'SHA-256'
8
+ }, false, [
9
+ 'sign',
10
+ 'verify'
11
+ ]);
12
+ }
13
+ function toBase64Url(buffer) {
14
+ const bytes = new Uint8Array(buffer);
15
+ let binary = '';
16
+ for (const byte of bytes)binary += String.fromCharCode(byte);
17
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
18
+ }
19
+ function fromBase64Url(value) {
20
+ const base64 = value.replace(/-/g, '+').replace(/_/g, '/');
21
+ const binary = atob(base64);
22
+ const bytes = new Uint8Array(new ArrayBuffer(binary.length));
23
+ for(let i = 0; i < binary.length; i++)bytes[i] = binary.charCodeAt(i);
24
+ return bytes;
25
+ }
26
+ /**
27
+ * Sign a URL (or path) with HMAC-SHA256, appending `signature` (and `expires`).
28
+ * The signature covers `pathname + search` (minus the signature param). Returns
29
+ * the full URL for absolute inputs, or `pathname?search` for relative ones.
30
+ */ export async function signUrl(url, secret, options) {
31
+ const parsed = new URL(url, 'https://placeholder.local');
32
+ const key = await importKey(secret);
33
+ if (options?.expiresIn) {
34
+ const expires = Math.floor(Date.now() / 1000) + options.expiresIn;
35
+ parsed.searchParams.set('expires', String(expires));
36
+ }
37
+ const dataToSign = `${parsed.pathname}?${parsed.searchParams.toString()}`;
38
+ const signatureBuffer = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(dataToSign));
39
+ parsed.searchParams.set('signature', toBase64Url(signatureBuffer));
40
+ return url.startsWith('http') ? parsed.toString() : `${parsed.pathname}?${parsed.searchParams.toString()}`;
41
+ }
42
+ /** Verify a signed URL (timing-safe) and enforce `expires`. */ export async function verifySignedUrl(url, secret) {
43
+ const parsed = new URL(url, 'https://placeholder.local');
44
+ const signature = parsed.searchParams.get('signature');
45
+ if (!signature) return false;
46
+ const expires = parsed.searchParams.get('expires');
47
+ if (expires) {
48
+ const expiryTime = parseInt(expires, 10);
49
+ if (Number.isNaN(expiryTime) || Math.floor(Date.now() / 1000) > expiryTime) return false;
50
+ }
51
+ parsed.searchParams.delete('signature');
52
+ const dataToVerify = `${parsed.pathname}?${parsed.searchParams.toString()}`;
53
+ const key = await importKey(secret);
54
+ return crypto.subtle.verify('HMAC', key, fromBase64Url(signature), new TextEncoder().encode(dataToVerify));
55
+ }
@@ -0,0 +1,41 @@
1
+ /** Body payloads accepted by uploads. */
2
+ export type StorageBody = ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob | null;
3
+ export type PresignMethod = 'GET' | 'PUT' | 'DELETE' | 'HEAD';
4
+ export interface UploadOptions {
5
+ size?: number;
6
+ mimeType?: string;
7
+ metadata?: Record<string, string>;
8
+ }
9
+ export interface UploadResult {
10
+ path: string;
11
+ disk: string;
12
+ size?: number;
13
+ mimeType: string;
14
+ uploadedAt: Date;
15
+ }
16
+ export interface DownloadResult {
17
+ toStream(): ReadableStream;
18
+ toArrayBuffer(): Promise<ArrayBuffer>;
19
+ toText(): Promise<string>;
20
+ contentType: string;
21
+ size: number;
22
+ metadata?: Record<string, string>;
23
+ }
24
+ export interface PresignedUrlResult {
25
+ url: string;
26
+ method: PresignMethod;
27
+ expiresIn: number;
28
+ expiresAt: Date;
29
+ }
30
+ /**
31
+ * Runtime-agnostic storage driver contract. Implement per backend (R2 in
32
+ * `@velajs/cloudflare`, and e.g. S3/GCS elsewhere) so the manager/service and
33
+ * multi-disk logic stay driver-independent.
34
+ */
35
+ export interface StorageDriver {
36
+ upload(body: StorageBody, path: string, options: UploadOptions): Promise<UploadResult>;
37
+ download(path: string): Promise<DownloadResult>;
38
+ delete(path: string): Promise<void>;
39
+ exists(path: string): Promise<boolean>;
40
+ getPresignedUrl(path: string, method: PresignMethod, expiresIn: number): Promise<PresignedUrlResult>;
41
+ }
@@ -0,0 +1,5 @@
1
+ /** Body payloads accepted by uploads. */ /**
2
+ * Runtime-agnostic storage driver contract. Implement per backend (R2 in
3
+ * `@velajs/cloudflare`, and e.g. S3/GCS elsewhere) so the manager/service and
4
+ * multi-disk logic stay driver-independent.
5
+ */ export { };
@@ -1,10 +1,7 @@
1
- import type { AsyncModuleOptions, DynamicModule } from '../module/types';
2
1
  import type { ThrottlerModuleOptions } from './throttler.types';
3
- export declare class ThrottlerModule {
4
- static forRoot(options: ThrottlerModuleOptions & {
5
- key?: string;
6
- }): DynamicModule;
7
- static forRootAsync(options: AsyncModuleOptions<ThrottlerModuleOptions> & {
8
- key?: string;
9
- }): DynamicModule;
2
+ declare const ConfigurableModuleClass: import("..").ConfigurableModuleClassType<ThrottlerModuleOptions, "forRoot", "create", {
3
+ isGlobal?: boolean;
4
+ }>;
5
+ export declare class ThrottlerModule extends ConfigurableModuleClass {
10
6
  }
7
+ export {};
@@ -1,48 +1,29 @@
1
- import { stableHash } from "../module/stable-hash.js";
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";
2
9
  import { APP_GUARD } from "../pipeline/tokens.js";
3
10
  import { ThrottlerGuard } from "./throttler.guard.js";
4
11
  import { ThrottlerStorage } from "./throttler.storage.js";
5
12
  import { THROTTLER_OPTIONS, THROTTLER_STORAGE } from "./throttler.tokens.js";
6
- export class ThrottlerModule {
7
- static forRoot(options) {
8
- const providers = [
9
- {
10
- provide: THROTTLER_OPTIONS,
11
- useValue: options
12
- },
13
- {
14
- provide: THROTTLER_STORAGE,
15
- useValue: options.storage ?? new ThrottlerStorage()
16
- },
17
- ThrottlerGuard,
18
- {
19
- provide: APP_GUARD,
20
- useExisting: ThrottlerGuard
21
- }
22
- ];
23
- return {
24
- module: ThrottlerModule,
25
- key: options.key ?? stableHash(options),
26
- providers,
27
- exports: [
28
- THROTTLER_OPTIONS,
29
- THROTTLER_STORAGE,
30
- ThrottlerGuard
31
- ]
32
- };
33
- }
34
- static forRootAsync(options) {
35
- const providers = [
36
- {
37
- provide: THROTTLER_OPTIONS,
38
- useFactory: options.useFactory,
39
- inject: options.inject ?? []
40
- },
13
+ const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModuleBuilder({
14
+ moduleName: 'Throttler',
15
+ optionsInjectionToken: THROTTLER_OPTIONS
16
+ }).build();
17
+ export class ThrottlerModule extends ConfigurableModuleClass {
18
+ }
19
+ ThrottlerModule = _ts_decorate([
20
+ Module({
21
+ providers: [
41
22
  {
42
23
  provide: THROTTLER_STORAGE,
43
- useFactory: (opts)=>opts.storage ?? new ThrottlerStorage(),
24
+ useFactory: (options)=>options.storage ?? new ThrottlerStorage(),
44
25
  inject: [
45
- THROTTLER_OPTIONS
26
+ MODULE_OPTIONS_TOKEN
46
27
  ]
47
28
  },
48
29
  ThrottlerGuard,
@@ -50,20 +31,11 @@ export class ThrottlerModule {
50
31
  provide: APP_GUARD,
51
32
  useExisting: ThrottlerGuard
52
33
  }
53
- ];
54
- return {
55
- module: ThrottlerModule,
56
- key: options.key ?? stableHash({
57
- inject: options.inject,
58
- useFactory: options.useFactory
59
- }),
60
- imports: options.imports ?? [],
61
- providers,
62
- exports: [
63
- THROTTLER_OPTIONS,
64
- THROTTLER_STORAGE,
65
- ThrottlerGuard
66
- ]
67
- };
68
- }
69
- }
34
+ ],
35
+ exports: [
36
+ THROTTLER_OPTIONS,
37
+ THROTTLER_STORAGE,
38
+ ThrottlerGuard
39
+ ]
40
+ })
41
+ ], ThrottlerModule);
@@ -0,0 +1,12 @@
1
+ export { WebSocketGateway, SubscribeMessage, MessageBody, ConnectedSocket, WebSocketServer, } from './websocket.decorators';
2
+ export { WebSocketModule } from './websocket.module';
3
+ export type { WebSocketModuleOptions } from './websocket.module';
4
+ export { WsDispatcher } from './ws-dispatcher';
5
+ export { WsServerImpl, BroadcastOperatorImpl } from './ws-server';
6
+ export { InMemoryRoomRegistry, local } from './ws-sync';
7
+ export type { SyncDriver, RoomRegistry } from './ws-sync';
8
+ export { buildWsExecutionContext } from './ws-execution-context';
9
+ export { WsException, toErrorFrame } from './ws-exception';
10
+ export { resolveWsArgs } from './ws-argument-resolver';
11
+ export { WS_SERVER, WS_SYNC_DRIVER, WS_ROOM_REGISTRY, WS_MODULE_OPTIONS, WS_GATEWAY_METADATA, WS_SUBSCRIBE_METADATA, WsParamType, } from './websocket.tokens';
12
+ export type { WsClient, WsServer, WsMessage, WsResponse, BroadcastCommand, BroadcastOperator, WebSocketGatewayOptions, SubscribeMessageMetadata, WsExecutionContext, WsArgumentsHost, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect, } from './websocket.types';
@@ -0,0 +1,16 @@
1
+ // Decorators
2
+ export { WebSocketGateway, SubscribeMessage, MessageBody, ConnectedSocket, WebSocketServer } from "./websocket.decorators.js";
3
+ // Module
4
+ export { WebSocketModule } from "./websocket.module.js";
5
+ // Dispatcher (injected/called by transports)
6
+ export { WsDispatcher } from "./ws-dispatcher.js";
7
+ // Server handle + rooms + sync
8
+ export { WsServerImpl, BroadcastOperatorImpl } from "./ws-server.js";
9
+ export { InMemoryRoomRegistry, local } from "./ws-sync.js";
10
+ // Execution context + exceptions
11
+ export { buildWsExecutionContext } from "./ws-execution-context.js";
12
+ export { WsException, toErrorFrame } from "./ws-exception.js";
13
+ // Argument resolution (used by transports building custom dispatch)
14
+ export { resolveWsArgs } from "./ws-argument-resolver.js";
15
+ // Tokens
16
+ export { WS_SERVER, WS_SYNC_DRIVER, WS_ROOM_REGISTRY, WS_MODULE_OPTIONS, WS_GATEWAY_METADATA, WS_SUBSCRIBE_METADATA, WsParamType } from "./websocket.tokens.js";
@@ -0,0 +1,33 @@
1
+ import type { WebSocketGatewayOptions } from './websocket.types';
2
+ /**
3
+ * Marks a class as a WebSocket gateway. Mirrors `@Controller` for the socket
4
+ * transport: registers the class as an injectable singleton and stores its
5
+ * routing options (`path`, Cloudflare `binding`).
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * @WebSocketGateway({ path: '/rooms/:id/ws', binding: 'CHAT_ROOM' })
10
+ * class ChatGateway {}
11
+ * ```
12
+ */
13
+ export declare function WebSocketGateway(options?: WebSocketGatewayOptions): ClassDecorator;
14
+ /**
15
+ * Binds a gateway method to an inbound event. Stackable — one class-level list,
16
+ * exactly like `@OnEvent` (`event-emitter.decorators.ts`).
17
+ */
18
+ export declare function SubscribeMessage(event: string): MethodDecorator;
19
+ /** Injects the inbound message payload (the envelope's `data`) into a handler parameter. */
20
+ export declare const MessageBody: () => ParameterDecorator;
21
+ /** Injects the connected socket (`WsClient`) into a handler parameter. */
22
+ export declare const ConnectedSocket: () => ParameterDecorator;
23
+ /**
24
+ * Injects the gateway server handle (`WsServer`). Constructor injection only —
25
+ * the container has no property-injection pass, so this is sugar for
26
+ * `@Inject(WS_SERVER)` on a constructor parameter.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * constructor(@WebSocketServer() private server: WsServer) {}
31
+ * ```
32
+ */
33
+ export declare function WebSocketServer(): ParameterDecorator;
@@ -0,0 +1,58 @@
1
+ import { Scope } from "../constants.js";
2
+ import { Inject } from "../container/decorators.js";
3
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
4
+ import { WS_GATEWAY_METADATA, WS_SERVER, WS_SUBSCRIBE_METADATA, WsParamType } from "./websocket.tokens.js";
5
+ /**
6
+ * Marks a class as a WebSocket gateway. Mirrors `@Controller` for the socket
7
+ * transport: registers the class as an injectable singleton and stores its
8
+ * routing options (`path`, Cloudflare `binding`).
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * @WebSocketGateway({ path: '/rooms/:id/ws', binding: 'CHAT_ROOM' })
13
+ * class ChatGateway {}
14
+ * ```
15
+ */ export function WebSocketGateway(options = {}) {
16
+ return (target)=>{
17
+ const ctor = target;
18
+ MetadataRegistry.setCustomClassMeta(ctor, WS_GATEWAY_METADATA, options);
19
+ MetadataRegistry.markInjectable(ctor);
20
+ MetadataRegistry.setScope(ctor, Scope.SINGLETON);
21
+ };
22
+ }
23
+ /**
24
+ * Binds a gateway method to an inbound event. Stackable — one class-level list,
25
+ * exactly like `@OnEvent` (`event-emitter.decorators.ts`).
26
+ */ export function SubscribeMessage(event) {
27
+ return (target, propertyKey)=>{
28
+ MetadataRegistry.appendCustomClassMeta(target.constructor, WS_SUBSCRIBE_METADATA, {
29
+ event,
30
+ methodName: String(propertyKey)
31
+ });
32
+ };
33
+ }
34
+ function wsParamDecorator(type) {
35
+ return ()=>(target, propertyKey, parameterIndex)=>{
36
+ if (propertyKey === undefined) {
37
+ throw new Error('WebSocket parameter decorators can only be used on method parameters');
38
+ }
39
+ MetadataRegistry.addParameter(target.constructor, propertyKey, {
40
+ index: parameterIndex,
41
+ type
42
+ });
43
+ };
44
+ }
45
+ /** Injects the inbound message payload (the envelope's `data`) into a handler parameter. */ export const MessageBody = wsParamDecorator(WsParamType.BODY);
46
+ /** Injects the connected socket (`WsClient`) into a handler parameter. */ export const ConnectedSocket = wsParamDecorator(WsParamType.SOCKET);
47
+ /**
48
+ * Injects the gateway server handle (`WsServer`). Constructor injection only —
49
+ * the container has no property-injection pass, so this is sugar for
50
+ * `@Inject(WS_SERVER)` on a constructor parameter.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * constructor(@WebSocketServer() private server: WsServer) {}
55
+ * ```
56
+ */ export function WebSocketServer() {
57
+ return Inject(WS_SERVER);
58
+ }
@@ -0,0 +1,18 @@
1
+ import type { DynamicModule } from '../module/types';
2
+ import { type RoomRegistry, type SyncDriver } from './ws-sync';
3
+ export interface WebSocketModuleOptions {
4
+ /**
5
+ * Cross-instance sync driver. Defaults to `local()` (single instance). Use
6
+ * `durableObject()` from `@velajs/cloudflare` or `redis()` from
7
+ * `@velajs/vela/websocket-node` for horizontal scale.
8
+ */
9
+ sync?: SyncDriver;
10
+ /**
11
+ * Local room registry the transport reads/writes. Defaults to the in-memory
12
+ * implementation (node/bun/deno); the Cloudflare transport supplies its own.
13
+ */
14
+ registry?: RoomRegistry;
15
+ }
16
+ export declare class WebSocketModule {
17
+ static forRoot(options?: WebSocketModuleOptions): DynamicModule;
18
+ }