@scpxl/nodejs-framework 1.0.14 → 1.0.19
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/README.md +29 -0
- package/dist/api-requester/api-requester.d.ts +27 -6
- package/dist/api-requester/api-requester.d.ts.map +1 -1
- package/dist/api-requester/api-requester.js +188 -26
- package/dist/api-requester/api-requester.js.map +2 -2
- package/dist/api-requester/index.d.ts +1 -0
- package/dist/api-requester/index.d.ts.map +1 -1
- package/dist/api-requester/index.js.map +1 -1
- package/dist/application/base-application.d.ts +16 -20
- package/dist/application/base-application.d.ts.map +1 -1
- package/dist/application/base-application.js +152 -109
- package/dist/application/base-application.js.map +2 -2
- package/dist/application/command-application.d.ts.map +1 -1
- package/dist/application/command-application.js +3 -4
- package/dist/application/command-application.js.map +2 -2
- package/dist/application/web-application.d.ts.map +1 -1
- package/dist/application/web-application.js +9 -2
- package/dist/application/web-application.js.map +2 -2
- package/dist/cache/manager.d.ts +87 -6
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +77 -30
- package/dist/cache/manager.js.map +2 -2
- package/dist/cluster/cluster-manager.d.ts.map +1 -1
- package/dist/cluster/cluster-manager.js +7 -9
- package/dist/cluster/cluster-manager.js.map +2 -2
- package/dist/config/env.d.ts +11 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +103 -0
- package/dist/config/env.js.map +7 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +7 -0
- package/dist/config/schema.d.ts +408 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +218 -0
- package/dist/config/schema.js.map +7 -0
- package/dist/database/dynamic-entity.d.ts.map +1 -1
- package/dist/database/dynamic-entity.js +6 -2
- package/dist/database/dynamic-entity.js.map +2 -2
- package/dist/database/instance.d.ts.map +1 -1
- package/dist/database/instance.js +0 -8
- package/dist/database/instance.js.map +2 -2
- package/dist/database/manager.d.ts.map +1 -1
- package/dist/database/manager.js +71 -9
- package/dist/database/manager.js.map +2 -2
- package/dist/error/error-reporter.d.ts +96 -0
- package/dist/error/error-reporter.d.ts.map +1 -0
- package/dist/error/error-reporter.js +228 -0
- package/dist/error/error-reporter.js.map +7 -0
- package/dist/error/error.interface.d.ts +126 -0
- package/dist/error/error.interface.d.ts.map +1 -0
- package/dist/error/error.interface.js +45 -0
- package/dist/error/error.interface.js.map +7 -0
- package/dist/error/framework-errors.d.ts +113 -0
- package/dist/error/framework-errors.d.ts.map +1 -0
- package/dist/error/framework-errors.js +176 -0
- package/dist/error/framework-errors.js.map +7 -0
- package/dist/error/index.d.ts +6 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +34 -0
- package/dist/error/index.js.map +7 -0
- package/dist/event/manager.d.ts.map +1 -1
- package/dist/event/manager.js +2 -9
- package/dist/event/manager.js.map +2 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +2 -2
- package/dist/lifecycle/exit.d.ts +11 -0
- package/dist/lifecycle/exit.d.ts.map +1 -0
- package/dist/lifecycle/exit.js +29 -0
- package/dist/lifecycle/exit.js.map +7 -0
- package/dist/lifecycle/index.d.ts +7 -0
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/lifecycle/index.js +12 -0
- package/dist/lifecycle/index.js.map +7 -0
- package/dist/lifecycle/lifecycle-manager.d.ts +66 -0
- package/dist/lifecycle/lifecycle-manager.d.ts.map +1 -0
- package/dist/lifecycle/lifecycle-manager.js +280 -0
- package/dist/lifecycle/lifecycle-manager.js.map +7 -0
- package/dist/lifecycle/shutdown-controller.d.ts +15 -0
- package/dist/lifecycle/shutdown-controller.d.ts.map +1 -0
- package/dist/lifecycle/shutdown-controller.js +38 -0
- package/dist/lifecycle/shutdown-controller.js.map +7 -0
- package/dist/lifecycle/types.d.ts +28 -0
- package/dist/lifecycle/types.d.ts.map +1 -0
- package/dist/lifecycle/types.js +13 -0
- package/dist/lifecycle/types.js.map +7 -0
- package/dist/logger/logger.d.ts +2 -1
- package/dist/logger/logger.d.ts.map +1 -1
- package/dist/logger/logger.js +35 -11
- package/dist/logger/logger.js.map +2 -2
- package/dist/performance/cache-performance.d.ts +6 -0
- package/dist/performance/cache-performance.d.ts.map +1 -1
- package/dist/performance/cache-performance.js +16 -0
- package/dist/performance/cache-performance.js.map +2 -2
- package/dist/performance/index.d.ts +1 -0
- package/dist/performance/index.d.ts.map +1 -1
- package/dist/performance/index.js +1 -0
- package/dist/performance/index.js.map +2 -2
- package/dist/performance/performance-monitor.d.ts.map +1 -1
- package/dist/performance/performance-monitor.js +47 -18
- package/dist/performance/performance-monitor.js.map +2 -2
- package/dist/performance/performance-monitor.plugin.d.ts +24 -0
- package/dist/performance/performance-monitor.plugin.d.ts.map +1 -0
- package/dist/performance/performance-monitor.plugin.js +89 -0
- package/dist/performance/performance-monitor.plugin.js.map +7 -0
- package/dist/performance/webserver-performance.js +1 -1
- package/dist/performance/webserver-performance.js.map +2 -2
- package/dist/queue/manager.d.ts.map +1 -1
- package/dist/queue/manager.js +3 -10
- package/dist/queue/manager.js.map +2 -2
- package/dist/queue/worker.d.ts.map +1 -1
- package/dist/queue/worker.js +2 -2
- package/dist/queue/worker.js.map +2 -2
- package/dist/redis/manager.d.ts.map +1 -1
- package/dist/redis/manager.js +228 -33
- package/dist/redis/manager.js.map +2 -2
- package/dist/request-context/index.d.ts +3 -0
- package/dist/request-context/index.d.ts.map +1 -0
- package/dist/request-context/index.js +25 -0
- package/dist/request-context/index.js.map +7 -0
- package/dist/request-context/request-context.d.ts +108 -0
- package/dist/request-context/request-context.d.ts.map +1 -0
- package/dist/request-context/request-context.interface.d.ts +46 -0
- package/dist/request-context/request-context.interface.d.ts.map +1 -0
- package/dist/request-context/request-context.interface.js +1 -0
- package/dist/request-context/request-context.interface.js.map +7 -0
- package/dist/request-context/request-context.js +79 -0
- package/dist/request-context/request-context.js.map +7 -0
- package/dist/services/aws/s3.js +4 -6
- package/dist/services/aws/s3.js.map +2 -2
- package/dist/util/file.d.ts +13 -0
- package/dist/util/file.d.ts.map +1 -1
- package/dist/util/file.js +46 -9
- package/dist/util/file.js.map +2 -2
- package/dist/util/helper.d.ts +16 -1
- package/dist/util/helper.d.ts.map +1 -1
- package/dist/util/helper.js +19 -43
- package/dist/util/helper.js.map +2 -2
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.d.ts.map +1 -1
- package/dist/util/index.js +18 -16
- package/dist/util/index.js.map +2 -2
- package/dist/util/loader.d.ts.map +1 -1
- package/dist/util/loader.js +13 -2
- package/dist/util/loader.js.map +2 -2
- package/dist/util/os.d.ts.map +1 -1
- package/dist/util/os.js +8 -14
- package/dist/util/os.js.map +2 -2
- package/dist/util/time.d.ts +8 -2
- package/dist/util/time.d.ts.map +1 -1
- package/dist/util/time.js +12 -7
- package/dist/util/time.js.map +2 -2
- package/dist/util/timing.d.ts +36 -0
- package/dist/util/timing.d.ts.map +1 -0
- package/dist/util/timing.interface.d.ts +47 -0
- package/dist/util/timing.interface.d.ts.map +1 -0
- package/dist/util/timing.interface.js +1 -0
- package/dist/util/timing.interface.js.map +7 -0
- package/dist/util/timing.js +98 -0
- package/dist/util/timing.js.map +7 -0
- package/dist/util/url.js +1 -1
- package/dist/util/url.js.map +2 -2
- package/dist/webserver/controller/base.d.ts +3 -1
- package/dist/webserver/controller/base.d.ts.map +1 -1
- package/dist/webserver/controller/base.interface.d.ts +2 -0
- package/dist/webserver/controller/base.interface.d.ts.map +1 -1
- package/dist/webserver/controller/base.js +4 -1
- package/dist/webserver/controller/base.js.map +2 -2
- package/dist/webserver/controller/health.d.ts +8 -1
- package/dist/webserver/controller/health.d.ts.map +1 -1
- package/dist/webserver/controller/health.js +36 -22
- package/dist/webserver/controller/health.js.map +2 -2
- package/dist/webserver/webserver.d.ts +16 -2
- package/dist/webserver/webserver.d.ts.map +1 -1
- package/dist/webserver/webserver.interface.d.ts +37 -0
- package/dist/webserver/webserver.interface.d.ts.map +1 -1
- package/dist/webserver/webserver.interface.js.map +2 -2
- package/dist/webserver/webserver.js +117 -20
- package/dist/webserver/webserver.js.map +2 -2
- package/dist/websocket/controllers/server/system.d.ts.map +1 -1
- package/dist/websocket/controllers/server/system.js.map +2 -2
- package/dist/websocket/websocket-base.d.ts.map +1 -1
- package/dist/websocket/websocket-base.js +2 -3
- package/dist/websocket/websocket-base.js.map +2 -2
- package/dist/websocket/websocket-server.d.ts +1 -1
- package/dist/websocket/websocket-server.d.ts.map +1 -1
- package/dist/websocket/websocket-server.js +7 -31
- package/dist/websocket/websocket-server.js.map +2 -2
- package/package.json +68 -25
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/redis/manager.ts"],
|
|
4
|
-
"sourcesContent": ["import { Redis, type RedisOptions } from 'ioredis';\nimport type { RedisManagerConfig as RedisManagerOptions } from './manager.interface.js';\nimport RedisInstance from './instance.js';\nimport { Logger } from '../logger/index.js';\n\nexport default class RedisManager {\n private logger: typeof Logger = Logger;\n\n private options: RedisManagerOptions;\n\n public instances: RedisInstance[] = [];\n\n constructor(config: RedisManagerOptions) {\n this.options = config;\n }\n\n public connect(): Promise<RedisInstance> {\n return
|
|
5
|
-
"mappings": ";;AAAA,SAAS,aAAgC;
|
|
4
|
+
"sourcesContent": ["import { Redis, type RedisOptions } from 'ioredis';\nimport { EventEmitter } from 'node:events';\nimport type { RedisManagerConfig as RedisManagerOptions } from './manager.interface.js';\nimport RedisInstance from './instance.js';\nimport { Logger } from '../logger/index.js';\nimport { CachePerformanceWrapper } from '../performance/index.js';\n\nconst truthyPattern = /^(1|true|yes|on)$/i;\nconst scheduleMicrotask =\n typeof (globalThis as any).queueMicrotask === 'function'\n ? (globalThis as any).queueMicrotask.bind(globalThis)\n : (callback: () => void) => {\n void Promise.resolve().then(callback);\n };\n\ntype RedisCallback = (error: Error | null, result?: string) => void;\n\ninterface InMemoryRedisSharedState {\n store: Map<string, string | Buffer>;\n expirations: Map<string, NodeJS.Timeout>;\n subscriptions: Map<string, Set<InMemoryRedisClient>>;\n}\n\nclass InMemoryRedisClient extends EventEmitter {\n private shared: InMemoryRedisSharedState;\n\n constructor(shared: InMemoryRedisSharedState) {\n super();\n this.shared = shared;\n\n scheduleMicrotask(() => {\n this.emit('ready');\n });\n }\n\n private cleanupSubscriptions(): void {\n for (const subscribers of this.shared.subscriptions.values()) {\n subscribers.delete(this);\n }\n }\n\n private clearExpirationForKey(key: string): void {\n const timer = this.shared.expirations.get(key);\n if (timer) {\n clearTimeout(timer);\n this.shared.expirations.delete(key);\n }\n }\n\n public ping(callback?: RedisCallback): Promise<string> {\n if (callback) {\n callback(null, 'PONG');\n return Promise.resolve('PONG');\n }\n\n return Promise.resolve('PONG');\n }\n\n public async set(...args: any[]): Promise<'OK'> {\n const [key, value, mode, expiration] = args;\n const serializedValue: string | Buffer = value instanceof Buffer ? value : String(value);\n\n this.shared.store.set(key, serializedValue);\n this.clearExpirationForKey(key);\n\n if (typeof mode === 'string' && mode.toUpperCase() === 'EX' && typeof expiration === 'number') {\n const timer = setTimeout(() => {\n this.shared.store.delete(key);\n this.shared.expirations.delete(key);\n }, expiration * 1000);\n\n if (typeof timer.unref === 'function') {\n timer.unref();\n }\n\n this.shared.expirations.set(key, timer);\n }\n\n return 'OK';\n }\n\n public async get(key: string): Promise<string | null> {\n return (this.shared.store.get(key) as string | undefined) ?? null;\n }\n\n public async del(key: string): Promise<number> {\n const existed = this.shared.store.delete(key);\n this.clearExpirationForKey(key);\n return existed ? 1 : 0;\n }\n\n public async publish(channel: string, message: string): Promise<number> {\n const subscribers = this.shared.subscriptions.get(channel);\n\n if (!subscribers || subscribers.size === 0) {\n return 0;\n }\n\n for (const subscriber of subscribers) {\n scheduleMicrotask(() => {\n subscriber.emit('message', channel, message);\n });\n }\n\n return subscribers.size;\n }\n\n public async subscribe(channel: string): Promise<number> {\n let subscribers = this.shared.subscriptions.get(channel);\n if (!subscribers) {\n subscribers = new Set<InMemoryRedisClient>();\n this.shared.subscriptions.set(channel, subscribers);\n }\n subscribers.add(this);\n return subscribers.size;\n }\n\n public async unsubscribe(channel: string): Promise<number> {\n const subscribers = this.shared.subscriptions.get(channel);\n\n if (!subscribers) {\n return 0;\n }\n\n subscribers.delete(this);\n return subscribers.size;\n }\n\n public async quit(): Promise<'OK'> {\n this.cleanupSubscriptions();\n this.removeAllListeners();\n this.emit('end');\n return 'OK';\n }\n\n public disconnect(): void {\n this.cleanupSubscriptions();\n this.removeAllListeners();\n this.emit('end');\n }\n}\n\nexport default class RedisManager {\n private logger: typeof Logger = Logger;\n\n private options: RedisManagerOptions;\n\n public instances: RedisInstance[] = [];\n\n constructor(config: RedisManagerOptions) {\n this.options = config;\n }\n\n public async connect(): Promise<RedisInstance> {\n return CachePerformanceWrapper.monitorConnection(\n 'connect',\n async () => {\n const startTime = performance.now();\n\n const redisOptions: RedisOptions = {\n host: this.options.host,\n port: this.options.port,\n password: this.options.password,\n maxRetriesPerRequest: null, // Needed for bullmq\n };\n\n const useInMemoryRedis =\n truthyPattern.test(process.env.PXL_REDIS_IN_MEMORY ?? '') ||\n truthyPattern.test(process.env.REDIS_IN_MEMORY ?? '');\n\n let sharedState: InMemoryRedisSharedState | undefined;\n if (useInMemoryRedis) {\n sharedState = {\n store: new Map<string, string | Buffer>(),\n expirations: new Map<string, NodeJS.Timeout>(),\n subscriptions: new Map<string, Set<InMemoryRedisClient>>(),\n };\n }\n\n const createClient = (): Redis => {\n if (useInMemoryRedis) {\n if (!sharedState) {\n throw new Error('In-memory Redis shared state not initialized');\n }\n return new InMemoryRedisClient(sharedState) as unknown as Redis;\n }\n\n return new Redis(redisOptions);\n };\n\n const client = createClient();\n const publisherClient = createClient();\n const subscriberClient = createClient();\n\n try {\n // Wait for all three clients to be ready\n await Promise.all([\n new Promise<void>((resolve, reject) => {\n client.once('ready', () => resolve());\n client.once('error', (error: Error) => reject(error));\n }),\n new Promise<void>((resolve, reject) => {\n publisherClient.once('ready', () => resolve());\n publisherClient.once('error', (error: Error) => reject(error));\n }),\n new Promise<void>((resolve, reject) => {\n subscriberClient.once('ready', () => resolve());\n subscriberClient.once('error', (error: Error) => reject(error));\n }),\n ]);\n\n const redisInstance = new RedisInstance({\n redisManager: this,\n client,\n publisherClient,\n subscriberClient,\n });\n\n this.instances.push(redisInstance);\n\n const duration = performance.now() - startTime;\n const meta = {\n Host: this.options.host,\n Port: this.options.port,\n Duration: `${duration.toFixed(2)}ms`,\n Mode: useInMemoryRedis ? 'in-memory' : 'network',\n };\n\n if (this.options.applicationConfig.log?.startUp) {\n this.log('Connected', meta);\n } else {\n this.logger.debug({ message: 'Redis connected', meta });\n }\n\n if (useInMemoryRedis) {\n this.logger.debug({ message: 'Using in-memory Redis stub' });\n }\n\n return redisInstance;\n } catch (error) {\n const duration = performance.now() - startTime;\n\n // Clean up clients on error\n await Promise.allSettled([client.quit(), publisherClient.quit(), subscriberClient.quit()]);\n\n this.logger.error({\n error: error instanceof Error ? error : new Error(String(error)),\n message: 'Redis connection failed',\n meta: {\n Host: this.options.host,\n Port: this.options.port,\n Duration: `${duration.toFixed(2)}ms`,\n Mode: useInMemoryRedis ? 'in-memory' : 'network',\n },\n });\n\n throw error;\n }\n },\n { host: this.options.host, port: this.options.port },\n );\n }\n\n public async disconnect(): Promise<void> {\n await CachePerformanceWrapper.monitorConnection(\n 'disconnect',\n async () => {\n const startTime = performance.now();\n const instanceCount = this.instances.length;\n\n try {\n await Promise.all(this.instances.map(instance => instance.disconnect()));\n\n const duration = performance.now() - startTime;\n\n if (instanceCount > 0) {\n const meta = {\n Instances: instanceCount,\n Host: this.options.host,\n Port: this.options.port,\n Duration: `${duration.toFixed(2)}ms`,\n };\n\n if (this.options.applicationConfig.log?.startUp) {\n this.log('Disconnected all Redis instances', meta);\n } else {\n this.logger.debug({ message: 'Redis instances disconnected', meta });\n }\n }\n\n this.instances = [];\n } catch (error) {\n const duration = performance.now() - startTime;\n\n this.logger.error({\n error: error instanceof Error ? error : new Error(String(error)),\n message: 'Redis disconnection failed',\n meta: {\n Host: this.options.host,\n Port: this.options.port,\n Instances: instanceCount,\n Duration: `${duration.toFixed(2)}ms`,\n },\n });\n\n throw error;\n }\n },\n { host: this.options.host, port: this.options.port },\n );\n }\n\n /**\n * Log Redis message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'redis', message, meta });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { RequestContext, RunWithContextOptions } from './request-context.interface.js';
|
|
2
|
+
export { getRequestContext, getRequestId, getUserId, setUserId, getContextMetadata, setContextMetadata, runWithContext, runWithContextAsync, enterRequestContext, requestContextStorage, } from './request-context.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/request-context/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,SAAS,EACT,SAAS,EACT,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getRequestContext,
|
|
3
|
+
getRequestId,
|
|
4
|
+
getUserId,
|
|
5
|
+
setUserId,
|
|
6
|
+
getContextMetadata,
|
|
7
|
+
setContextMetadata,
|
|
8
|
+
runWithContext,
|
|
9
|
+
runWithContextAsync,
|
|
10
|
+
enterRequestContext,
|
|
11
|
+
requestContextStorage
|
|
12
|
+
} from "./request-context.js";
|
|
13
|
+
export {
|
|
14
|
+
enterRequestContext,
|
|
15
|
+
getContextMetadata,
|
|
16
|
+
getRequestContext,
|
|
17
|
+
getRequestId,
|
|
18
|
+
getUserId,
|
|
19
|
+
requestContextStorage,
|
|
20
|
+
runWithContext,
|
|
21
|
+
runWithContextAsync,
|
|
22
|
+
setContextMetadata,
|
|
23
|
+
setUserId
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/request-context/index.ts"],
|
|
4
|
+
"sourcesContent": ["export type { RequestContext, RunWithContextOptions } from './request-context.interface.js';\nexport {\n getRequestContext,\n getRequestId,\n getUserId,\n setUserId,\n getContextMetadata,\n setContextMetadata,\n runWithContext,\n runWithContextAsync,\n enterRequestContext,\n requestContextStorage,\n} from './request-context.js';\n"],
|
|
5
|
+
"mappings": "AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import type { RequestContext, RunWithContextOptions } from './request-context.interface.js';
|
|
3
|
+
/**
|
|
4
|
+
* AsyncLocalStorage instance for request context
|
|
5
|
+
*
|
|
6
|
+
* This provides request-scoped storage that automatically propagates through
|
|
7
|
+
* async operations, enabling correlation IDs and request metadata to be
|
|
8
|
+
* accessible throughout the request lifecycle without explicit passing.
|
|
9
|
+
*/
|
|
10
|
+
declare const requestContextStorage: AsyncLocalStorage<RequestContext>;
|
|
11
|
+
/**
|
|
12
|
+
* Get the current request context
|
|
13
|
+
*
|
|
14
|
+
* @returns The current request context, or undefined if not in a request context
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const context = getRequestContext();
|
|
18
|
+
* if (context) {
|
|
19
|
+
* console.log('Request ID:', context.requestId);
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export declare function getRequestContext(): RequestContext | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Get the current request ID
|
|
25
|
+
*
|
|
26
|
+
* @returns The current request ID, or undefined if not in a request context
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const requestId = getRequestId();
|
|
30
|
+
* logger.info({ message: 'Processing request', requestId });
|
|
31
|
+
*/
|
|
32
|
+
export declare function getRequestId(): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Set metadata in the current request context
|
|
35
|
+
*
|
|
36
|
+
* @param key - Metadata key
|
|
37
|
+
* @param value - Metadata value
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* setContextMetadata('operation', 'userLookup');
|
|
41
|
+
* setContextMetadata('cacheHit', true);
|
|
42
|
+
*/
|
|
43
|
+
export declare function setContextMetadata(key: string, value: unknown): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get metadata from the current request context
|
|
46
|
+
*
|
|
47
|
+
* @param key - Metadata key
|
|
48
|
+
* @returns Metadata value, or undefined if not found
|
|
49
|
+
*/
|
|
50
|
+
export declare function getContextMetadata(key: string): unknown;
|
|
51
|
+
/**
|
|
52
|
+
* Run a function within a new request context
|
|
53
|
+
*
|
|
54
|
+
* @param options - Context options (requestId will be generated if not provided)
|
|
55
|
+
* @param fn - Function to run within the context
|
|
56
|
+
* @returns The result of the function
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* await runWithContext({ requestId: 'custom-id' }, async () => {
|
|
60
|
+
* await processRequest();
|
|
61
|
+
* });
|
|
62
|
+
*/
|
|
63
|
+
export declare function runWithContext<T>(options: RunWithContextOptions | undefined, fn: () => T): T;
|
|
64
|
+
/**
|
|
65
|
+
* Run a function within a new request context (async version)
|
|
66
|
+
*
|
|
67
|
+
* @param options - Context options (requestId will be generated if not provided)
|
|
68
|
+
* @param fn - Async function to run within the context
|
|
69
|
+
* @returns Promise resolving to the result of the function
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* await runWithContextAsync({ requestId: 'custom-id' }, async () => {
|
|
73
|
+
* await processRequest();
|
|
74
|
+
* });
|
|
75
|
+
*/
|
|
76
|
+
export declare function runWithContextAsync<T>(options: RunWithContextOptions | undefined, fn: () => Promise<T>): Promise<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Update the user ID in the current request context
|
|
79
|
+
*
|
|
80
|
+
* @param userId - User ID to set
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* // After authentication
|
|
84
|
+
* setUserId(authenticatedUser.id);
|
|
85
|
+
*/
|
|
86
|
+
export declare function setUserId(userId: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* Get the user ID from the current request context
|
|
89
|
+
*
|
|
90
|
+
* @returns The current user ID, or undefined if not set
|
|
91
|
+
*/
|
|
92
|
+
export declare function getUserId(): string | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Enter a new request context (advanced usage for middleware)
|
|
95
|
+
*
|
|
96
|
+
* This sets the context for the current async execution context without
|
|
97
|
+
* wrapping in a callback. Use with caution - prefer runWithContext when possible.
|
|
98
|
+
*
|
|
99
|
+
* @param options - Context options
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* // In Fastify middleware
|
|
103
|
+
* const requestId = req.headers['x-request-id'] || crypto.randomUUID();
|
|
104
|
+
* enterRequestContext({ requestId });
|
|
105
|
+
*/
|
|
106
|
+
export declare function enterRequestContext(options: RunWithContextOptions): void;
|
|
107
|
+
export { requestContextStorage };
|
|
108
|
+
//# sourceMappingURL=request-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/request-context/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5F;;;;;;GAMG;AACH,QAAA,MAAM,qBAAqB,mCAA0C,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAEjD;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAOpE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,qBAAqB,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAS5F;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,OAAO,EAAE,qBAAqB,GAAG,SAAS,EAC1C,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CASZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAK9C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CASxE;AAGD,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request context interface
|
|
3
|
+
*
|
|
4
|
+
* This interface defines the shape of the context stored in AsyncLocalStorage
|
|
5
|
+
* for each HTTP request, providing correlation IDs and request metadata.
|
|
6
|
+
*/
|
|
7
|
+
export interface RequestContext {
|
|
8
|
+
/**
|
|
9
|
+
* Unique request ID (UUID v4/v7) for tracing/correlation
|
|
10
|
+
*/
|
|
11
|
+
requestId: string;
|
|
12
|
+
/**
|
|
13
|
+
* Request start time (performance.now() timestamp)
|
|
14
|
+
*/
|
|
15
|
+
startTime?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Authenticated user ID (if available)
|
|
18
|
+
*/
|
|
19
|
+
userId?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Additional custom metadata
|
|
22
|
+
*/
|
|
23
|
+
metadata?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Options for running code within a request context
|
|
27
|
+
*/
|
|
28
|
+
export interface RunWithContextOptions {
|
|
29
|
+
/**
|
|
30
|
+
* Request ID to use (generated if not provided)
|
|
31
|
+
*/
|
|
32
|
+
requestId?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Request start time
|
|
35
|
+
*/
|
|
36
|
+
startTime?: number;
|
|
37
|
+
/**
|
|
38
|
+
* User ID
|
|
39
|
+
*/
|
|
40
|
+
userId?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Additional metadata
|
|
43
|
+
*/
|
|
44
|
+
metadata?: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=request-context.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-context.interface.d.ts","sourceRoot":"","sources":["../../src/request-context/request-context.interface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=request-context.interface.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
+
import crypto from "node:crypto";
|
|
5
|
+
const requestContextStorage = new AsyncLocalStorage();
|
|
6
|
+
function getRequestContext() {
|
|
7
|
+
return requestContextStorage.getStore();
|
|
8
|
+
}
|
|
9
|
+
__name(getRequestContext, "getRequestContext");
|
|
10
|
+
function getRequestId() {
|
|
11
|
+
return requestContextStorage.getStore()?.requestId;
|
|
12
|
+
}
|
|
13
|
+
__name(getRequestId, "getRequestId");
|
|
14
|
+
function setContextMetadata(key, value) {
|
|
15
|
+
const context = requestContextStorage.getStore();
|
|
16
|
+
if (context) {
|
|
17
|
+
context.metadata ??= {};
|
|
18
|
+
context.metadata[key] = value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
__name(setContextMetadata, "setContextMetadata");
|
|
22
|
+
function getContextMetadata(key) {
|
|
23
|
+
return requestContextStorage.getStore()?.metadata?.[key];
|
|
24
|
+
}
|
|
25
|
+
__name(getContextMetadata, "getContextMetadata");
|
|
26
|
+
function runWithContext(options, fn) {
|
|
27
|
+
const context = {
|
|
28
|
+
requestId: options?.requestId ?? crypto.randomUUID(),
|
|
29
|
+
startTime: options?.startTime,
|
|
30
|
+
userId: options?.userId,
|
|
31
|
+
metadata: options?.metadata
|
|
32
|
+
};
|
|
33
|
+
return requestContextStorage.run(context, fn);
|
|
34
|
+
}
|
|
35
|
+
__name(runWithContext, "runWithContext");
|
|
36
|
+
async function runWithContextAsync(options, fn) {
|
|
37
|
+
const context = {
|
|
38
|
+
requestId: options?.requestId ?? crypto.randomUUID(),
|
|
39
|
+
startTime: options?.startTime,
|
|
40
|
+
userId: options?.userId,
|
|
41
|
+
metadata: options?.metadata
|
|
42
|
+
};
|
|
43
|
+
return requestContextStorage.run(context, fn);
|
|
44
|
+
}
|
|
45
|
+
__name(runWithContextAsync, "runWithContextAsync");
|
|
46
|
+
function setUserId(userId) {
|
|
47
|
+
const context = requestContextStorage.getStore();
|
|
48
|
+
if (context) {
|
|
49
|
+
context.userId = userId;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
__name(setUserId, "setUserId");
|
|
53
|
+
function getUserId() {
|
|
54
|
+
return requestContextStorage.getStore()?.userId;
|
|
55
|
+
}
|
|
56
|
+
__name(getUserId, "getUserId");
|
|
57
|
+
function enterRequestContext(options) {
|
|
58
|
+
const context = {
|
|
59
|
+
requestId: options?.requestId ?? crypto.randomUUID(),
|
|
60
|
+
startTime: options?.startTime,
|
|
61
|
+
userId: options?.userId,
|
|
62
|
+
metadata: options?.metadata
|
|
63
|
+
};
|
|
64
|
+
requestContextStorage.enterWith(context);
|
|
65
|
+
}
|
|
66
|
+
__name(enterRequestContext, "enterRequestContext");
|
|
67
|
+
export {
|
|
68
|
+
enterRequestContext,
|
|
69
|
+
getContextMetadata,
|
|
70
|
+
getRequestContext,
|
|
71
|
+
getRequestId,
|
|
72
|
+
getUserId,
|
|
73
|
+
requestContextStorage,
|
|
74
|
+
runWithContext,
|
|
75
|
+
runWithContextAsync,
|
|
76
|
+
setContextMetadata,
|
|
77
|
+
setUserId
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=request-context.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/request-context/request-context.ts"],
|
|
4
|
+
"sourcesContent": ["import { AsyncLocalStorage } from 'node:async_hooks';\nimport crypto from 'node:crypto';\nimport type { RequestContext, RunWithContextOptions } from './request-context.interface.js';\n\n/**\n * AsyncLocalStorage instance for request context\n *\n * This provides request-scoped storage that automatically propagates through\n * async operations, enabling correlation IDs and request metadata to be\n * accessible throughout the request lifecycle without explicit passing.\n */\nconst requestContextStorage = new AsyncLocalStorage<RequestContext>();\n\n/**\n * Get the current request context\n *\n * @returns The current request context, or undefined if not in a request context\n *\n * @example\n * const context = getRequestContext();\n * if (context) {\n * console.log('Request ID:', context.requestId);\n * }\n */\nexport function getRequestContext(): RequestContext | undefined {\n return requestContextStorage.getStore();\n}\n\n/**\n * Get the current request ID\n *\n * @returns The current request ID, or undefined if not in a request context\n *\n * @example\n * const requestId = getRequestId();\n * logger.info({ message: 'Processing request', requestId });\n */\nexport function getRequestId(): string | undefined {\n return requestContextStorage.getStore()?.requestId;\n}\n\n/**\n * Set metadata in the current request context\n *\n * @param key - Metadata key\n * @param value - Metadata value\n *\n * @example\n * setContextMetadata('operation', 'userLookup');\n * setContextMetadata('cacheHit', true);\n */\nexport function setContextMetadata(key: string, value: unknown): void {\n const context = requestContextStorage.getStore();\n if (context) {\n context.metadata ??= {};\n // eslint-disable-next-line security/detect-object-injection\n context.metadata[key] = value;\n }\n}\n\n/**\n * Get metadata from the current request context\n *\n * @param key - Metadata key\n * @returns Metadata value, or undefined if not found\n */\nexport function getContextMetadata(key: string): unknown {\n // eslint-disable-next-line security/detect-object-injection\n return requestContextStorage.getStore()?.metadata?.[key];\n}\n\n/**\n * Run a function within a new request context\n *\n * @param options - Context options (requestId will be generated if not provided)\n * @param fn - Function to run within the context\n * @returns The result of the function\n *\n * @example\n * await runWithContext({ requestId: 'custom-id' }, async () => {\n * await processRequest();\n * });\n */\nexport function runWithContext<T>(options: RunWithContextOptions | undefined, fn: () => T): T {\n const context: RequestContext = {\n requestId: options?.requestId ?? crypto.randomUUID(),\n startTime: options?.startTime,\n userId: options?.userId,\n metadata: options?.metadata,\n };\n\n return requestContextStorage.run(context, fn);\n}\n\n/**\n * Run a function within a new request context (async version)\n *\n * @param options - Context options (requestId will be generated if not provided)\n * @param fn - Async function to run within the context\n * @returns Promise resolving to the result of the function\n *\n * @example\n * await runWithContextAsync({ requestId: 'custom-id' }, async () => {\n * await processRequest();\n * });\n */\nexport async function runWithContextAsync<T>(\n options: RunWithContextOptions | undefined,\n fn: () => Promise<T>,\n): Promise<T> {\n const context: RequestContext = {\n requestId: options?.requestId ?? crypto.randomUUID(),\n startTime: options?.startTime,\n userId: options?.userId,\n metadata: options?.metadata,\n };\n\n return requestContextStorage.run(context, fn);\n}\n\n/**\n * Update the user ID in the current request context\n *\n * @param userId - User ID to set\n *\n * @example\n * // After authentication\n * setUserId(authenticatedUser.id);\n */\nexport function setUserId(userId: string): void {\n const context = requestContextStorage.getStore();\n if (context) {\n context.userId = userId;\n }\n}\n\n/**\n * Get the user ID from the current request context\n *\n * @returns The current user ID, or undefined if not set\n */\nexport function getUserId(): string | undefined {\n return requestContextStorage.getStore()?.userId;\n}\n\n/**\n * Enter a new request context (advanced usage for middleware)\n *\n * This sets the context for the current async execution context without\n * wrapping in a callback. Use with caution - prefer runWithContext when possible.\n *\n * @param options - Context options\n *\n * @example\n * // In Fastify middleware\n * const requestId = req.headers['x-request-id'] || crypto.randomUUID();\n * enterRequestContext({ requestId });\n */\nexport function enterRequestContext(options: RunWithContextOptions): void {\n const context: RequestContext = {\n requestId: options?.requestId ?? crypto.randomUUID(),\n startTime: options?.startTime,\n userId: options?.userId,\n metadata: options?.metadata,\n };\n\n requestContextStorage.enterWith(context);\n}\n\n// Export the storage instance for advanced usage (e.g., middleware)\nexport { requestContextStorage };\n"],
|
|
5
|
+
"mappings": ";;AAAA,SAAS,yBAAyB;AAClC,OAAO,YAAY;AAUnB,MAAM,wBAAwB,IAAI,kBAAkC;AAa7D,SAAS,oBAAgD;AAC9D,SAAO,sBAAsB,SAAS;AACxC;AAFgB;AAaT,SAAS,eAAmC;AACjD,SAAO,sBAAsB,SAAS,GAAG;AAC3C;AAFgB;AAcT,SAAS,mBAAmB,KAAa,OAAsB;AACpE,QAAM,UAAU,sBAAsB,SAAS;AAC/C,MAAI,SAAS;AACX,YAAQ,aAAa,CAAC;AAEtB,YAAQ,SAAS,GAAG,IAAI;AAAA,EAC1B;AACF;AAPgB;AAeT,SAAS,mBAAmB,KAAsB;AAEvD,SAAO,sBAAsB,SAAS,GAAG,WAAW,GAAG;AACzD;AAHgB;AAiBT,SAAS,eAAkB,SAA4C,IAAgB;AAC5F,QAAM,UAA0B;AAAA,IAC9B,WAAW,SAAS,aAAa,OAAO,WAAW;AAAA,IACnD,WAAW,SAAS;AAAA,IACpB,QAAQ,SAAS;AAAA,IACjB,UAAU,SAAS;AAAA,EACrB;AAEA,SAAO,sBAAsB,IAAI,SAAS,EAAE;AAC9C;AATgB;AAuBhB,eAAsB,oBACpB,SACA,IACY;AACZ,QAAM,UAA0B;AAAA,IAC9B,WAAW,SAAS,aAAa,OAAO,WAAW;AAAA,IACnD,WAAW,SAAS;AAAA,IACpB,QAAQ,SAAS;AAAA,IACjB,UAAU,SAAS;AAAA,EACrB;AAEA,SAAO,sBAAsB,IAAI,SAAS,EAAE;AAC9C;AAZsB;AAuBf,SAAS,UAAU,QAAsB;AAC9C,QAAM,UAAU,sBAAsB,SAAS;AAC/C,MAAI,SAAS;AACX,YAAQ,SAAS;AAAA,EACnB;AACF;AALgB;AAYT,SAAS,YAAgC;AAC9C,SAAO,sBAAsB,SAAS,GAAG;AAC3C;AAFgB;AAiBT,SAAS,oBAAoB,SAAsC;AACxE,QAAM,UAA0B;AAAA,IAC9B,WAAW,SAAS,aAAa,OAAO,WAAW;AAAA,IACnD,WAAW,SAAS;AAAA,IACpB,QAAQ,SAAS;AAAA,IACjB,UAAU,SAAS;AAAA,EACrB;AAEA,wBAAsB,UAAU,OAAO;AACzC;AATgB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/services/aws/s3.js
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
UploadPartCommand
|
|
10
10
|
} from "@aws-sdk/client-s3";
|
|
11
11
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
12
|
-
import { Helper } from "../../util/index.js";
|
|
13
|
-
import { createWriteStream
|
|
12
|
+
import { File, Helper } from "../../util/index.js";
|
|
13
|
+
import { createWriteStream } from "fs";
|
|
14
14
|
import { Readable, pipeline } from "stream";
|
|
15
15
|
import { promisify } from "node:util";
|
|
16
16
|
import { Logger } from "../../logger/index.js";
|
|
@@ -173,9 +173,7 @@ class AwsS3 {
|
|
|
173
173
|
onStart();
|
|
174
174
|
}
|
|
175
175
|
const directoryPath = dirname(destinationFilePath);
|
|
176
|
-
|
|
177
|
-
mkdirSync(directoryPath, { recursive: true });
|
|
178
|
-
}
|
|
176
|
+
await File.ensureDir(directoryPath);
|
|
179
177
|
const fileStream = createWriteStream(destinationFilePath);
|
|
180
178
|
const totalSize = parseInt(response.ContentLength?.toString() ?? "0", 10);
|
|
181
179
|
let bytesRead = 0;
|
|
@@ -188,7 +186,7 @@ class AwsS3 {
|
|
|
188
186
|
}
|
|
189
187
|
});
|
|
190
188
|
await asyncPipeline(response.Body, fileStream);
|
|
191
|
-
if (!
|
|
189
|
+
if (!await File.pathExists(destinationFilePath)) {
|
|
192
190
|
throw new Error(`Could not find downloaded file at ${destinationFilePath}`);
|
|
193
191
|
}
|
|
194
192
|
Logger.info({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/services/aws/s3.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n CompleteMultipartUploadCommand,\n CreateMultipartUploadCommand,\n GetObjectCommand,\n PutObjectCommand,\n type PutObjectCommandInput,\n S3Client,\n type S3ClientConfig,\n UploadPartCommand,\n} from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { Helper } from '../../util/index.js';\nimport type { AwsS3ConstructorOptions } from './s3.interface.js';\nimport { createWriteStream
|
|
5
|
-
"mappings": ";;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,cAAc;
|
|
4
|
+
"sourcesContent": ["import {\n CompleteMultipartUploadCommand,\n CreateMultipartUploadCommand,\n GetObjectCommand,\n PutObjectCommand,\n type PutObjectCommandInput,\n S3Client,\n type S3ClientConfig,\n UploadPartCommand,\n} from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { File, Helper } from '../../util/index.js';\nimport type { AwsS3ConstructorOptions } from './s3.interface.js';\nimport { createWriteStream } from 'fs';\nimport { Readable, pipeline } from 'stream';\nimport { promisify } from 'node:util';\nimport { Logger } from '../../logger/index.js';\nimport { dirname } from 'path';\n\nconst asyncPipeline = promisify(pipeline);\n\ninterface DownloadFileOptions {\n bucketName: string;\n key: string;\n destinationFilePath: string;\n}\n\nexport default class AwsS3 {\n public client: S3Client;\n\n private options: AwsS3ConstructorOptions;\n\n constructor(options: Partial<AwsS3ConstructorOptions>) {\n // Define default options\n const defaultOptions: Partial<AwsS3ConstructorOptions> = {\n region: 'us-east-1',\n localstack: {\n enabled: false,\n port: 4566,\n },\n };\n\n this.options = Helper.defaultsDeep(options, defaultOptions);\n\n const s3ClientConfig: S3ClientConfig = {\n region: this.options.region,\n };\n\n if (this.options.localstack.enabled) {\n s3ClientConfig.forcePathStyle = true;\n\n if (!this.options.endpoint) {\n throw new Error('Endpoint is required when using LocalStack');\n }\n\n // s3ClientConfig.endpoint = `http://s3.localhost.localstack.cloud:${this.options.localstack.port}`; // Works when the Node.js API is calling from within the Docker container\n // s3ClientConfig.endpoint = `http://localhost:${this.options.localstack.port}`; // works out side of the container (media generator example)\n\n s3ClientConfig.endpoint = this.options.endpoint;\n\n s3ClientConfig.credentials = {\n accessKeyId: 'test',\n secretAccessKey: 'test',\n };\n } else {\n if (this.options.credentials?.accessKeyId && this.options.credentials?.secretAccessKey) {\n s3ClientConfig.credentials = {\n accessKeyId: this.options.credentials.accessKeyId,\n secretAccessKey: this.options.credentials.secretAccessKey,\n };\n }\n }\n\n this.client = new S3Client(s3ClientConfig);\n }\n\n private getBucketUrl({ bucketName, path }: { bucketName: string; path: string }) {\n let url;\n\n if (this.options.localstack.enabled) {\n url = `http://localhost:${this.options.localstack.port}/${bucketName}/${path}`;\n } else {\n url = `https://${bucketName}.s3.amazonaws.com/${path}`;\n }\n\n return url;\n }\n\n public async uploadFile({\n bucketName,\n path,\n body,\n contentType,\n forceDownload,\n publicRead,\n }: {\n bucketName: string;\n path: string;\n body: Buffer;\n contentType?: string;\n forceDownload?: boolean;\n publicRead?: boolean;\n }): Promise<string> {\n let contentDisposition = forceDownload ? 'attachment' : 'inline';\n contentDisposition += `; filename=\"${path.split('/').pop()}\"`;\n\n const putObjectOptions: PutObjectCommandInput = {\n Bucket: bucketName,\n Key: path,\n Body: body,\n ContentDisposition: contentDisposition,\n ACL: publicRead ? 'public-read' : 'private',\n };\n\n if (contentType) {\n putObjectOptions.ContentType = contentType;\n }\n\n const command = new PutObjectCommand(putObjectOptions);\n\n await this.client.send(command);\n\n return this.getBucketUrl({ bucketName, path });\n }\n\n public async startMultipartUpload({\n bucketName,\n path,\n publicRead,\n }: {\n bucketName: string;\n path: string;\n publicRead?: boolean;\n }) {\n const command = new CreateMultipartUploadCommand({\n Bucket: bucketName,\n Key: path,\n ACL: publicRead ? 'public-read' : 'private',\n });\n\n const response = await this.client.send(command);\n\n return response.UploadId;\n }\n\n public async uploadPart({\n bucketName,\n path,\n partNumber,\n uploadId,\n body,\n }: {\n bucketName: string;\n path: string;\n partNumber: number;\n uploadId: string;\n body: any;\n }): Promise<string | undefined> {\n const command = new UploadPartCommand({\n Bucket: bucketName,\n Key: path,\n PartNumber: partNumber,\n UploadId: uploadId,\n Body: body,\n });\n\n const response = await this.client.send(command);\n\n return response.ETag;\n }\n\n public async completeMultipartUpload({\n bucketName,\n path,\n uploadId,\n parts,\n }: {\n bucketName: string;\n path: string;\n uploadId: string;\n parts: { PartNumber: number; ETag: string }[];\n }) {\n // Sort parts by PartNumber\n parts.sort((a, b) => a.PartNumber - b.PartNumber);\n\n const command = new CompleteMultipartUploadCommand({\n Bucket: bucketName,\n Key: path,\n UploadId: uploadId,\n MultipartUpload: {\n Parts: parts,\n },\n });\n\n const response = await this.client.send(command);\n\n if (!response.Location) {\n throw new Error('Failed to complete multipart upload');\n }\n\n // return response.Location;\n return this.getBucketUrl({\n bucketName,\n path,\n });\n }\n\n async downloadFile({\n bucketName,\n key,\n destinationFilePath,\n onStart,\n onProgress,\n onComplete,\n onError,\n }: DownloadFileOptions & {\n onStart?: () => void;\n onProgress?: (progress: number) => void;\n onComplete?: () => void;\n onError?: (error: Error) => void;\n }): Promise<void> {\n const decodedKey = decodeURIComponent(key);\n const bucketKey = decodedKey;\n\n Logger.info({\n message: 'Downloading file from S3',\n meta: {\n bucketName,\n Key: bucketKey,\n },\n });\n\n const getObjectParams = {\n Bucket: bucketName,\n Key: bucketKey,\n };\n\n try {\n const command = new GetObjectCommand(getObjectParams);\n\n const response = await this.client.send(command);\n\n if (!response.Body || !(response.Body instanceof Readable)) {\n throw new Error('Expected Body to be a readable stream!');\n }\n\n if (onStart) {\n onStart();\n }\n\n const directoryPath = dirname(destinationFilePath);\n\n // Ensure directory exists\n await File.ensureDir(directoryPath);\n\n const fileStream = createWriteStream(destinationFilePath);\n const totalSize = parseInt(response.ContentLength?.toString() ?? '0', 10);\n\n let bytesRead = 0;\n\n response.Body.on('data', (chunk: Buffer) => {\n bytesRead += chunk.length;\n\n if (onProgress && totalSize > 0) {\n const progress = Math.min((bytesRead / totalSize) * 100, 100);\n const formattedProgress = parseFloat(progress.toFixed(1));\n\n onProgress(formattedProgress);\n }\n });\n\n await asyncPipeline(response.Body, fileStream);\n\n // Verify file was written\n if (!(await File.pathExists(destinationFilePath))) {\n throw new Error(`Could not find downloaded file at ${destinationFilePath}`);\n }\n\n Logger.info({\n message: 'File successfully downloaded',\n meta: {\n Path: destinationFilePath,\n },\n });\n\n if (onComplete) {\n onComplete();\n }\n } catch (error) {\n Logger.error({ error });\n\n if (onError) {\n onError(error as Error);\n }\n\n throw error as Error;\n }\n }\n\n public async generateSignedUrl({ bucket, key }: { bucket: string; key: string }): Promise<string> {\n try {\n const command = new GetObjectCommand({\n Bucket: bucket,\n Key: key,\n });\n\n // Set the expiration for the signed URL to 1 hour\n const signedUrl = await getSignedUrl(this.client, command, {\n expiresIn: 3600,\n });\n\n // Log the signed URL\n Logger.info({\n message: 'Generated signed URL',\n meta: {\n URL: signedUrl,\n },\n });\n\n return signedUrl;\n } catch (error) {\n Logger.error({ error });\n\n throw error;\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/util/file.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a file or directory exists asynchronously
|
|
3
|
+
* @param pathToCheck - Path to check
|
|
4
|
+
* @returns Promise<boolean> - true if exists, false otherwise
|
|
5
|
+
*/
|
|
6
|
+
declare function pathExists(pathToCheck: string): Promise<boolean>;
|
|
7
|
+
/**
|
|
8
|
+
* Ensure directory exists, create if it doesn't
|
|
9
|
+
* @param dirPath - Directory path to ensure
|
|
10
|
+
*/
|
|
11
|
+
declare function ensureDir(dirPath: string): Promise<void>;
|
|
1
12
|
declare function convertFile({ inputFilePath, outputFilePath, format, }: {
|
|
2
13
|
inputFilePath: string;
|
|
3
14
|
outputFilePath: string;
|
|
@@ -40,6 +51,8 @@ declare const _default: {
|
|
|
40
51
|
downloadFile: typeof downloadFile;
|
|
41
52
|
formatFileSize: typeof formatFileSize;
|
|
42
53
|
removeSync: typeof removeSync;
|
|
54
|
+
pathExists: typeof pathExists;
|
|
55
|
+
ensureDir: typeof ensureDir;
|
|
43
56
|
};
|
|
44
57
|
export default _default;
|
|
45
58
|
//# sourceMappingURL=file.d.ts.map
|
package/dist/util/file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/util/file.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/util/file.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,iBAAe,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED;;;GAGG;AACH,iBAAe,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvD;AAED,iBAAe,WAAW,CAAC,EACzB,aAAa,EACb,cAAc,EACd,MAAM,GACP,EAAE;IACD,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBhB;AAED;;;;;GAKG;AACH,iBAAS,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAmBjD;AAED;;;;;GAKG;AACH,iBAAe,YAAY,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B7G;AAED;;;;GAIG;AACH,iBAAS,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAyB5D;AAED;;;;GAIG;AACH,iBAAS,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAoBxC;;;;;;;;;;AAED,wBAQE"}
|
package/dist/util/file.js
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
import * as fs from "fs";
|
|
4
|
+
import { access, mkdir } from "fs/promises";
|
|
4
5
|
import * as path from "path";
|
|
5
6
|
import * as https from "https";
|
|
6
7
|
import { pipeline } from "stream";
|
|
7
8
|
import { promisify } from "node:util";
|
|
8
9
|
import ffmpeg from "fluent-ffmpeg";
|
|
9
10
|
const pipelineAsync = promisify(pipeline);
|
|
11
|
+
async function pathExists(pathToCheck) {
|
|
12
|
+
try {
|
|
13
|
+
await access(pathToCheck);
|
|
14
|
+
return true;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
__name(pathExists, "pathExists");
|
|
20
|
+
async function ensureDir(dirPath) {
|
|
21
|
+
try {
|
|
22
|
+
await access(dirPath);
|
|
23
|
+
} catch {
|
|
24
|
+
await mkdir(dirPath, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
__name(ensureDir, "ensureDir");
|
|
10
28
|
async function convertFile({
|
|
11
29
|
inputFilePath,
|
|
12
30
|
outputFilePath,
|
|
@@ -33,8 +51,7 @@ function copySync(src, dest) {
|
|
|
33
51
|
if (!fs.existsSync(dest)) {
|
|
34
52
|
fs.mkdirSync(dest);
|
|
35
53
|
}
|
|
36
|
-
const
|
|
37
|
-
for (const entry of entries) {
|
|
54
|
+
for (const entry of fs.readdirSync(src)) {
|
|
38
55
|
const srcPath = path.join(src, entry);
|
|
39
56
|
const destPath = path.join(dest, entry);
|
|
40
57
|
copySync(srcPath, destPath);
|
|
@@ -67,19 +84,37 @@ async function downloadFile({ url, destinationPath }) {
|
|
|
67
84
|
}
|
|
68
85
|
__name(downloadFile, "downloadFile");
|
|
69
86
|
function formatFileSize({ bytes }) {
|
|
70
|
-
const sizes = ["bytes", "kB", "MB", "GB", "TB"];
|
|
71
87
|
if (bytes === 0) return "0 bytes";
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
const units = ["bytes", "kB", "MB", "GB", "TB"];
|
|
89
|
+
let idx = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
90
|
+
if (idx < 0) idx = 0;
|
|
91
|
+
if (idx >= units.length) idx = units.length - 1;
|
|
92
|
+
const fileSize = (bytes / Math.pow(1024, idx)).toFixed(1);
|
|
93
|
+
let unit;
|
|
94
|
+
switch (idx) {
|
|
95
|
+
case 0:
|
|
96
|
+
unit = "bytes";
|
|
97
|
+
break;
|
|
98
|
+
case 1:
|
|
99
|
+
unit = "kB";
|
|
100
|
+
break;
|
|
101
|
+
case 2:
|
|
102
|
+
unit = "MB";
|
|
103
|
+
break;
|
|
104
|
+
case 3:
|
|
105
|
+
unit = "GB";
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
unit = "TB";
|
|
109
|
+
}
|
|
110
|
+
return `${fileSize} ${unit}`;
|
|
75
111
|
}
|
|
76
112
|
__name(formatFileSize, "formatFileSize");
|
|
77
113
|
function removeSync(target) {
|
|
78
114
|
if (fs.existsSync(target)) {
|
|
79
115
|
const stats = fs.statSync(target);
|
|
80
116
|
if (stats.isDirectory()) {
|
|
81
|
-
const
|
|
82
|
-
for (const entry of entries) {
|
|
117
|
+
for (const entry of fs.readdirSync(target)) {
|
|
83
118
|
const entryPath = path.join(target, entry);
|
|
84
119
|
removeSync(entryPath);
|
|
85
120
|
}
|
|
@@ -97,7 +132,9 @@ var file_default = {
|
|
|
97
132
|
copySync,
|
|
98
133
|
downloadFile,
|
|
99
134
|
formatFileSize,
|
|
100
|
-
removeSync
|
|
135
|
+
removeSync,
|
|
136
|
+
pathExists,
|
|
137
|
+
ensureDir
|
|
101
138
|
};
|
|
102
139
|
export {
|
|
103
140
|
file_default as default
|