@dereekb/nestjs 13.6.8 → 13.6.10

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.
@@ -113,6 +113,9 @@ function _define_property$5(obj, key, value) {
113
113
  /**
114
114
  * Default environment variable for the Discord application public key.
115
115
  */ var DISCORD_PUBLIC_KEY_ENV_VAR = 'DISCORD_PUBLIC_KEY';
116
+ /**
117
+ * The byte length of a Discord Ed25519 public key (32 bytes = 64 hex characters).
118
+ */ var DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH = 32;
116
119
  /**
117
120
  * Configuration for the DiscordWebhookService.
118
121
  */ var DiscordWebhookServiceConfig = /*#__PURE__*/ function() {
@@ -124,9 +127,15 @@ function _define_property$5(obj, key, value) {
124
127
  {
125
128
  key: "assertValidConfig",
126
129
  value: function assertValidConfig(config) {
127
- if (!config.discordWebhook.publicKey) {
130
+ var publicKey = config.discordWebhook.publicKey;
131
+ if (!publicKey) {
128
132
  throw new Error('No Discord public key specified.');
129
133
  }
134
+ if (!util.isHexWithByteLength(publicKey, {
135
+ byteLength: DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH
136
+ })) {
137
+ throw new Error('Discord public key is not available or is invalid. Expected a 64-character hex string (32-byte Ed25519 key).');
138
+ }
130
139
  }
131
140
  }
132
141
  ]);
@@ -1463,6 +1472,7 @@ function _unsupported_iterable_to_array(o, minLen) {
1463
1472
  exports.DISCORD_BOT_TOKEN_ENV_VAR = DISCORD_BOT_TOKEN_ENV_VAR;
1464
1473
  exports.DISCORD_DEFAULT_INTENTS = DISCORD_DEFAULT_INTENTS;
1465
1474
  exports.DISCORD_DEFAULT_MESSAGES_PER_PAGE = DISCORD_DEFAULT_MESSAGES_PER_PAGE;
1475
+ exports.DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH = DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH;
1466
1476
  exports.DISCORD_PUBLIC_KEY_ENV_VAR = DISCORD_PUBLIC_KEY_ENV_VAR;
1467
1477
  exports.DiscordServiceConfig = DiscordServiceConfig;
1468
1478
  exports.DiscordWebhookServiceConfig = DiscordWebhookServiceConfig;
@@ -1,4 +1,4 @@
1
- import { handlerFactory, handlerConfigurerFactory, handlerMappedSetFunctionFactory, lastValue } from '@dereekb/util';
1
+ import { handlerFactory, handlerConfigurerFactory, handlerMappedSetFunctionFactory, isHexWithByteLength, lastValue } from '@dereekb/util';
2
2
  import { InteractionType, GatewayIntentBits, Client, Events, TextChannel } from 'discord.js';
3
3
  import { RawBody } from '@dereekb/nestjs';
4
4
  import { Injectable, Inject, Logger, Post, Req, Controller, Module } from '@nestjs/common';
@@ -111,6 +111,9 @@ function _define_property$5(obj, key, value) {
111
111
  /**
112
112
  * Default environment variable for the Discord application public key.
113
113
  */ var DISCORD_PUBLIC_KEY_ENV_VAR = 'DISCORD_PUBLIC_KEY';
114
+ /**
115
+ * The byte length of a Discord Ed25519 public key (32 bytes = 64 hex characters).
116
+ */ var DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH = 32;
114
117
  /**
115
118
  * Configuration for the DiscordWebhookService.
116
119
  */ var DiscordWebhookServiceConfig = /*#__PURE__*/ function() {
@@ -122,9 +125,15 @@ function _define_property$5(obj, key, value) {
122
125
  {
123
126
  key: "assertValidConfig",
124
127
  value: function assertValidConfig(config) {
125
- if (!config.discordWebhook.publicKey) {
128
+ var publicKey = config.discordWebhook.publicKey;
129
+ if (!publicKey) {
126
130
  throw new Error('No Discord public key specified.');
127
131
  }
132
+ if (!isHexWithByteLength(publicKey, {
133
+ byteLength: DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH
134
+ })) {
135
+ throw new Error('Discord public key is not available or is invalid. Expected a 64-character hex string (32-byte Ed25519 key).');
136
+ }
128
137
  }
129
138
  }
130
139
  ]);
@@ -1458,4 +1467,4 @@ function _unsupported_iterable_to_array(o, minLen) {
1458
1467
  };
1459
1468
  }
1460
1469
 
1461
- export { DISCORD_BOT_TOKEN_ENV_VAR, DISCORD_DEFAULT_INTENTS, DISCORD_DEFAULT_MESSAGES_PER_PAGE, DISCORD_PUBLIC_KEY_ENV_VAR, DiscordApi, DiscordModule, DiscordServiceConfig, DiscordWebhookController, DiscordWebhookModule, DiscordWebhookService, DiscordWebhookServiceConfig, discordClientOptionsWithIntents, discordDefaultClientOptions, discordFetchMessagePageFactory, discordInteractionHandlerConfigurerFactory, discordInteractionHandlerFactory, discordServiceConfigFactory, discordWebhookEventVerifier, discordWebhookInteraction, discordWebhookServiceConfigFactory };
1470
+ export { DISCORD_BOT_TOKEN_ENV_VAR, DISCORD_DEFAULT_INTENTS, DISCORD_DEFAULT_MESSAGES_PER_PAGE, DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH, DISCORD_PUBLIC_KEY_ENV_VAR, DiscordApi, DiscordModule, DiscordServiceConfig, DiscordWebhookController, DiscordWebhookModule, DiscordWebhookService, DiscordWebhookServiceConfig, discordClientOptionsWithIntents, discordDefaultClientOptions, discordFetchMessagePageFactory, discordInteractionHandlerConfigurerFactory, discordInteractionHandlerFactory, discordServiceConfigFactory, discordWebhookEventVerifier, discordWebhookInteraction, discordWebhookServiceConfigFactory };
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/discord",
3
- "version": "13.6.8",
3
+ "version": "13.6.10",
4
4
  "peerDependencies": {
5
- "@dereekb/nestjs": "13.6.8",
6
- "@dereekb/util": "13.6.8",
5
+ "@dereekb/nestjs": "13.6.10",
6
+ "@dereekb/rxjs": "13.6.10",
7
+ "@dereekb/util": "13.6.10",
7
8
  "@nestjs/common": "^11.1.17",
8
9
  "@nestjs/config": "^4.0.3",
9
10
  "discord.js": "^14.25.1",
@@ -3,6 +3,10 @@ import { type DiscordPublicKey } from '../discord.type';
3
3
  * Default environment variable for the Discord application public key.
4
4
  */
5
5
  export declare const DISCORD_PUBLIC_KEY_ENV_VAR = "DISCORD_PUBLIC_KEY";
6
+ /**
7
+ * The byte length of a Discord Ed25519 public key (32 bytes = 64 hex characters).
8
+ */
9
+ export declare const DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH = 32;
6
10
  export interface DiscordWebhookConfig {
7
11
  /**
8
12
  * The Ed25519 public key used to verify incoming interaction webhook signatures.
package/index.cjs.js CHANGED
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ var rxjs = require('@dereekb/rxjs');
4
+ var promises = require('fs/promises');
5
+ var path = require('path');
3
6
  var common = require('@nestjs/common');
4
7
  var rawbody = require('raw-body');
5
8
  var querystring = require('querystring');
@@ -8,6 +11,214 @@ var util = require('@dereekb/util');
8
11
  var config = require('@nestjs/config');
9
12
  var crypto = require('crypto');
10
13
 
14
+ function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
15
+ try {
16
+ var info = gen[key](arg);
17
+ var value = info.value;
18
+ } catch (error) {
19
+ reject(error);
20
+ return;
21
+ }
22
+ if (info.done) {
23
+ resolve(value);
24
+ } else {
25
+ Promise.resolve(value).then(_next, _throw);
26
+ }
27
+ }
28
+ function _async_to_generator$1(fn) {
29
+ return function() {
30
+ var self = this, args = arguments;
31
+ return new Promise(function(resolve, reject) {
32
+ var gen = fn.apply(self, args);
33
+ function _next(value) {
34
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value);
35
+ }
36
+ function _throw(err) {
37
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err);
38
+ }
39
+ _next(undefined);
40
+ });
41
+ };
42
+ }
43
+ function _ts_generator$1(thisArg, body) {
44
+ var f, y, t, _ = {
45
+ label: 0,
46
+ sent: function() {
47
+ if (t[0] & 1) throw t[1];
48
+ return t[1];
49
+ },
50
+ trys: [],
51
+ ops: []
52
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
53
+ return d(g, "next", {
54
+ value: verb(0)
55
+ }), d(g, "throw", {
56
+ value: verb(1)
57
+ }), d(g, "return", {
58
+ value: verb(2)
59
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
60
+ value: function() {
61
+ return this;
62
+ }
63
+ }), g;
64
+ function verb(n) {
65
+ return function(v) {
66
+ return step([
67
+ n,
68
+ v
69
+ ]);
70
+ };
71
+ }
72
+ function step(op) {
73
+ if (f) throw new TypeError("Generator is already executing.");
74
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
75
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
76
+ if (y = 0, t) op = [
77
+ op[0] & 2,
78
+ t.value
79
+ ];
80
+ switch(op[0]){
81
+ case 0:
82
+ case 1:
83
+ t = op;
84
+ break;
85
+ case 4:
86
+ _.label++;
87
+ return {
88
+ value: op[1],
89
+ done: false
90
+ };
91
+ case 5:
92
+ _.label++;
93
+ y = op[1];
94
+ op = [
95
+ 0
96
+ ];
97
+ continue;
98
+ case 7:
99
+ op = _.ops.pop();
100
+ _.trys.pop();
101
+ continue;
102
+ default:
103
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
104
+ _ = 0;
105
+ continue;
106
+ }
107
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
108
+ _.label = op[1];
109
+ break;
110
+ }
111
+ if (op[0] === 6 && _.label < t[1]) {
112
+ _.label = t[1];
113
+ t = op;
114
+ break;
115
+ }
116
+ if (t && _.label < t[2]) {
117
+ _.label = t[2];
118
+ _.ops.push(op);
119
+ break;
120
+ }
121
+ if (t[2]) _.ops.pop();
122
+ _.trys.pop();
123
+ continue;
124
+ }
125
+ op = body.call(thisArg, _);
126
+ } catch (e) {
127
+ op = [
128
+ 6,
129
+ e
130
+ ];
131
+ y = 0;
132
+ } finally{
133
+ f = t = 0;
134
+ }
135
+ if (op[0] & 5) throw op[1];
136
+ return {
137
+ value: op[0] ? op[1] : void 0,
138
+ done: true
139
+ };
140
+ }
141
+ }
142
+ /**
143
+ * Creates an {@link AssetLoader} that reads local assets from the
144
+ * filesystem using Node.js `fs/promises`.
145
+ *
146
+ * The ref's {@link AssetLocalPathRef.path} is resolved relative
147
+ * to the configured {@link NodeJsLocalAssetLoaderConfig.basePath}.
148
+ *
149
+ * @example
150
+ * ```ts
151
+ * const loader = nodeJsLocalAssetLoader({ basePath: './assets' });
152
+ * loader.get(localAsset('data/districts.json')).load().subscribe((buffer) => {
153
+ * // reads from ./assets/data/districts.json
154
+ * });
155
+ * ```
156
+ *
157
+ * @param config - Filesystem configuration with base path.
158
+ */ function nodeJsLocalAssetLoader(config) {
159
+ var basePath = config.basePath;
160
+ var getFn = function getFn(ref) {
161
+ return _async_to_generator$1(function() {
162
+ var localRef, fullPath, buffer;
163
+ return _ts_generator$1(this, function(_state) {
164
+ switch(_state.label){
165
+ case 0:
166
+ localRef = ref;
167
+ fullPath = path.resolve(basePath, localRef.path);
168
+ return [
169
+ 4,
170
+ promises.readFile(fullPath)
171
+ ];
172
+ case 1:
173
+ buffer = _state.sent();
174
+ return [
175
+ 2,
176
+ buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength)
177
+ ];
178
+ }
179
+ });
180
+ })();
181
+ };
182
+ return rxjs.assetLoaderFromGetFn(getFn);
183
+ }
184
+
185
+ /**
186
+ * Creates NestJS module metadata that provides an {@link AssetLoader}
187
+ * using {@link delegatedAssetLoader} with Node.js-specific leaf loaders.
188
+ *
189
+ * Local assets are loaded from the filesystem. Remote assets (which always
190
+ * have absolute URLs) are loaded via `fetch`.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * @Module(appAssetLoaderModuleMetadata({
195
+ * local: { basePath: './assets' }
196
+ * }))
197
+ * export class AppAssetLoaderModule {}
198
+ * ```
199
+ *
200
+ * @param config - Local filesystem config and optional remote fetch config.
201
+ */ function appAssetLoaderModuleMetadata(config) {
202
+ var local = nodeJsLocalAssetLoader(config.local);
203
+ var remote = rxjs.fetchAssetLoader(config.remote);
204
+ var loader = rxjs.delegatedAssetLoader({
205
+ local: local,
206
+ remote: remote
207
+ });
208
+ var providers = [
209
+ {
210
+ provide: rxjs.AssetLoader,
211
+ useValue: loader
212
+ }
213
+ ];
214
+ return {
215
+ providers: providers,
216
+ exports: [
217
+ rxjs.AssetLoader
218
+ ]
219
+ };
220
+ }
221
+
11
222
  /**
12
223
  * Returns true if the request is from localhost.
13
224
  */ var IsRequestFromLocalHost = common.createParamDecorator(function(data, context) {
@@ -1108,6 +1319,7 @@ exports.RawBodyToParsedQueryString = RawBodyToParsedQueryString;
1108
1319
  exports.RawBodyToString = RawBodyToString;
1109
1320
  exports.SERVER_ENV_TOKEN = SERVER_ENV_TOKEN;
1110
1321
  exports.ServerEnvironmentConfig = ServerEnvironmentConfig;
1322
+ exports.appAssetLoaderModuleMetadata = appAssetLoaderModuleMetadata;
1111
1323
  exports.clientAppConfigFactory = clientAppConfigFactory;
1112
1324
  exports.consumeWebhooksWithRawBodyMiddleware = consumeWebhooksWithRawBodyMiddleware;
1113
1325
  exports.createAES256GCMEncryption = createAES256GCMEncryption;
@@ -1119,5 +1331,6 @@ exports.isLocalhost = isLocalhost;
1119
1331
  exports.isTestNodeEnv = isTestNodeEnv;
1120
1332
  exports.isValidAES256GCMEncryptionSecret = isValidAES256GCMEncryptionSecret;
1121
1333
  exports.mergeModuleMetadata = mergeModuleMetadata;
1334
+ exports.nodeJsLocalAssetLoader = nodeJsLocalAssetLoader;
1122
1335
  exports.resolveEncryptionKey = resolveEncryptionKey;
1123
1336
  exports.serverEnvTokenProvider = serverEnvTokenProvider;
package/index.esm.js CHANGED
@@ -1,3 +1,6 @@
1
+ import { assetLoaderFromGetFn, fetchAssetLoader, delegatedAssetLoader, AssetLoader } from '@dereekb/rxjs';
2
+ import { readFile } from 'fs/promises';
3
+ import { resolve } from 'path';
1
4
  import { createParamDecorator, Logger, BadRequestException, InternalServerErrorException, Injectable, RequestMethod, Module, Inject } from '@nestjs/common';
2
5
  import rawbody from 'raw-body';
3
6
  import { parse } from 'querystring';
@@ -6,6 +9,214 @@ import { asArray, mergeArrays, isHex, getValueFromGetter } from '@dereekb/util';
6
9
  import { ConfigService, ConfigModule } from '@nestjs/config';
7
10
  import { createDecipheriv, randomBytes, createCipheriv } from 'crypto';
8
11
 
12
+ function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
13
+ try {
14
+ var info = gen[key](arg);
15
+ var value = info.value;
16
+ } catch (error) {
17
+ reject(error);
18
+ return;
19
+ }
20
+ if (info.done) {
21
+ resolve(value);
22
+ } else {
23
+ Promise.resolve(value).then(_next, _throw);
24
+ }
25
+ }
26
+ function _async_to_generator$1(fn) {
27
+ return function() {
28
+ var self = this, args = arguments;
29
+ return new Promise(function(resolve, reject) {
30
+ var gen = fn.apply(self, args);
31
+ function _next(value) {
32
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value);
33
+ }
34
+ function _throw(err) {
35
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err);
36
+ }
37
+ _next(undefined);
38
+ });
39
+ };
40
+ }
41
+ function _ts_generator$1(thisArg, body) {
42
+ var f, y, t, _ = {
43
+ label: 0,
44
+ sent: function() {
45
+ if (t[0] & 1) throw t[1];
46
+ return t[1];
47
+ },
48
+ trys: [],
49
+ ops: []
50
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
51
+ return d(g, "next", {
52
+ value: verb(0)
53
+ }), d(g, "throw", {
54
+ value: verb(1)
55
+ }), d(g, "return", {
56
+ value: verb(2)
57
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
58
+ value: function() {
59
+ return this;
60
+ }
61
+ }), g;
62
+ function verb(n) {
63
+ return function(v) {
64
+ return step([
65
+ n,
66
+ v
67
+ ]);
68
+ };
69
+ }
70
+ function step(op) {
71
+ if (f) throw new TypeError("Generator is already executing.");
72
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
73
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
74
+ if (y = 0, t) op = [
75
+ op[0] & 2,
76
+ t.value
77
+ ];
78
+ switch(op[0]){
79
+ case 0:
80
+ case 1:
81
+ t = op;
82
+ break;
83
+ case 4:
84
+ _.label++;
85
+ return {
86
+ value: op[1],
87
+ done: false
88
+ };
89
+ case 5:
90
+ _.label++;
91
+ y = op[1];
92
+ op = [
93
+ 0
94
+ ];
95
+ continue;
96
+ case 7:
97
+ op = _.ops.pop();
98
+ _.trys.pop();
99
+ continue;
100
+ default:
101
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
102
+ _ = 0;
103
+ continue;
104
+ }
105
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
106
+ _.label = op[1];
107
+ break;
108
+ }
109
+ if (op[0] === 6 && _.label < t[1]) {
110
+ _.label = t[1];
111
+ t = op;
112
+ break;
113
+ }
114
+ if (t && _.label < t[2]) {
115
+ _.label = t[2];
116
+ _.ops.push(op);
117
+ break;
118
+ }
119
+ if (t[2]) _.ops.pop();
120
+ _.trys.pop();
121
+ continue;
122
+ }
123
+ op = body.call(thisArg, _);
124
+ } catch (e) {
125
+ op = [
126
+ 6,
127
+ e
128
+ ];
129
+ y = 0;
130
+ } finally{
131
+ f = t = 0;
132
+ }
133
+ if (op[0] & 5) throw op[1];
134
+ return {
135
+ value: op[0] ? op[1] : void 0,
136
+ done: true
137
+ };
138
+ }
139
+ }
140
+ /**
141
+ * Creates an {@link AssetLoader} that reads local assets from the
142
+ * filesystem using Node.js `fs/promises`.
143
+ *
144
+ * The ref's {@link AssetLocalPathRef.path} is resolved relative
145
+ * to the configured {@link NodeJsLocalAssetLoaderConfig.basePath}.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * const loader = nodeJsLocalAssetLoader({ basePath: './assets' });
150
+ * loader.get(localAsset('data/districts.json')).load().subscribe((buffer) => {
151
+ * // reads from ./assets/data/districts.json
152
+ * });
153
+ * ```
154
+ *
155
+ * @param config - Filesystem configuration with base path.
156
+ */ function nodeJsLocalAssetLoader(config) {
157
+ var basePath = config.basePath;
158
+ var getFn = function getFn(ref) {
159
+ return _async_to_generator$1(function() {
160
+ var localRef, fullPath, buffer;
161
+ return _ts_generator$1(this, function(_state) {
162
+ switch(_state.label){
163
+ case 0:
164
+ localRef = ref;
165
+ fullPath = resolve(basePath, localRef.path);
166
+ return [
167
+ 4,
168
+ readFile(fullPath)
169
+ ];
170
+ case 1:
171
+ buffer = _state.sent();
172
+ return [
173
+ 2,
174
+ buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength)
175
+ ];
176
+ }
177
+ });
178
+ })();
179
+ };
180
+ return assetLoaderFromGetFn(getFn);
181
+ }
182
+
183
+ /**
184
+ * Creates NestJS module metadata that provides an {@link AssetLoader}
185
+ * using {@link delegatedAssetLoader} with Node.js-specific leaf loaders.
186
+ *
187
+ * Local assets are loaded from the filesystem. Remote assets (which always
188
+ * have absolute URLs) are loaded via `fetch`.
189
+ *
190
+ * @example
191
+ * ```ts
192
+ * @Module(appAssetLoaderModuleMetadata({
193
+ * local: { basePath: './assets' }
194
+ * }))
195
+ * export class AppAssetLoaderModule {}
196
+ * ```
197
+ *
198
+ * @param config - Local filesystem config and optional remote fetch config.
199
+ */ function appAssetLoaderModuleMetadata(config) {
200
+ var local = nodeJsLocalAssetLoader(config.local);
201
+ var remote = fetchAssetLoader(config.remote);
202
+ var loader = delegatedAssetLoader({
203
+ local: local,
204
+ remote: remote
205
+ });
206
+ var providers = [
207
+ {
208
+ provide: AssetLoader,
209
+ useValue: loader
210
+ }
211
+ ];
212
+ return {
213
+ providers: providers,
214
+ exports: [
215
+ AssetLoader
216
+ ]
217
+ };
218
+ }
219
+
9
220
  /**
10
221
  * Returns true if the request is from localhost.
11
222
  */ var IsRequestFromLocalHost = createParamDecorator(function(data, context) {
@@ -1092,4 +1303,4 @@ var ENCRYPTED_FIELD_KEY_LENGTH = 32;
1092
1303
  return result;
1093
1304
  }
1094
1305
 
1095
- export { AppModuleWithWebhooksEnabled, CLIENT_WEB_APP_URL_ENV_VAR, ClientAppModule, ClientAppService, ClientAppServiceConfig, ConfigureWebhookMiddlewareModule, DEFAULT_BASE_WEBHOOK_PATH, DEFAULT_WEBHOOK_MIDDLEWARE_ROUTE_INFO, IsRequestFromLocalHost, JsonBodyMiddleware, ParseRawBody, ParsedQueryRawBody, RawBody, RawBodyMiddleware, RawBodyToJson, RawBodyToParsedQueryString, RawBodyToString, SERVER_ENV_TOKEN, ServerEnvironmentConfig, ServerEnvironmentService, clientAppConfigFactory, consumeWebhooksWithRawBodyMiddleware, createAES256GCMEncryption, createAesStringEncryptionProvider, decryptValue, encryptValue, injectionTokensFromProviders, isLocalhost, isTestNodeEnv, isValidAES256GCMEncryptionSecret, mergeModuleMetadata, resolveEncryptionKey, serverEnvTokenProvider };
1306
+ export { AppModuleWithWebhooksEnabled, CLIENT_WEB_APP_URL_ENV_VAR, ClientAppModule, ClientAppService, ClientAppServiceConfig, ConfigureWebhookMiddlewareModule, DEFAULT_BASE_WEBHOOK_PATH, DEFAULT_WEBHOOK_MIDDLEWARE_ROUTE_INFO, IsRequestFromLocalHost, JsonBodyMiddleware, ParseRawBody, ParsedQueryRawBody, RawBody, RawBodyMiddleware, RawBodyToJson, RawBodyToParsedQueryString, RawBodyToString, SERVER_ENV_TOKEN, ServerEnvironmentConfig, ServerEnvironmentService, appAssetLoaderModuleMetadata, clientAppConfigFactory, consumeWebhooksWithRawBodyMiddleware, createAES256GCMEncryption, createAesStringEncryptionProvider, decryptValue, encryptValue, injectionTokensFromProviders, isLocalhost, isTestNodeEnv, isValidAES256GCMEncryptionSecret, mergeModuleMetadata, nodeJsLocalAssetLoader, resolveEncryptionKey, serverEnvTokenProvider };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/mailgun",
3
- "version": "13.6.8",
3
+ "version": "13.6.10",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.6.8",
6
- "@dereekb/model": "13.6.8",
7
- "@dereekb/nestjs": "13.6.8",
8
- "@dereekb/rxjs": "13.6.8",
9
- "@dereekb/util": "13.6.8",
5
+ "@dereekb/date": "13.6.10",
6
+ "@dereekb/model": "13.6.10",
7
+ "@dereekb/nestjs": "13.6.10",
8
+ "@dereekb/rxjs": "13.6.10",
9
+ "@dereekb/util": "13.6.10",
10
10
  "@nestjs/common": "^11.1.17",
11
11
  "@nestjs/config": "^4.0.3",
12
12
  "form-data": "^4.0.0",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/openai",
3
- "version": "13.6.8",
3
+ "version": "13.6.10",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.6.8",
6
- "@dereekb/model": "13.6.8",
7
- "@dereekb/nestjs": "13.6.8",
8
- "@dereekb/rxjs": "13.6.8",
9
- "@dereekb/util": "13.6.8",
5
+ "@dereekb/date": "13.6.10",
6
+ "@dereekb/model": "13.6.10",
7
+ "@dereekb/nestjs": "13.6.10",
8
+ "@dereekb/rxjs": "13.6.10",
9
+ "@dereekb/util": "13.6.10",
10
10
  "@nestjs/common": "^11.1.17",
11
11
  "@nestjs/config": "^4.0.3",
12
12
  "express": "^5.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs",
3
- "version": "13.6.8",
3
+ "version": "13.6.10",
4
4
  "types": "./src/index.d.ts",
5
5
  "module": "./index.esm.js",
6
6
  "main": "./index.cjs.js",
@@ -50,7 +50,8 @@
50
50
  }
51
51
  },
52
52
  "peerDependencies": {
53
- "@dereekb/util": "13.6.8",
53
+ "@dereekb/rxjs": "13.6.10",
54
+ "@dereekb/util": "13.6.10",
54
55
  "discord.js": "^14.25.1",
55
56
  "@nestjs/common": "^11.1.17",
56
57
  "@nestjs/config": "^4.0.3",
@@ -0,0 +1,31 @@
1
+ import { type SlashPath } from '@dereekb/util';
2
+ import { AssetLoader } from '@dereekb/rxjs';
3
+ /**
4
+ * Configuration for {@link nodeJsLocalAssetLoader}.
5
+ */
6
+ export interface NodeJsLocalAssetLoaderConfig {
7
+ /**
8
+ * Base filesystem directory for local assets.
9
+ *
10
+ * @example `'./assets'` or `'/app/dist/assets'`
11
+ */
12
+ readonly basePath: SlashPath;
13
+ }
14
+ /**
15
+ * Creates an {@link AssetLoader} that reads local assets from the
16
+ * filesystem using Node.js `fs/promises`.
17
+ *
18
+ * The ref's {@link AssetLocalPathRef.path} is resolved relative
19
+ * to the configured {@link NodeJsLocalAssetLoaderConfig.basePath}.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const loader = nodeJsLocalAssetLoader({ basePath: './assets' });
24
+ * loader.get(localAsset('data/districts.json')).load().subscribe((buffer) => {
25
+ * // reads from ./assets/data/districts.json
26
+ * });
27
+ * ```
28
+ *
29
+ * @param config - Filesystem configuration with base path.
30
+ */
31
+ export declare function nodeJsLocalAssetLoader(config: NodeJsLocalAssetLoaderConfig): AssetLoader;
@@ -0,0 +1,37 @@
1
+ import { type ModuleMetadata } from '@nestjs/common';
2
+ import { type FetchAssetLoaderConfig } from '@dereekb/rxjs';
3
+ import { type NodeJsLocalAssetLoaderConfig } from './asset.loader.node';
4
+ /**
5
+ * Configuration for {@link appAssetLoaderModuleMetadata}.
6
+ */
7
+ export interface AppAssetLoaderModuleMetadataConfig {
8
+ /**
9
+ * Filesystem config for local assets.
10
+ */
11
+ readonly local: NodeJsLocalAssetLoaderConfig;
12
+ /**
13
+ * Optional fetch config for remote assets (e.g., custom fetch function
14
+ * with pre-configured auth headers).
15
+ *
16
+ * If omitted, remote assets use the global `fetch`.
17
+ */
18
+ readonly remote?: FetchAssetLoaderConfig;
19
+ }
20
+ /**
21
+ * Creates NestJS module metadata that provides an {@link AssetLoader}
22
+ * using {@link delegatedAssetLoader} with Node.js-specific leaf loaders.
23
+ *
24
+ * Local assets are loaded from the filesystem. Remote assets (which always
25
+ * have absolute URLs) are loaded via `fetch`.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * @Module(appAssetLoaderModuleMetadata({
30
+ * local: { basePath: './assets' }
31
+ * }))
32
+ * export class AppAssetLoaderModule {}
33
+ * ```
34
+ *
35
+ * @param config - Local filesystem config and optional remote fetch config.
36
+ */
37
+ export declare function appAssetLoaderModuleMetadata(config: AppAssetLoaderModuleMetadataConfig): ModuleMetadata;
@@ -0,0 +1,2 @@
1
+ export * from './asset.loader.node';
2
+ export * from './asset.nest';
@@ -1,3 +1,4 @@
1
+ export * from './asset';
1
2
  export * from './decorators';
2
3
  export * from './middlewares';
3
4
  export * from './module';
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/stripe",
3
- "version": "13.6.8",
3
+ "version": "13.6.10",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.6.8",
6
- "@dereekb/model": "13.6.8",
7
- "@dereekb/nestjs": "13.6.8",
8
- "@dereekb/rxjs": "13.6.8",
9
- "@dereekb/util": "13.6.8",
5
+ "@dereekb/date": "13.6.10",
6
+ "@dereekb/model": "13.6.10",
7
+ "@dereekb/nestjs": "13.6.10",
8
+ "@dereekb/rxjs": "13.6.10",
9
+ "@dereekb/util": "13.6.10",
10
10
  "@nestjs/common": "^11.1.17",
11
11
  "@nestjs/config": "^4.0.3",
12
12
  "express": "^5.0.0",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/typeform",
3
- "version": "13.6.8",
3
+ "version": "13.6.10",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.6.8",
6
- "@dereekb/model": "13.6.8",
7
- "@dereekb/nestjs": "13.6.8",
8
- "@dereekb/rxjs": "13.6.8",
9
- "@dereekb/util": "13.6.8",
5
+ "@dereekb/date": "13.6.10",
6
+ "@dereekb/model": "13.6.10",
7
+ "@dereekb/nestjs": "13.6.10",
8
+ "@dereekb/rxjs": "13.6.10",
9
+ "@dereekb/util": "13.6.10",
10
10
  "@nestjs/common": "^11.1.17",
11
11
  "@nestjs/config": "^4.0.3",
12
12
  "@typeform/api-client": "^2.5.1",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/nestjs/vapiai",
3
- "version": "13.6.8",
3
+ "version": "13.6.10",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.6.8",
6
- "@dereekb/model": "13.6.8",
7
- "@dereekb/nestjs": "13.6.8",
8
- "@dereekb/rxjs": "13.6.8",
9
- "@dereekb/util": "13.6.8",
5
+ "@dereekb/date": "13.6.10",
6
+ "@dereekb/model": "13.6.10",
7
+ "@dereekb/nestjs": "13.6.10",
8
+ "@dereekb/rxjs": "13.6.10",
9
+ "@dereekb/util": "13.6.10",
10
10
  "@nestjs/common": "^11.1.17",
11
11
  "@nestjs/config": "^4.0.3",
12
12
  "@vapi-ai/server-sdk": "^0.11.0",