@dereekb/nestjs 13.2.2 → 13.3.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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/openai",
3
- "version": "13.2.2",
3
+ "version": "13.3.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.2.2",
6
- "@dereekb/model": "13.2.2",
7
- "@dereekb/nestjs": "13.2.2",
8
- "@dereekb/rxjs": "13.2.2",
9
- "@dereekb/util": "13.2.2",
5
+ "@dereekb/date": "13.3.0",
6
+ "@dereekb/model": "13.3.0",
7
+ "@dereekb/nestjs": "13.3.0",
8
+ "@dereekb/rxjs": "13.3.0",
9
+ "@dereekb/util": "13.3.0",
10
10
  "@nestjs/common": "^11.0.0",
11
11
  "@nestjs/config": "^4.0.0",
12
12
  "express": "^5.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs",
3
- "version": "13.2.2",
3
+ "version": "13.3.0",
4
4
  "types": "./src/index.d.ts",
5
5
  "module": "./index.esm.js",
6
6
  "main": "./index.cjs.js",
@@ -50,7 +50,7 @@
50
50
  }
51
51
  },
52
52
  "peerDependencies": {
53
- "@dereekb/util": "13.2.2",
53
+ "@dereekb/util": "13.3.0",
54
54
  "discord.js": "^14.25.1",
55
55
  "@nestjs/common": "^11.0.0",
56
56
  "@nestjs/config": "^4.0.0",
@@ -1,6 +1,6 @@
1
1
  import { type ExecutionContext } from '@nestjs/common';
2
2
  /**
3
- * Returns true if the request is from localhost:4200.
3
+ * Returns true if the request is from localhost.
4
4
  */
5
5
  export declare const IsRequestFromLocalHost: (...dataOrPipes: unknown[]) => ParameterDecorator;
6
6
  export declare function isLocalhost(context: ExecutionContext): boolean;
@@ -1,8 +1,81 @@
1
1
  import { type ParsedUrlQuery } from 'querystring';
2
+ /**
3
+ * Buffer type alias representing a raw HTTP request body before any parsing.
4
+ */
2
5
  export type RawBodyBuffer = Buffer;
6
+ /**
7
+ * NestJS parameter decorator that reads the raw request body directly from the incoming stream.
8
+ *
9
+ * Requires the request to still be readable (i.e., no prior body-parsing middleware has consumed it).
10
+ *
11
+ * @throws {BadRequestException} When the request stream is not readable
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * @Post('webhook')
16
+ * handleWebhook(@ParseRawBody() body: RawBodyBuffer) { ... }
17
+ * ```
18
+ */
3
19
  export declare const ParseRawBody: (...dataOrPipes: any[]) => ParameterDecorator;
20
+ /**
21
+ * NestJS parameter decorator that retrieves the already-parsed raw body buffer from `req.body`.
22
+ *
23
+ * Expects that a prior middleware (e.g., raw body middleware) has already set `req.body` to a Buffer.
24
+ *
25
+ * @throws {InternalServerErrorException} When `req.body` is not a Buffer
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * @Post('webhook')
30
+ * handleWebhook(@RawBody() body: RawBodyBuffer) { ... }
31
+ * ```
32
+ */
4
33
  export declare const RawBody: (...dataOrPipes: any[]) => ParameterDecorator;
34
+ /**
35
+ * NestJS parameter decorator that parses the raw body buffer as a URL-encoded query string
36
+ * and replaces `req.body` with the parsed result.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * @Post('form')
41
+ * handleForm(@ParsedQueryRawBody() body: ParsedUrlQuery) { ... }
42
+ * ```
43
+ */
5
44
  export declare const ParsedQueryRawBody: (...dataOrPipes: any[]) => ParameterDecorator;
45
+ /**
46
+ * Parses a raw body buffer as JSON.
47
+ *
48
+ * @param rawBody - The raw body buffer to parse
49
+ * @returns The parsed JSON object
50
+ * @throws {SyntaxError} When the body is not valid JSON
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const data = RawBodyToJson<{ id: string }>(rawBody);
55
+ * ```
56
+ */
6
57
  export declare function RawBodyToJson<T extends object>(rawBody: RawBodyBuffer): T;
58
+ /**
59
+ * Parses a raw body buffer as a URL-encoded query string.
60
+ *
61
+ * @param rawBody - The raw body buffer to parse
62
+ * @returns The parsed query parameters
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * const params = RawBodyToParsedQueryString(rawBody); // { key: "value" }
67
+ * ```
68
+ */
7
69
  export declare function RawBodyToParsedQueryString(rawBody: RawBodyBuffer): ParsedUrlQuery;
70
+ /**
71
+ * Converts a raw body buffer to a trimmed UTF-8 string.
72
+ *
73
+ * @param rawBody - The raw body buffer to convert
74
+ * @returns The decoded and trimmed string content
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const text = RawBodyToString(rawBody);
79
+ * ```
80
+ */
8
81
  export declare function RawBodyToString(rawBody: RawBodyBuffer): string;
@@ -1,3 +1,4 @@
1
1
  export * from './decorators';
2
2
  export * from './middlewares';
3
3
  export * from './module';
4
+ export * from './util';
@@ -1,5 +1,15 @@
1
1
  import { type Request, type Response } from 'express';
2
2
  import { type NestMiddleware } from '@nestjs/common';
3
+ /**
4
+ * NestJS middleware that applies JSON body parsing to incoming requests using `body-parser`.
5
+ *
6
+ * Useful when the global body parser is disabled and JSON parsing needs to be applied selectively to specific routes.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * consumer.apply(JsonBodyMiddleware).forRoutes('api');
11
+ * ```
12
+ */
3
13
  export declare class JsonBodyMiddleware implements NestMiddleware {
4
14
  use(req: Request, res: Response, next: () => unknown): void;
5
15
  }
@@ -16,7 +16,7 @@ export declare class ConfigureWebhookMiddlewareModule extends AppModuleWithWebho
16
16
  configure(consumer: MiddlewareConsumer): void;
17
17
  }
18
18
  /**
19
- * Configures a MiddlewareConsumer to use RawBodyMiddleware for all POST requests to /webhook/*. All other routes are consumed with the JsonBodyMiddleware.
19
+ * Configures a MiddlewareConsumer to use RawBodyMiddleware for all POST requests to /webhook/{*path}. All other routes are consumed with the JsonBodyMiddleware.
20
20
  *
21
21
  * This is required for various webhooks that require the full body to properly parse content.
22
22
  *
@@ -1,8 +1,24 @@
1
1
  import { type ClientWebAppUrl } from './client';
2
+ /**
3
+ * Configuration holding the client-facing web application URL.
4
+ *
5
+ * Used by backend services that need to generate links pointing to the frontend (e.g., email templates, redirect URLs).
6
+ */
2
7
  export interface ClientAppConfig {
3
8
  readonly clientWebAppUrl: ClientWebAppUrl;
4
9
  }
10
+ /**
11
+ * Abstract service configuration that provides access to the client application config.
12
+ *
13
+ * Subclass this to supply environment-specific client URLs to NestJS services.
14
+ */
5
15
  export declare abstract class ClientAppServiceConfig {
6
16
  readonly client: ClientAppConfig;
17
+ /**
18
+ * Validates that the configuration contains a non-empty client web app URL.
19
+ *
20
+ * @param config - The configuration to validate
21
+ * @throws {Error} When `clientWebAppUrl` is not specified
22
+ */
7
23
  static assertValidConfig(config: ClientAppServiceConfig): void;
8
24
  }
@@ -22,4 +22,10 @@ export declare abstract class ServerEnvironmentConfig {
22
22
  * This is always false when production is true.
23
23
  */
24
24
  abstract developerToolsEnabled?: boolean;
25
+ /**
26
+ * The primary URL of the application (e.g., 'https://app.example.com').
27
+ *
28
+ * Should not end with a trailing slash.
29
+ */
30
+ abstract appUrl?: string;
25
31
  }
@@ -6,4 +6,5 @@ export declare class ServerEnvironmentService {
6
6
  get isProduction(): boolean;
7
7
  get isStaging(): boolean;
8
8
  get developerToolsEnabled(): boolean;
9
+ get appUrl(): string | undefined;
9
10
  }
@@ -0,0 +1 @@
1
+ export * from './json.encrypt';
@@ -0,0 +1,130 @@
1
+ import { type StringEncryptionProvider, type Getter, type GetterOrValue } from '@dereekb/util';
2
+ /**
3
+ * A hex-encoded secret key for AES-256-GCM encryption. Must be 64 hex characters (32 bytes).
4
+ */
5
+ export type AES256GCMEncryptionSecret = string;
6
+ /**
7
+ * Validates that the given secret is a 64-character hexadecimal string (32 bytes for AES-256).
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * isValidAES256GCMEncryptionSecret('a'.repeat(64)); // true
12
+ * isValidAES256GCMEncryptionSecret('too-short'); // false
13
+ * ```
14
+ */
15
+ export declare function isValidAES256GCMEncryptionSecret(secret: AES256GCMEncryptionSecret): boolean;
16
+ /**
17
+ * The source for the encryption secret.
18
+ *
19
+ * - If a string, it is used directly as the hex-encoded key (64 hex chars = 32 bytes).
20
+ * - If a Getter, it is called each time to retrieve the key (useful for rotation or lazy loading).
21
+ */
22
+ export type AES256GCMEncryptionSecretSource = GetterOrValue<AES256GCMEncryptionSecret>;
23
+ /**
24
+ * Factory that eagerly resolves and validates the encryption key from a secret source.
25
+ *
26
+ * The getter is called immediately and the key is validated on creation. The returned
27
+ * function provides the resolved Buffer without re-resolving or re-validating.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const getKey = resolveEncryptionKey('a'.repeat(64));
32
+ * const key: Buffer = getKey();
33
+ * ```
34
+ *
35
+ * @param source - The secret source configuration.
36
+ * @returns A getter that returns the resolved 32-byte Buffer for AES-256 encryption.
37
+ * @throws Error if the resolved key is not 64 hex characters.
38
+ */
39
+ export declare function resolveEncryptionKey(source: AES256GCMEncryptionSecretSource): Getter<Buffer>;
40
+ /**
41
+ * Provides AES-256-GCM encryption/decryption for JSON-serializable values.
42
+ *
43
+ * The key is captured in the closure at creation time via `createAES256GCMEncryption()`.
44
+ */
45
+ export interface AES256GCMEncryption {
46
+ /**
47
+ * Encrypts a raw string to a base64-encoded ciphertext string.
48
+ *
49
+ * Format: base64(IV (12 bytes) + ciphertext + authTag (16 bytes))
50
+ */
51
+ encryptString(plaintext: string): string;
52
+ /**
53
+ * Decrypts a base64-encoded ciphertext string back to the original plaintext.
54
+ */
55
+ decryptString(encoded: string): string;
56
+ /**
57
+ * Encrypts a JSON-serializable value to a base64-encoded string.
58
+ *
59
+ * The value is JSON.stringified before encryption.
60
+ */
61
+ encryptValue<T>(value: T): string;
62
+ /**
63
+ * Decrypts a base64-encoded string back to the original JSON-parsed value.
64
+ */
65
+ decryptValue<T>(encoded: string): T;
66
+ }
67
+ /**
68
+ * Creates an `AES256GCMEncryption` instance that captures the resolved key in a closure.
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const encryption = createAES256GCMEncryption('a'.repeat(64));
73
+ *
74
+ * const encrypted = encryption.encryptValue({ sensitive: 'data' });
75
+ * const decrypted = encryption.decryptValue<{ sensitive: string }>(encrypted);
76
+ *
77
+ * const encryptedStr = encryption.encryptString('hello');
78
+ * const decryptedStr = encryption.decryptString(encryptedStr);
79
+ * // decryptedStr === 'hello'
80
+ * ```
81
+ *
82
+ * @param source - The hex-encoded secret or getter for the AES-256 key.
83
+ * @returns An `AES256GCMEncryption` instance.
84
+ * @throws Error if the resolved key is not 64 hex characters.
85
+ */
86
+ export declare function createAES256GCMEncryption(source: AES256GCMEncryptionSecretSource): AES256GCMEncryption;
87
+ /**
88
+ * Encrypts a JSON-serializable value to a base64-encoded string using AES-256-GCM.
89
+ *
90
+ * Format: base64(IV (12 bytes) + ciphertext + authTag (16 bytes))
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * const getKey = resolveEncryptionKey(mySecret);
95
+ * const encrypted = encryptValue({ sensitive: 'data' }, getKey());
96
+ * const decrypted = decryptValue<{ sensitive: string }>(encrypted, getKey());
97
+ * ```
98
+ *
99
+ * @param value - The value to encrypt (must be JSON-serializable).
100
+ * @param key - The 32-byte encryption key from `resolveEncryptionKey()`.
101
+ * @returns The encrypted value as a base64 string.
102
+ */
103
+ export declare function encryptValue<T>(value: T, key: Buffer): string;
104
+ /**
105
+ * Decrypts a base64-encoded string back to the original value.
106
+ *
107
+ * @param encoded - The base64-encoded encrypted string (IV + ciphertext + authTag).
108
+ * @param key - The 32-byte encryption key Buffer from calling the getter returned by `resolveEncryptionKey()`.
109
+ * @returns The decrypted JSON-parsed value.
110
+ */
111
+ export declare function decryptValue<T>(encoded: string, key: Buffer): T;
112
+ /**
113
+ * Creates a `StringEncryptionProvider` backed by AES-256-GCM from a secret source.
114
+ *
115
+ * The key is resolved and validated eagerly at creation time. The provider encrypts/decrypts
116
+ * raw strings (no JSON serialization) — suitable for use with `selectiveFieldEncryptor`.
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * const provider = createAesStringEncryptionProvider('a'.repeat(64));
121
+ * const encrypted = provider.encrypt('sensitive data');
122
+ * const decrypted = provider.decrypt(encrypted);
123
+ * // decrypted === 'sensitive data'
124
+ * ```
125
+ *
126
+ * @param source - The hex-encoded secret or getter for the AES-256 key.
127
+ * @returns A `StringEncryptionProvider` that encrypts/decrypts strings via AES-256-GCM.
128
+ * @throws Error if the resolved key is not 64 hex characters.
129
+ */
130
+ export declare function createAesStringEncryptionProvider(source: AES256GCMEncryptionSecretSource): StringEncryptionProvider;
@@ -0,0 +1 @@
1
+ export * from './encryption';