node-server-engine 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.commitlintrc.js +10 -10
- package/.nycrc +1 -3
- package/.releaserc.js +2 -1
- package/README.md +206 -146
- package/dist/const/metrics.js.map +1 -1
- package/dist/db/models/index.js.map +1 -1
- package/dist/entities/AWSS3/AWSS3.js +12 -12
- package/dist/entities/AWSS3/AWSS3.js.map +1 -1
- package/dist/entities/ElasticSearch/ElasticSearch.js.map +1 -1
- package/dist/entities/Endpoint/Endpoint.types.js.map +1 -1
- package/dist/entities/GoogleCloudStorage/GoogleCloudStorage.js +11 -11
- package/dist/entities/GoogleCloudStorage/GoogleCloudStorage.js.map +1 -1
- package/dist/entities/KeySet/KeySet.js.map +1 -1
- package/dist/entities/PubSub/PubSub.js.map +1 -1
- package/dist/entities/PushNotification/PushNotification.js.map +1 -1
- package/dist/entities/Redis/Redis.js +3 -3
- package/dist/entities/Redis/Redis.js.map +1 -1
- package/dist/entities/SecretManager/SecretManager.js +3 -3
- package/dist/entities/SecretManager/SecretManager.js.map +1 -1
- package/dist/entities/Sequelize/Sequelize.config.js +11 -7
- package/dist/entities/Sequelize/Sequelize.config.js.map +1 -1
- package/dist/entities/Sequelize/Sequelize.js.map +1 -1
- package/dist/entities/Server/Server.js.map +1 -1
- package/dist/entities/Server/Server.types.js.map +1 -1
- package/dist/entities/SocketClient/SocketClient.d.ts +12 -0
- package/dist/entities/SocketClient/SocketClient.js +34 -3
- package/dist/entities/SocketClient/SocketClient.js.map +1 -1
- package/dist/entities/SocketClient/SocketClient.types.d.ts +6 -0
- package/dist/entities/SocketClient/SocketClient.types.js.map +1 -1
- package/dist/entities/index.js.map +1 -1
- package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
- package/dist/middleware/checkPermission/index.js.map +1 -1
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/multiPartFileUploader/multiPartFileUploader.js.map +1 -1
- package/dist/middleware/requestMetrics/requestMetrics.js.map +1 -1
- package/dist/middleware/swaggerDocs/swaggerDocs.js.map +1 -1
- package/dist/middleware/verificationToken/verificationToken.js.map +1 -1
- package/dist/utils/createSortedObject/createSortedObject.js.map +1 -1
- package/dist/utils/dbMigration/dbMigration.js.map +1 -1
- package/dist/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.js.map +1 -1
- package/dist/utils/jwt/jwt.js.map +1 -1
- package/dist/utils/jwt/jwt.types.js.map +1 -1
- package/dist/utils/report/output.js.map +1 -1
- package/dist/utils/report/report.js.map +1 -1
- package/dist/utils/semverCompare/semverCompare.js.map +1 -1
- package/dist/utils/verificationToken/verificationToken.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.js","names":["_promClient","require","instanceRegistry","exports","Registry","serviceRegistry","collectDefaultMetrics","register","prefix"],"sources":["../../src/const/metrics.ts"],"sourcesContent":["import { Registry, collectDefaultMetrics } from 'prom-client';\n\n// Registry for metrics that apply to this specific instance of the service\nexport const instanceRegistry = new Registry();\n\n// Registry for metrics that apply to the service as a whole\nexport const serviceRegistry = new Registry();\n\n// Collect default Node.js process metrics (includes process_start_time_seconds)\ncollectDefaultMetrics({\n register: instanceRegistry,\n prefix: ''
|
|
1
|
+
{"version":3,"file":"metrics.js","names":["_promClient","require","instanceRegistry","exports","Registry","serviceRegistry","collectDefaultMetrics","register","prefix"],"sources":["../../src/const/metrics.ts"],"sourcesContent":["import { Registry, collectDefaultMetrics } from 'prom-client';\n\n// Registry for metrics that apply to this specific instance of the service\nexport const instanceRegistry = new Registry();\n\n// Registry for metrics that apply to the service as a whole\nexport const serviceRegistry = new Registry();\n\n// Collect default Node.js process metrics (includes process_start_time_seconds)\ncollectDefaultMetrics({\n register: instanceRegistry,\n prefix: ''\n});\n"],"mappings":";;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAEA;AACO,MAAMC,gBAAgB,GAAAC,OAAA,CAAAD,gBAAA,GAAG,IAAIE,oBAAQ,CAAC,CAAC;;AAE9C;AACO,MAAMC,eAAe,GAAAF,OAAA,CAAAE,eAAA,GAAG,IAAID,oBAAQ,CAAC,CAAC;;AAE7C;AACA,IAAAE,iCAAqB,EAAC;EACpBC,QAAQ,EAAEL,gBAAgB;EAC1BM,MAAM,EAAE;AACV,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_SequelizeMeta","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get"],"sources":["../../../src/db/models/index.ts"],"sourcesContent":["export * from './SequelizeMeta';\n
|
|
1
|
+
{"version":3,"file":"index.js","names":["_SequelizeMeta","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get"],"sources":["../../../src/db/models/index.ts"],"sourcesContent":["export * from './SequelizeMeta';\n"],"mappings":";;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,cAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,cAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,cAAA,CAAAK,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
|
|
@@ -18,7 +18,7 @@ const namespace = 'engine:aws-s3';
|
|
|
18
18
|
* Generic AWS S3 wrapper for easy file operations
|
|
19
19
|
* Provides methods for uploading, downloading, streaming, and deleting files
|
|
20
20
|
* Compatible with AWS S3 and S3-compatible services (MinIO, LocalStack, etc.)
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* @example
|
|
23
23
|
* ```typescript
|
|
24
24
|
* // Initialize with custom configuration
|
|
@@ -27,17 +27,17 @@ const namespace = 'engine:aws-s3';
|
|
|
27
27
|
* accessKeyId: 'YOUR_ACCESS_KEY',
|
|
28
28
|
* secretAccessKey: 'YOUR_SECRET_KEY'
|
|
29
29
|
* });
|
|
30
|
-
*
|
|
30
|
+
*
|
|
31
31
|
* // Upload a file
|
|
32
32
|
* const result = await AWSS3.upload(
|
|
33
33
|
* fileStream,
|
|
34
34
|
* 'my-bucket',
|
|
35
35
|
* { directory: 'uploads', mime: 'image/png' }
|
|
36
36
|
* );
|
|
37
|
-
*
|
|
37
|
+
*
|
|
38
38
|
* // Download a file
|
|
39
39
|
* const { data, metadata } = await AWSS3.get('my-bucket', 'uploads/file.png');
|
|
40
|
-
*
|
|
40
|
+
*
|
|
41
41
|
* // Delete a file
|
|
42
42
|
* await AWSS3.delete('my-bucket', 'uploads/file.png');
|
|
43
43
|
* ```
|
|
@@ -107,7 +107,7 @@ const AWSS3 = exports.AWSS3 = {
|
|
|
107
107
|
* @param uploaderOptions - Additional options like maxSize
|
|
108
108
|
* @param metadata - Optional metadata to attach to the file
|
|
109
109
|
* @returns Promise with file upload result
|
|
110
|
-
*
|
|
110
|
+
*
|
|
111
111
|
* @example
|
|
112
112
|
* ```typescript
|
|
113
113
|
* const fileStream = fs.createReadStream('photo.jpg');
|
|
@@ -210,7 +210,7 @@ const AWSS3 = exports.AWSS3 = {
|
|
|
210
210
|
* @param bucket - Bucket name
|
|
211
211
|
* @param key - File key (path) in the bucket
|
|
212
212
|
* @returns Promise with file data and metadata
|
|
213
|
-
*
|
|
213
|
+
*
|
|
214
214
|
* @example
|
|
215
215
|
* ```typescript
|
|
216
216
|
* const { data, metadata } = await AWSS3.get('my-bucket', 'photos/image.jpg');
|
|
@@ -261,7 +261,7 @@ const AWSS3 = exports.AWSS3 = {
|
|
|
261
261
|
* @param bucket - Bucket name
|
|
262
262
|
* @param key - File key (path) in the bucket
|
|
263
263
|
* @returns Promise with readable stream and metadata
|
|
264
|
-
*
|
|
264
|
+
*
|
|
265
265
|
* @example
|
|
266
266
|
* ```typescript
|
|
267
267
|
* const { stream, metadata } = await AWSS3.download('my-bucket', 'videos/video.mp4');
|
|
@@ -304,7 +304,7 @@ const AWSS3 = exports.AWSS3 = {
|
|
|
304
304
|
* @param bucket - Bucket name
|
|
305
305
|
* @param key - File key (path) in the bucket
|
|
306
306
|
* @returns Promise with readable stream
|
|
307
|
-
*
|
|
307
|
+
*
|
|
308
308
|
* @example
|
|
309
309
|
* ```typescript
|
|
310
310
|
* const stream = await AWSS3.getFileStream('my-bucket', 'audio/song.mp3');
|
|
@@ -333,7 +333,7 @@ const AWSS3 = exports.AWSS3 = {
|
|
|
333
333
|
* @param bucket - Bucket name
|
|
334
334
|
* @param key - File key (path) in the bucket
|
|
335
335
|
* @returns Promise with file metadata
|
|
336
|
-
*
|
|
336
|
+
*
|
|
337
337
|
* @example
|
|
338
338
|
* ```typescript
|
|
339
339
|
* const metadata = await AWSS3.getMetadata('my-bucket', 'photos/image.jpg');
|
|
@@ -363,7 +363,7 @@ const AWSS3 = exports.AWSS3 = {
|
|
|
363
363
|
* @param bucket - Bucket name
|
|
364
364
|
* @param key - File key (path) in the bucket
|
|
365
365
|
* @returns Promise that resolves when deletion is complete
|
|
366
|
-
*
|
|
366
|
+
*
|
|
367
367
|
* @example
|
|
368
368
|
* ```typescript
|
|
369
369
|
* await AWSS3.delete('my-bucket', 'temp/old-file.txt');
|
|
@@ -390,13 +390,13 @@ const AWSS3 = exports.AWSS3 = {
|
|
|
390
390
|
* Useful for creating unique file names
|
|
391
391
|
* @param options - Options for file destination generation
|
|
392
392
|
* @returns Generated file path
|
|
393
|
-
*
|
|
393
|
+
*
|
|
394
394
|
* @example
|
|
395
395
|
* ```typescript
|
|
396
396
|
* // Generate UUID only
|
|
397
397
|
* const path1 = AWSS3.generateFileDestination();
|
|
398
398
|
* // 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
|
399
|
-
*
|
|
399
|
+
*
|
|
400
400
|
* // With directory and MIME type
|
|
401
401
|
* const path2 = AWSS3.generateFileDestination({
|
|
402
402
|
* directory: 'uploads/images',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AWSS3.js","names":["_crypto","require","_clientS","_filesizeParser","_interopRequireDefault","_mimeTypes","_WebError","_report","_trimPathSlash","namespace","AWSS3","exports","s3Client","init","config","s3Config","region","endpoint","forcePathStyle","undefined","accessKeyId","secretAccessKey","credentials","sessionToken","process","env","AWS_REGION","AWS_S3_ENDPOINT","AWS_S3_FORCE_PATH_STYLE","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SESSION_TOKEN","S3Client","reportDebug","message","data","getS3Client","upload","readStream","bucket","destinationOptions","uploaderOptions","metadata","client","maxSize","fileName","directory","key","trimmedDirectory","trimPathSlash","generateFileDestination","chunks","receivedSize","intMaxSize","fileSizeParser","chunk","length","WebError","statusCode","errorCode","hint","push","body","Buffer","concat","contentType","mime","command","PutObjectCommand","Bucket","Key","Body","ContentType","Metadata","response","send","etag","ETag","Location","ServerSideEncryption","VersionId","get","GetObjectCommand","ContentLength","LastModified","size","download","stream","getFileStream","getMetadata","HeadObjectCommand","delete","DeleteObjectCommand","options","noExtension","extension","mimeTypes","fullName","randomUUID"],"sources":["../../../src/entities/AWSS3/AWSS3.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport { Readable } from 'stream';\nimport {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n DeleteObjectCommand,\n HeadObjectCommand,\n S3ClientConfig\n} from '@aws-sdk/client-s3';\nimport fileSizeParser from 'filesize-parser';\nimport mimeTypes from 'mime-types';\nimport {\n S3UploadDestinationOptions,\n S3UploadedFile,\n S3UploaderOptions,\n S3GetResponse,\n S3DownloadResponse,\n AWSS3Config,\n S3FileMetadata\n} from './AWSS3.types';\nimport { WebError } from 'entities/WebError';\nimport { reportDebug } from 'utils/report';\nimport { trimPathSlash } from 'utils/trimPathSlash';\n\nconst namespace = 'engine:aws-s3';\n\n/**\n * Generic AWS S3 wrapper for easy file operations\n * Provides methods for uploading, downloading, streaming, and deleting files\n * Compatible with AWS S3 and S3-compatible services (MinIO, LocalStack, etc.)\n * \n * @example\n * ```typescript\n * // Initialize with custom configuration\n * AWSS3.init({\n * region: 'us-east-1',\n * accessKeyId: 'YOUR_ACCESS_KEY',\n * secretAccessKey: 'YOUR_SECRET_KEY'\n * });\n * \n * // Upload a file\n * const result = await AWSS3.upload(\n * fileStream,\n * 'my-bucket',\n * { directory: 'uploads', mime: 'image/png' }\n * );\n * \n * // Download a file\n * const { data, metadata } = await AWSS3.get('my-bucket', 'uploads/file.png');\n * \n * // Delete a file\n * await AWSS3.delete('my-bucket', 'uploads/file.png');\n * ```\n */\nexport const AWSS3 = {\n s3Client: null as S3Client | null,\n\n /**\n * Initialize AWS S3 with configuration\n * Call this method before using any other methods\n * @param config - AWS S3 configuration options\n */\n init(config?: AWSS3Config): void {\n const s3Config: S3ClientConfig = {};\n\n if (config) {\n if (config.region) s3Config.region = config.region;\n if (config.endpoint) s3Config.endpoint = config.endpoint;\n if (config.forcePathStyle !== undefined) s3Config.forcePathStyle = config.forcePathStyle;\n \n if (config.accessKeyId && config.secretAccessKey) {\n s3Config.credentials = {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n ...(config.sessionToken && { sessionToken: config.sessionToken })\n };\n }\n } else {\n // Use environment variables as fallback\n if (process.env.AWS_REGION) s3Config.region = process.env.AWS_REGION;\n if (process.env.AWS_S3_ENDPOINT) s3Config.endpoint = process.env.AWS_S3_ENDPOINT;\n if (process.env.AWS_S3_FORCE_PATH_STYLE === 'true') s3Config.forcePathStyle = true;\n \n if (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {\n s3Config.credentials = {\n accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n ...(process.env.AWS_SESSION_TOKEN && { sessionToken: process.env.AWS_SESSION_TOKEN })\n };\n }\n }\n\n this.s3Client = new S3Client(s3Config);\n reportDebug({\n namespace,\n message: 'AWS S3 initialized',\n data: { region: s3Config.region, endpoint: s3Config.endpoint }\n });\n },\n\n /**\n * Get the S3 client instance (auto-initializes if needed)\n * @private\n */\n getS3Client(): S3Client {\n if (!this.s3Client) {\n this.init();\n }\n return this.s3Client!;\n },\n\n /**\n * Upload a file to AWS S3\n * @param readStream - Readable stream of the file content\n * @param bucket - Bucket name where the file should be stored\n * @param destinationOptions - Options for file destination (directory, fileName, etc.)\n * @param uploaderOptions - Additional options like maxSize\n * @param metadata - Optional metadata to attach to the file\n * @returns Promise with file upload result\n * \n * @example\n * ```typescript\n * const fileStream = fs.createReadStream('photo.jpg');\n * const result = await AWSS3.upload(\n * fileStream,\n * 'my-bucket',\n * { directory: 'photos', mime: 'image/jpeg' },\n * { maxSize: '5MB' },\n * { userId: '123', uploadedBy: 'user@example.com' }\n * );\n * console.log(result.Key); // photos/uuid.jpeg\n * ```\n */\n async upload(\n readStream: Readable,\n bucket: string,\n destinationOptions: S3UploadDestinationOptions = {},\n uploaderOptions: S3UploaderOptions = {},\n metadata?: Record<string, string>\n ): Promise<S3UploadedFile> {\n const client = this.getS3Client();\n const { maxSize } = uploaderOptions;\n\n reportDebug({\n namespace,\n message: 'Uploading file to S3',\n data: { bucket, destinationOptions, uploaderOptions }\n });\n\n // Generate the file path\n const { fileName, directory } = destinationOptions;\n\n let key: string;\n if (fileName) {\n const trimmedDirectory = trimPathSlash(directory ?? '/');\n key = trimmedDirectory ? `${trimmedDirectory}/${fileName}` : fileName;\n } else {\n key = this.generateFileDestination(destinationOptions);\n }\n\n // Collect stream data with size validation\n const chunks: Buffer[] = [];\n let receivedSize = 0;\n const intMaxSize = maxSize && fileSizeParser(maxSize);\n\n for await (const chunk of readStream) {\n receivedSize += chunk.length;\n \n if (intMaxSize && receivedSize > intMaxSize) {\n throw new WebError({\n statusCode: 413,\n errorCode: 'file-too-large',\n message: 'File size exceeds the maximum allowed limit',\n hint: { maxSize },\n data: {\n bucket,\n destinationOptions,\n receivedSize,\n maxSize\n }\n });\n }\n \n chunks.push(chunk);\n }\n\n const body = Buffer.concat(chunks);\n\n // Determine content type\n const contentType = destinationOptions.mime || 'application/octet-stream';\n\n const command = new PutObjectCommand({\n Bucket: bucket,\n Key: key,\n Body: body,\n ContentType: contentType,\n ...(metadata && { Metadata: metadata })\n });\n\n const response = await client.send(command);\n\n reportDebug({\n namespace,\n message: 'File uploaded to S3',\n data: { bucket, key, etag: response.ETag }\n });\n\n return {\n Bucket: bucket,\n Key: key,\n ETag: response.ETag,\n Location: `https://${bucket}.s3.amazonaws.com/${key}`,\n ServerSideEncryption: response.ServerSideEncryption,\n VersionId: response.VersionId\n };\n },\n\n /**\n * Download a file from AWS S3 and return its content as Buffer\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise with file data and metadata\n * \n * @example\n * ```typescript\n * const { data, metadata } = await AWSS3.get('my-bucket', 'photos/image.jpg');\n * console.log(metadata.ContentLength); // File size in bytes\n * console.log(data); // Buffer with file content\n * ```\n */\n async get(bucket: string, key: string): Promise<S3GetResponse> {\n const client = this.getS3Client();\n\n const command = new GetObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n const response = await client.send(command);\n\n // Convert stream to buffer\n const chunks: Buffer[] = [];\n for await (const chunk of response.Body as Readable) {\n chunks.push(chunk);\n }\n const data = Buffer.concat(chunks);\n\n const metadata: S3FileMetadata = {\n ContentType: response.ContentType,\n ContentLength: response.ContentLength,\n LastModified: response.LastModified,\n ETag: response.ETag,\n Metadata: response.Metadata,\n ServerSideEncryption: response.ServerSideEncryption,\n VersionId: response.VersionId\n };\n\n reportDebug({\n namespace,\n message: 'Downloaded file from S3',\n data: { bucket, key, size: data.length }\n });\n\n return { data, metadata };\n },\n\n /**\n * Get a readable stream for a file from AWS S3\n * Use this for large files or when you need to stream the content\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise with readable stream and metadata\n * \n * @example\n * ```typescript\n * const { stream, metadata } = await AWSS3.download('my-bucket', 'videos/video.mp4');\n * stream.pipe(res); // Stream to HTTP response\n * ```\n */\n async download(bucket: string, key: string): Promise<S3DownloadResponse> {\n const client = this.getS3Client();\n\n const command = new GetObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n const response = await client.send(command);\n\n const metadata: S3FileMetadata = {\n ContentType: response.ContentType,\n ContentLength: response.ContentLength,\n LastModified: response.LastModified,\n ETag: response.ETag,\n Metadata: response.Metadata,\n ServerSideEncryption: response.ServerSideEncryption,\n VersionId: response.VersionId\n };\n\n reportDebug({\n namespace,\n message: 'Fetched file stream from S3',\n data: { bucket, key, metadata }\n });\n\n return {\n stream: response.Body as Readable,\n metadata\n };\n },\n\n /**\n * Get a readable stream for a file (without fetching all metadata first)\n * Use this when you don't need metadata and want faster streaming\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise with readable stream\n * \n * @example\n * ```typescript\n * const stream = await AWSS3.getFileStream('my-bucket', 'audio/song.mp3');\n * stream.pipe(res); // Direct streaming\n * ```\n */\n async getFileStream(bucket: string, key: string): Promise<Readable> {\n const client = this.getS3Client();\n\n const command = new GetObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n const response = await client.send(command);\n\n reportDebug({\n namespace,\n message: \"Fetched file stream from S3's bucket\",\n data: { bucket, key }\n });\n\n return response.Body as Readable;\n },\n\n /**\n * Get file metadata without downloading the file\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise with file metadata\n * \n * @example\n * ```typescript\n * const metadata = await AWSS3.getMetadata('my-bucket', 'photos/image.jpg');\n * console.log(metadata.ContentLength); // File size\n * console.log(metadata.ContentType); // MIME type\n * ```\n */\n async getMetadata(bucket: string, key: string): Promise<S3FileMetadata> {\n const client = this.getS3Client();\n\n const command = new HeadObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n const response = await client.send(command);\n\n return {\n ContentType: response.ContentType,\n ContentLength: response.ContentLength,\n LastModified: response.LastModified,\n ETag: response.ETag,\n Metadata: response.Metadata,\n ServerSideEncryption: response.ServerSideEncryption,\n VersionId: response.VersionId\n };\n },\n\n /**\n * Delete a file from AWS S3\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise that resolves when deletion is complete\n * \n * @example\n * ```typescript\n * await AWSS3.delete('my-bucket', 'temp/old-file.txt');\n * ```\n */\n async delete(bucket: string, key: string): Promise<void> {\n const client = this.getS3Client();\n\n reportDebug({\n namespace,\n message: 'Deleting file from S3',\n data: { bucket, key }\n });\n\n const command = new DeleteObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n await client.send(command);\n },\n\n /**\n * Generate a random file path with optional directory and extension\n * Useful for creating unique file names\n * @param options - Options for file destination generation\n * @returns Generated file path\n * \n * @example\n * ```typescript\n * // Generate UUID only\n * const path1 = AWSS3.generateFileDestination();\n * // 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'\n * \n * // With directory and MIME type\n * const path2 = AWSS3.generateFileDestination({\n * directory: 'uploads/images',\n * mime: 'image/jpeg'\n * });\n * // 'uploads/images/a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpeg'\n * ```\n */\n generateFileDestination(options: S3UploadDestinationOptions = {}): string {\n const { directory = '/', mime, noExtension = false } = options;\n\n // Determine file extension from MIME type\n const extension =\n mime && mimeTypes.extension(mime) ? mimeTypes.extension(mime) : undefined;\n \n // Build the full name with or without extension\n const fullName =\n extension && !noExtension ? `${randomUUID()}.${extension}` : randomUUID();\n \n // Clean up directory path\n const trimmedDirectory = trimPathSlash(directory);\n return `${trimmedDirectory ? `${trimmedDirectory}/` : ''}${fullName}`;\n }\n};\n"],"mappings":";;;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAEA,IAAAC,QAAA,GAAAD,OAAA;AAQA,IAAAE,eAAA,GAAAC,sBAAA,CAAAH,OAAA;AACA,IAAAI,UAAA,GAAAD,sBAAA,CAAAH,OAAA;AAUA,IAAAK,SAAA,GAAAL,OAAA;AACA,IAAAM,OAAA,GAAAN,OAAA;AACA,IAAAO,cAAA,GAAAP,OAAA;AAEA,MAAMQ,SAAS,GAAG,eAAe;;AAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,KAAK,GAAAC,OAAA,CAAAD,KAAA,GAAG;EACnBE,QAAQ,EAAE,IAAuB;EAEjC;AACF;AACA;AACA;AACA;EACEC,IAAIA,CAACC,MAAoB,EAAQ;IAC/B,MAAMC,QAAwB,GAAG,CAAC,CAAC;IAEnC,IAAID,MAAM,EAAE;MACV,IAAIA,MAAM,CAACE,MAAM,EAAED,QAAQ,CAACC,MAAM,GAAGF,MAAM,CAACE,MAAM;MAClD,IAAIF,MAAM,CAACG,QAAQ,EAAEF,QAAQ,CAACE,QAAQ,GAAGH,MAAM,CAACG,QAAQ;MACxD,IAAIH,MAAM,CAACI,cAAc,KAAKC,SAAS,EAAEJ,QAAQ,CAACG,cAAc,GAAGJ,MAAM,CAACI,cAAc;MAExF,IAAIJ,MAAM,CAACM,WAAW,IAAIN,MAAM,CAACO,eAAe,EAAE;QAChDN,QAAQ,CAACO,WAAW,GAAG;UACrBF,WAAW,EAAEN,MAAM,CAACM,WAAW;UAC/BC,eAAe,EAAEP,MAAM,CAACO,eAAe;UACvC,IAAIP,MAAM,CAACS,YAAY,IAAI;YAAEA,YAAY,EAAET,MAAM,CAACS;UAAa,CAAC;QAClE,CAAC;MACH;IACF,CAAC,MAAM;MACL;MACA,IAAIC,OAAO,CAACC,GAAG,CAACC,UAAU,EAAEX,QAAQ,CAACC,MAAM,GAAGQ,OAAO,CAACC,GAAG,CAACC,UAAU;MACpE,IAAIF,OAAO,CAACC,GAAG,CAACE,eAAe,EAAEZ,QAAQ,CAACE,QAAQ,GAAGO,OAAO,CAACC,GAAG,CAACE,eAAe;MAChF,IAAIH,OAAO,CAACC,GAAG,CAACG,uBAAuB,KAAK,MAAM,EAAEb,QAAQ,CAACG,cAAc,GAAG,IAAI;MAElF,IAAIM,OAAO,CAACC,GAAG,CAACI,iBAAiB,IAAIL,OAAO,CAACC,GAAG,CAACK,qBAAqB,EAAE;QACtEf,QAAQ,CAACO,WAAW,GAAG;UACrBF,WAAW,EAAEI,OAAO,CAACC,GAAG,CAACI,iBAAiB;UAC1CR,eAAe,EAAEG,OAAO,CAACC,GAAG,CAACK,qBAAqB;UAClD,IAAIN,OAAO,CAACC,GAAG,CAACM,iBAAiB,IAAI;YAAER,YAAY,EAAEC,OAAO,CAACC,GAAG,CAACM;UAAkB,CAAC;QACtF,CAAC;MACH;IACF;IAEA,IAAI,CAACnB,QAAQ,GAAG,IAAIoB,iBAAQ,CAACjB,QAAQ,CAAC;IACtC,IAAAkB,mBAAW,EAAC;MACVxB,SAAS;MACTyB,OAAO,EAAE,oBAAoB;MAC7BC,IAAI,EAAE;QAAEnB,MAAM,EAAED,QAAQ,CAACC,MAAM;QAAEC,QAAQ,EAAEF,QAAQ,CAACE;MAAS;IAC/D,CAAC,CAAC;EACJ,CAAC;EAED;AACF;AACA;AACA;EACEmB,WAAWA,CAAA,EAAa;IACtB,IAAI,CAAC,IAAI,CAACxB,QAAQ,EAAE;MAClB,IAAI,CAACC,IAAI,CAAC,CAAC;IACb;IACA,OAAO,IAAI,CAACD,QAAQ;EACtB,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAMyB,MAAMA,CACVC,UAAoB,EACpBC,MAAc,EACdC,kBAA8C,GAAG,CAAC,CAAC,EACnDC,eAAkC,GAAG,CAAC,CAAC,EACvCC,QAAiC,EACR;IACzB,MAAMC,MAAM,GAAG,IAAI,CAACP,WAAW,CAAC,CAAC;IACjC,MAAM;MAAEQ;IAAQ,CAAC,GAAGH,eAAe;IAEnC,IAAAR,mBAAW,EAAC;MACVxB,SAAS;MACTyB,OAAO,EAAE,sBAAsB;MAC/BC,IAAI,EAAE;QAAEI,MAAM;QAAEC,kBAAkB;QAAEC;MAAgB;IACtD,CAAC,CAAC;;IAEF;IACA,MAAM;MAAEI,QAAQ;MAAEC;IAAU,CAAC,GAAGN,kBAAkB;IAElD,IAAIO,GAAW;IACf,IAAIF,QAAQ,EAAE;MACZ,MAAMG,gBAAgB,GAAG,IAAAC,4BAAa,EAACH,SAAS,IAAI,GAAG,CAAC;MACxDC,GAAG,GAAGC,gBAAgB,GAAG,GAAGA,gBAAgB,IAAIH,QAAQ,EAAE,GAAGA,QAAQ;IACvE,CAAC,MAAM;MACLE,GAAG,GAAG,IAAI,CAACG,uBAAuB,CAACV,kBAAkB,CAAC;IACxD;;IAEA;IACA,MAAMW,MAAgB,GAAG,EAAE;IAC3B,IAAIC,YAAY,GAAG,CAAC;IACpB,MAAMC,UAAU,GAAGT,OAAO,IAAI,IAAAU,uBAAc,EAACV,OAAO,CAAC;IAErD,WAAW,MAAMW,KAAK,IAAIjB,UAAU,EAAE;MACpCc,YAAY,IAAIG,KAAK,CAACC,MAAM;MAE5B,IAAIH,UAAU,IAAID,YAAY,GAAGC,UAAU,EAAE;QAC3C,MAAM,IAAII,kBAAQ,CAAC;UACjBC,UAAU,EAAE,GAAG;UACfC,SAAS,EAAE,gBAAgB;UAC3BzB,OAAO,EAAE,6CAA6C;UACtD0B,IAAI,EAAE;YAAEhB;UAAQ,CAAC;UACjBT,IAAI,EAAE;YACJI,MAAM;YACNC,kBAAkB;YAClBY,YAAY;YACZR;UACF;QACF,CAAC,CAAC;MACJ;MAEAO,MAAM,CAACU,IAAI,CAACN,KAAK,CAAC;IACpB;IAEA,MAAMO,IAAI,GAAGC,MAAM,CAACC,MAAM,CAACb,MAAM,CAAC;;IAElC;IACA,MAAMc,WAAW,GAAGzB,kBAAkB,CAAC0B,IAAI,IAAI,0BAA0B;IAEzE,MAAMC,OAAO,GAAG,IAAIC,yBAAgB,CAAC;MACnCC,MAAM,EAAE9B,MAAM;MACd+B,GAAG,EAAEvB,GAAG;MACRwB,IAAI,EAAET,IAAI;MACVU,WAAW,EAAEP,WAAW;MACxB,IAAIvB,QAAQ,IAAI;QAAE+B,QAAQ,EAAE/B;MAAS,CAAC;IACxC,CAAC,CAAC;IAEF,MAAMgC,QAAQ,GAAG,MAAM/B,MAAM,CAACgC,IAAI,CAACR,OAAO,CAAC;IAE3C,IAAAlC,mBAAW,EAAC;MACVxB,SAAS;MACTyB,OAAO,EAAE,qBAAqB;MAC9BC,IAAI,EAAE;QAAEI,MAAM;QAAEQ,GAAG;QAAE6B,IAAI,EAAEF,QAAQ,CAACG;MAAK;IAC3C,CAAC,CAAC;IAEF,OAAO;MACLR,MAAM,EAAE9B,MAAM;MACd+B,GAAG,EAAEvB,GAAG;MACR8B,IAAI,EAAEH,QAAQ,CAACG,IAAI;MACnBC,QAAQ,EAAE,WAAWvC,MAAM,qBAAqBQ,GAAG,EAAE;MACrDgC,oBAAoB,EAAEL,QAAQ,CAACK,oBAAoB;MACnDC,SAAS,EAAEN,QAAQ,CAACM;IACtB,CAAC;EACH,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAMC,GAAGA,CAAC1C,MAAc,EAAEQ,GAAW,EAA0B;IAC7D,MAAMJ,MAAM,GAAG,IAAI,CAACP,WAAW,CAAC,CAAC;IAEjC,MAAM+B,OAAO,GAAG,IAAIe,yBAAgB,CAAC;MACnCb,MAAM,EAAE9B,MAAM;MACd+B,GAAG,EAAEvB;IACP,CAAC,CAAC;IAEF,MAAM2B,QAAQ,GAAG,MAAM/B,MAAM,CAACgC,IAAI,CAACR,OAAO,CAAC;;IAE3C;IACA,MAAMhB,MAAgB,GAAG,EAAE;IAC3B,WAAW,MAAMI,KAAK,IAAImB,QAAQ,CAACH,IAAI,EAAc;MACnDpB,MAAM,CAACU,IAAI,CAACN,KAAK,CAAC;IACpB;IACA,MAAMpB,IAAI,GAAG4B,MAAM,CAACC,MAAM,CAACb,MAAM,CAAC;IAElC,MAAMT,QAAwB,GAAG;MAC/B8B,WAAW,EAAEE,QAAQ,CAACF,WAAW;MACjCW,aAAa,EAAET,QAAQ,CAACS,aAAa;MACrCC,YAAY,EAAEV,QAAQ,CAACU,YAAY;MACnCP,IAAI,EAAEH,QAAQ,CAACG,IAAI;MACnBJ,QAAQ,EAAEC,QAAQ,CAACD,QAAQ;MAC3BM,oBAAoB,EAAEL,QAAQ,CAACK,oBAAoB;MACnDC,SAAS,EAAEN,QAAQ,CAACM;IACtB,CAAC;IAED,IAAA/C,mBAAW,EAAC;MACVxB,SAAS;MACTyB,OAAO,EAAE,yBAAyB;MAClCC,IAAI,EAAE;QAAEI,MAAM;QAAEQ,GAAG;QAAEsC,IAAI,EAAElD,IAAI,CAACqB;MAAO;IACzC,CAAC,CAAC;IAEF,OAAO;MAAErB,IAAI;MAAEO;IAAS,CAAC;EAC3B,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAM4C,QAAQA,CAAC/C,MAAc,EAAEQ,GAAW,EAA+B;IACvE,MAAMJ,MAAM,GAAG,IAAI,CAACP,WAAW,CAAC,CAAC;IAEjC,MAAM+B,OAAO,GAAG,IAAIe,yBAAgB,CAAC;MACnCb,MAAM,EAAE9B,MAAM;MACd+B,GAAG,EAAEvB;IACP,CAAC,CAAC;IAEF,MAAM2B,QAAQ,GAAG,MAAM/B,MAAM,CAACgC,IAAI,CAACR,OAAO,CAAC;IAE3C,MAAMzB,QAAwB,GAAG;MAC/B8B,WAAW,EAAEE,QAAQ,CAACF,WAAW;MACjCW,aAAa,EAAET,QAAQ,CAACS,aAAa;MACrCC,YAAY,EAAEV,QAAQ,CAACU,YAAY;MACnCP,IAAI,EAAEH,QAAQ,CAACG,IAAI;MACnBJ,QAAQ,EAAEC,QAAQ,CAACD,QAAQ;MAC3BM,oBAAoB,EAAEL,QAAQ,CAACK,oBAAoB;MACnDC,SAAS,EAAEN,QAAQ,CAACM;IACtB,CAAC;IAED,IAAA/C,mBAAW,EAAC;MACVxB,SAAS;MACTyB,OAAO,EAAE,6BAA6B;MACtCC,IAAI,EAAE;QAAEI,MAAM;QAAEQ,GAAG;QAAEL;MAAS;IAChC,CAAC,CAAC;IAEF,OAAO;MACL6C,MAAM,EAAEb,QAAQ,CAACH,IAAgB;MACjC7B;IACF,CAAC;EACH,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAM8C,aAAaA,CAACjD,MAAc,EAAEQ,GAAW,EAAqB;IAClE,MAAMJ,MAAM,GAAG,IAAI,CAACP,WAAW,CAAC,CAAC;IAEjC,MAAM+B,OAAO,GAAG,IAAIe,yBAAgB,CAAC;MACnCb,MAAM,EAAE9B,MAAM;MACd+B,GAAG,EAAEvB;IACP,CAAC,CAAC;IAEF,MAAM2B,QAAQ,GAAG,MAAM/B,MAAM,CAACgC,IAAI,CAACR,OAAO,CAAC;IAE3C,IAAAlC,mBAAW,EAAC;MACVxB,SAAS;MACTyB,OAAO,EAAE,sCAAsC;MAC/CC,IAAI,EAAE;QAAEI,MAAM;QAAEQ;MAAI;IACtB,CAAC,CAAC;IAEF,OAAO2B,QAAQ,CAACH,IAAI;EACtB,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAMkB,WAAWA,CAAClD,MAAc,EAAEQ,GAAW,EAA2B;IACtE,MAAMJ,MAAM,GAAG,IAAI,CAACP,WAAW,CAAC,CAAC;IAEjC,MAAM+B,OAAO,GAAG,IAAIuB,0BAAiB,CAAC;MACpCrB,MAAM,EAAE9B,MAAM;MACd+B,GAAG,EAAEvB;IACP,CAAC,CAAC;IAEF,MAAM2B,QAAQ,GAAG,MAAM/B,MAAM,CAACgC,IAAI,CAACR,OAAO,CAAC;IAE3C,OAAO;MACLK,WAAW,EAAEE,QAAQ,CAACF,WAAW;MACjCW,aAAa,EAAET,QAAQ,CAACS,aAAa;MACrCC,YAAY,EAAEV,QAAQ,CAACU,YAAY;MACnCP,IAAI,EAAEH,QAAQ,CAACG,IAAI;MACnBJ,QAAQ,EAAEC,QAAQ,CAACD,QAAQ;MAC3BM,oBAAoB,EAAEL,QAAQ,CAACK,oBAAoB;MACnDC,SAAS,EAAEN,QAAQ,CAACM;IACtB,CAAC;EACH,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAMW,MAAMA,CAACpD,MAAc,EAAEQ,GAAW,EAAiB;IACvD,MAAMJ,MAAM,GAAG,IAAI,CAACP,WAAW,CAAC,CAAC;IAEjC,IAAAH,mBAAW,EAAC;MACVxB,SAAS;MACTyB,OAAO,EAAE,uBAAuB;MAChCC,IAAI,EAAE;QAAEI,MAAM;QAAEQ;MAAI;IACtB,CAAC,CAAC;IAEF,MAAMoB,OAAO,GAAG,IAAIyB,4BAAmB,CAAC;MACtCvB,MAAM,EAAE9B,MAAM;MACd+B,GAAG,EAAEvB;IACP,CAAC,CAAC;IAEF,MAAMJ,MAAM,CAACgC,IAAI,CAACR,OAAO,CAAC;EAC5B,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEjB,uBAAuBA,CAAC2C,OAAmC,GAAG,CAAC,CAAC,EAAU;IACxE,MAAM;MAAE/C,SAAS,GAAG,GAAG;MAAEoB,IAAI;MAAE4B,WAAW,GAAG;IAAM,CAAC,GAAGD,OAAO;;IAE9D;IACA,MAAME,SAAS,GACb7B,IAAI,IAAI8B,kBAAS,CAACD,SAAS,CAAC7B,IAAI,CAAC,GAAG8B,kBAAS,CAACD,SAAS,CAAC7B,IAAI,CAAC,GAAG/C,SAAS;;IAE3E;IACA,MAAM8E,QAAQ,GACZF,SAAS,IAAI,CAACD,WAAW,GAAG,GAAG,IAAAI,kBAAU,EAAC,CAAC,IAAIH,SAAS,EAAE,GAAG,IAAAG,kBAAU,EAAC,CAAC;;IAE3E;IACA,MAAMlD,gBAAgB,GAAG,IAAAC,4BAAa,EAACH,SAAS,CAAC;IACjD,OAAO,GAAGE,gBAAgB,GAAG,GAAGA,gBAAgB,GAAG,GAAG,EAAE,GAAGiD,QAAQ,EAAE;EACvE;AACF,CAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"AWSS3.js","names":["_crypto","require","_clientS","_filesizeParser","_interopRequireDefault","_mimeTypes","_WebError","_report","_trimPathSlash","namespace","AWSS3","exports","s3Client","init","config","s3Config","region","endpoint","forcePathStyle","undefined","accessKeyId","secretAccessKey","credentials","sessionToken","process","env","AWS_REGION","AWS_S3_ENDPOINT","AWS_S3_FORCE_PATH_STYLE","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SESSION_TOKEN","S3Client","reportDebug","message","data","getS3Client","upload","readStream","bucket","destinationOptions","uploaderOptions","metadata","client","maxSize","fileName","directory","key","trimmedDirectory","trimPathSlash","generateFileDestination","chunks","receivedSize","intMaxSize","fileSizeParser","chunk","length","WebError","statusCode","errorCode","hint","push","body","Buffer","concat","contentType","mime","command","PutObjectCommand","Bucket","Key","Body","ContentType","Metadata","response","send","etag","ETag","Location","ServerSideEncryption","VersionId","get","GetObjectCommand","ContentLength","LastModified","size","download","stream","getFileStream","getMetadata","HeadObjectCommand","delete","DeleteObjectCommand","options","noExtension","extension","mimeTypes","fullName","randomUUID"],"sources":["../../../src/entities/AWSS3/AWSS3.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport { Readable } from 'stream';\nimport {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n DeleteObjectCommand,\n HeadObjectCommand,\n S3ClientConfig\n} from '@aws-sdk/client-s3';\nimport fileSizeParser from 'filesize-parser';\nimport mimeTypes from 'mime-types';\nimport {\n S3UploadDestinationOptions,\n S3UploadedFile,\n S3UploaderOptions,\n S3GetResponse,\n S3DownloadResponse,\n AWSS3Config,\n S3FileMetadata\n} from './AWSS3.types';\nimport { WebError } from 'entities/WebError';\nimport { reportDebug } from 'utils/report';\nimport { trimPathSlash } from 'utils/trimPathSlash';\n\nconst namespace = 'engine:aws-s3';\n\n/**\n * Generic AWS S3 wrapper for easy file operations\n * Provides methods for uploading, downloading, streaming, and deleting files\n * Compatible with AWS S3 and S3-compatible services (MinIO, LocalStack, etc.)\n *\n * @example\n * ```typescript\n * // Initialize with custom configuration\n * AWSS3.init({\n * region: 'us-east-1',\n * accessKeyId: 'YOUR_ACCESS_KEY',\n * secretAccessKey: 'YOUR_SECRET_KEY'\n * });\n *\n * // Upload a file\n * const result = await AWSS3.upload(\n * fileStream,\n * 'my-bucket',\n * { directory: 'uploads', mime: 'image/png' }\n * );\n *\n * // Download a file\n * const { data, metadata } = await AWSS3.get('my-bucket', 'uploads/file.png');\n *\n * // Delete a file\n * await AWSS3.delete('my-bucket', 'uploads/file.png');\n * ```\n */\nexport const AWSS3 = {\n s3Client: null as S3Client | null,\n\n /**\n * Initialize AWS S3 with configuration\n * Call this method before using any other methods\n * @param config - AWS S3 configuration options\n */\n init(config?: AWSS3Config): void {\n const s3Config: S3ClientConfig = {};\n\n if (config) {\n if (config.region) s3Config.region = config.region;\n if (config.endpoint) s3Config.endpoint = config.endpoint;\n if (config.forcePathStyle !== undefined)\n s3Config.forcePathStyle = config.forcePathStyle;\n\n if (config.accessKeyId && config.secretAccessKey) {\n s3Config.credentials = {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n ...(config.sessionToken && { sessionToken: config.sessionToken })\n };\n }\n } else {\n // Use environment variables as fallback\n if (process.env.AWS_REGION) s3Config.region = process.env.AWS_REGION;\n if (process.env.AWS_S3_ENDPOINT)\n s3Config.endpoint = process.env.AWS_S3_ENDPOINT;\n if (process.env.AWS_S3_FORCE_PATH_STYLE === 'true')\n s3Config.forcePathStyle = true;\n\n if (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {\n s3Config.credentials = {\n accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n ...(process.env.AWS_SESSION_TOKEN && {\n sessionToken: process.env.AWS_SESSION_TOKEN\n })\n };\n }\n }\n\n this.s3Client = new S3Client(s3Config);\n reportDebug({\n namespace,\n message: 'AWS S3 initialized',\n data: { region: s3Config.region, endpoint: s3Config.endpoint }\n });\n },\n\n /**\n * Get the S3 client instance (auto-initializes if needed)\n * @private\n */\n getS3Client(): S3Client {\n if (!this.s3Client) {\n this.init();\n }\n return this.s3Client!;\n },\n\n /**\n * Upload a file to AWS S3\n * @param readStream - Readable stream of the file content\n * @param bucket - Bucket name where the file should be stored\n * @param destinationOptions - Options for file destination (directory, fileName, etc.)\n * @param uploaderOptions - Additional options like maxSize\n * @param metadata - Optional metadata to attach to the file\n * @returns Promise with file upload result\n *\n * @example\n * ```typescript\n * const fileStream = fs.createReadStream('photo.jpg');\n * const result = await AWSS3.upload(\n * fileStream,\n * 'my-bucket',\n * { directory: 'photos', mime: 'image/jpeg' },\n * { maxSize: '5MB' },\n * { userId: '123', uploadedBy: 'user@example.com' }\n * );\n * console.log(result.Key); // photos/uuid.jpeg\n * ```\n */\n async upload(\n readStream: Readable,\n bucket: string,\n destinationOptions: S3UploadDestinationOptions = {},\n uploaderOptions: S3UploaderOptions = {},\n metadata?: Record<string, string>\n ): Promise<S3UploadedFile> {\n const client = this.getS3Client();\n const { maxSize } = uploaderOptions;\n\n reportDebug({\n namespace,\n message: 'Uploading file to S3',\n data: { bucket, destinationOptions, uploaderOptions }\n });\n\n // Generate the file path\n const { fileName, directory } = destinationOptions;\n\n let key: string;\n if (fileName) {\n const trimmedDirectory = trimPathSlash(directory ?? '/');\n key = trimmedDirectory ? `${trimmedDirectory}/${fileName}` : fileName;\n } else {\n key = this.generateFileDestination(destinationOptions);\n }\n\n // Collect stream data with size validation\n const chunks: Buffer[] = [];\n let receivedSize = 0;\n const intMaxSize = maxSize && fileSizeParser(maxSize);\n\n for await (const chunk of readStream) {\n receivedSize += chunk.length;\n\n if (intMaxSize && receivedSize > intMaxSize) {\n throw new WebError({\n statusCode: 413,\n errorCode: 'file-too-large',\n message: 'File size exceeds the maximum allowed limit',\n hint: { maxSize },\n data: {\n bucket,\n destinationOptions,\n receivedSize,\n maxSize\n }\n });\n }\n\n chunks.push(chunk);\n }\n\n const body = Buffer.concat(chunks);\n\n // Determine content type\n const contentType = destinationOptions.mime || 'application/octet-stream';\n\n const command = new PutObjectCommand({\n Bucket: bucket,\n Key: key,\n Body: body,\n ContentType: contentType,\n ...(metadata && { Metadata: metadata })\n });\n\n const response = await client.send(command);\n\n reportDebug({\n namespace,\n message: 'File uploaded to S3',\n data: { bucket, key, etag: response.ETag }\n });\n\n return {\n Bucket: bucket,\n Key: key,\n ETag: response.ETag,\n Location: `https://${bucket}.s3.amazonaws.com/${key}`,\n ServerSideEncryption: response.ServerSideEncryption,\n VersionId: response.VersionId\n };\n },\n\n /**\n * Download a file from AWS S3 and return its content as Buffer\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise with file data and metadata\n *\n * @example\n * ```typescript\n * const { data, metadata } = await AWSS3.get('my-bucket', 'photos/image.jpg');\n * console.log(metadata.ContentLength); // File size in bytes\n * console.log(data); // Buffer with file content\n * ```\n */\n async get(bucket: string, key: string): Promise<S3GetResponse> {\n const client = this.getS3Client();\n\n const command = new GetObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n const response = await client.send(command);\n\n // Convert stream to buffer\n const chunks: Buffer[] = [];\n for await (const chunk of response.Body as Readable) {\n chunks.push(chunk);\n }\n const data = Buffer.concat(chunks);\n\n const metadata: S3FileMetadata = {\n ContentType: response.ContentType,\n ContentLength: response.ContentLength,\n LastModified: response.LastModified,\n ETag: response.ETag,\n Metadata: response.Metadata,\n ServerSideEncryption: response.ServerSideEncryption,\n VersionId: response.VersionId\n };\n\n reportDebug({\n namespace,\n message: 'Downloaded file from S3',\n data: { bucket, key, size: data.length }\n });\n\n return { data, metadata };\n },\n\n /**\n * Get a readable stream for a file from AWS S3\n * Use this for large files or when you need to stream the content\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise with readable stream and metadata\n *\n * @example\n * ```typescript\n * const { stream, metadata } = await AWSS3.download('my-bucket', 'videos/video.mp4');\n * stream.pipe(res); // Stream to HTTP response\n * ```\n */\n async download(bucket: string, key: string): Promise<S3DownloadResponse> {\n const client = this.getS3Client();\n\n const command = new GetObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n const response = await client.send(command);\n\n const metadata: S3FileMetadata = {\n ContentType: response.ContentType,\n ContentLength: response.ContentLength,\n LastModified: response.LastModified,\n ETag: response.ETag,\n Metadata: response.Metadata,\n ServerSideEncryption: response.ServerSideEncryption,\n VersionId: response.VersionId\n };\n\n reportDebug({\n namespace,\n message: 'Fetched file stream from S3',\n data: { bucket, key, metadata }\n });\n\n return {\n stream: response.Body as Readable,\n metadata\n };\n },\n\n /**\n * Get a readable stream for a file (without fetching all metadata first)\n * Use this when you don't need metadata and want faster streaming\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise with readable stream\n *\n * @example\n * ```typescript\n * const stream = await AWSS3.getFileStream('my-bucket', 'audio/song.mp3');\n * stream.pipe(res); // Direct streaming\n * ```\n */\n async getFileStream(bucket: string, key: string): Promise<Readable> {\n const client = this.getS3Client();\n\n const command = new GetObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n const response = await client.send(command);\n\n reportDebug({\n namespace,\n message: \"Fetched file stream from S3's bucket\",\n data: { bucket, key }\n });\n\n return response.Body as Readable;\n },\n\n /**\n * Get file metadata without downloading the file\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise with file metadata\n *\n * @example\n * ```typescript\n * const metadata = await AWSS3.getMetadata('my-bucket', 'photos/image.jpg');\n * console.log(metadata.ContentLength); // File size\n * console.log(metadata.ContentType); // MIME type\n * ```\n */\n async getMetadata(bucket: string, key: string): Promise<S3FileMetadata> {\n const client = this.getS3Client();\n\n const command = new HeadObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n const response = await client.send(command);\n\n return {\n ContentType: response.ContentType,\n ContentLength: response.ContentLength,\n LastModified: response.LastModified,\n ETag: response.ETag,\n Metadata: response.Metadata,\n ServerSideEncryption: response.ServerSideEncryption,\n VersionId: response.VersionId\n };\n },\n\n /**\n * Delete a file from AWS S3\n * @param bucket - Bucket name\n * @param key - File key (path) in the bucket\n * @returns Promise that resolves when deletion is complete\n *\n * @example\n * ```typescript\n * await AWSS3.delete('my-bucket', 'temp/old-file.txt');\n * ```\n */\n async delete(bucket: string, key: string): Promise<void> {\n const client = this.getS3Client();\n\n reportDebug({\n namespace,\n message: 'Deleting file from S3',\n data: { bucket, key }\n });\n\n const command = new DeleteObjectCommand({\n Bucket: bucket,\n Key: key\n });\n\n await client.send(command);\n },\n\n /**\n * Generate a random file path with optional directory and extension\n * Useful for creating unique file names\n * @param options - Options for file destination generation\n * @returns Generated file path\n *\n * @example\n * ```typescript\n * // Generate UUID only\n * const path1 = AWSS3.generateFileDestination();\n * // 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'\n *\n * // With directory and MIME type\n * const path2 = AWSS3.generateFileDestination({\n * directory: 'uploads/images',\n * mime: 'image/jpeg'\n * });\n * // 'uploads/images/a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpeg'\n * ```\n */\n generateFileDestination(options: S3UploadDestinationOptions = {}): string {\n const { directory = '/', mime, noExtension = false } = options;\n\n // Determine file extension from MIME type\n const extension =\n mime && mimeTypes.extension(mime) ? mimeTypes.extension(mime) : undefined;\n\n // Build the full name with or without extension\n const fullName =\n extension && !noExtension ? `${randomUUID()}.${extension}` : randomUUID();\n\n // Clean up directory path\n const trimmedDirectory = trimPathSlash(directory);\n return `${trimmedDirectory ? `${trimmedDirectory}/` : ''}${fullName}`;\n }\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ElasticSearch.js","names":["_fs","require","_path","_interopRequireDefault","_elasticsearch","_EngineError","_LifecycleController","_utils","_checkEnvironment","cache","_interopRequireWildcard","e","t","__esModule","r","c","a","Object","defineProperty","n","__proto__","default","WeakMap","has","get","set","hasOwnProperty","call","getOwnPropertyDescriptor","namespace","client","ElasticSearch","exports","init","checkEnvironment","ELASTIC_SEARCH_HOST","envAssert","isString","ELASTIC_SEARCH_USERNAME","ELASTIC_SEARCH_PASSWORD","ELASTIC_SEARCH_MIGRATION_PATH","process","env","EngineError","message","reportDebug","data","host","config","node","auth","username","password","maxRetries","requestTimeout","sniffOnStart","TLS_CA","tls","ca","rejectUnauthorized","NODE_ENV","Client","ping","error","indices","delete","index","migrate","LifecycleController","register","reportInfo","getClient","migrationPath","path","resolve","files","readdirSync","filter","f","endsWith","indexExists","exists","ran","file","result","search","query","match","total","hits","value","push","migration","specifier","Promise","then","s","id","document","ranAt","Date","toISOString","reportError","stack","length","shutdown","close","undefined"],"sources":["../../../src/entities/ElasticSearch/ElasticSearch.ts"],"sourcesContent":["import { readdirSync } from 'fs';\nimport path from 'path';\nimport { Client, ClientOptions } from '@elastic/elasticsearch';\nimport { ElasticSearchMigration } from './ElasticSearch.types';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { envAssert, reportError, reportInfo, reportDebug } from 'utils';\nimport { checkEnvironment } from 'utils/checkEnvironment';\n\nconst namespace = 'engine:elasticsearch';\n\n/** Elastic search client */\nlet client: undefined | Client;\n\nexport const ElasticSearch = {\n /**\n * Init function that should be called on server startup to establish the connection\n */\n async init(): Promise<void> {\n checkEnvironment({\n ELASTIC_SEARCH_HOST: envAssert.isString(),\n ELASTIC_SEARCH_USERNAME: envAssert.isString(),\n ELASTIC_SEARCH_PASSWORD: envAssert.isString(),\n ELASTIC_SEARCH_MIGRATION_PATH: envAssert.isString()\n });\n\n if (!process.env.ELASTIC_SEARCH_HOST)\n throw new EngineError({\n message: 'ElasticSearch Host not set in environment'\n });\n\n reportDebug({\n namespace,\n message: 'Initializing ElasticSearch client',\n data: { host: process.env.ELASTIC_SEARCH_HOST }\n });\n\n const config: ClientOptions = {\n node: process.env.ELASTIC_SEARCH_HOST,\n auth: {\n username: process.env.ELASTIC_SEARCH_USERNAME as string,\n password: process.env.ELASTIC_SEARCH_PASSWORD as string\n },\n maxRetries: 3,\n requestTimeout: 30000,\n sniffOnStart: false\n };\n\n // Add TLS configuration if TLS_CA is provided\n if (process.env.TLS_CA) {\n config.tls = {\n ca: process.env.TLS_CA,\n rejectUnauthorized: process.env.NODE_ENV === 'production'\n };\n reportDebug({\n namespace,\n message: 'TLS enabled for ElasticSearch connection'\n });\n }\n\n client = new Client(config);\n\n // Verify connection\n try {\n await client.ping();\n reportDebug({\n namespace,\n message: 'ElasticSearch connection established'\n });\n } catch (error) {\n throw new EngineError({\n message: 'Failed to connect to ElasticSearch',\n data: { error: (error as Error).message }\n });\n }\n\n // In test environment flush the database before running migrations\n if (process.env.NODE_ENV === 'test') {\n reportDebug({\n namespace,\n message: 'Test environment detected, flushing all indices'\n });\n await client.indices.delete({ index: '*' });\n }\n\n await this.migrate();\n LifecycleController.register(this);\n\n reportInfo({ message: 'ElasticSearch initialized successfully' });\n },\n\n /**\n * Get the ElasticSearch client (for advanced use cases)\n */\n getClient(): Client | undefined {\n return client;\n },\n\n /**\n * Migration function called during the init process\n * Manages the database structure\n */\n async migrate(): Promise<void> {\n if (!client) throw new EngineError({ message: 'ElasticSearch was not initialized' });\n\n reportDebug({\n namespace,\n message: 'Starting ElasticSearch migrations'\n });\n\n const migrationPath = path.resolve(\n process.env.ELASTIC_SEARCH_MIGRATION_PATH as string\n );\n\n let files: string[];\n try {\n files = readdirSync(migrationPath).filter(\n f => f.endsWith('.ts') || f.endsWith('.js')\n );\n } catch (error) {\n throw new EngineError({\n message: 'Failed to read migration directory',\n data: { path: migrationPath, error: (error as Error).message }\n });\n }\n\n const indexExists = await client.indices.exists({\n index: 'migrations'\n });\n\n const ran: string[] = [];\n\n for (const file of files) {\n if (indexExists) {\n const result = await client.search({\n index: 'migrations',\n query: { match: { file } }\n });\n\n const total = typeof result.hits.total === 'number'\n ? result.hits.total\n : result.hits.total?.value ?? 0;\n\n if (total > 0) {\n reportDebug({\n namespace,\n message: `Skipping migration ${file} (already ran)`\n });\n continue;\n }\n }\n\n reportDebug({\n namespace,\n message: `Running migration: ${file}`\n });\n\n ran.push(file);\n\n try {\n const migration = (await import(\n `${migrationPath}/${file}`\n )) as ElasticSearchMigration;\n\n await migration.migrate(client);\n\n await client.index({\n index: 'migrations',\n id: file,\n document: { file, ranAt: new Date().toISOString() }\n });\n\n reportDebug({\n namespace,\n message: `Successfully ran migration: ${file}`\n });\n } catch (error) {\n reportError(\n new EngineError({\n message: `Migration failed: ${file}`,\n data: { error: (error as Error).message, stack: (error as Error).stack }\n })\n );\n throw error;\n }\n }\n\n reportInfo({\n message: `ElasticSearch: ran ${ran.length} migration(s)`,\n data: { files: ran }\n });\n },\n\n /**\n * Shutdown function that should be called on server stop to close the connection\n */\n async shutdown(): Promise<void> {\n if (client) {\n try {\n await client.close();\n reportDebug({\n namespace,\n message: 'ElasticSearch client disconnected'\n });\n } catch (error) {\n reportError(\n new EngineError({\n message: 'Error during ElasticSearch shutdown',\n data: { error: (error as Error).message }\n })\n );\n }\n client = undefined;\n }\n }\n};\n"],"mappings":";;;;;;;AAAA,IAAAA,GAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,cAAA,GAAAH,OAAA;AAEA,IAAAI,YAAA,GAAAJ,OAAA;AACA,IAAAK,oBAAA,GAAAL,OAAA;AACA,IAAAM,MAAA,GAAAN,OAAA;AACA,IAAAO,iBAAA,GAAAP,OAAA;AAA0D,IAAAQ,KAAA;AAAA,SAAAC,wBAAAC,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAE,UAAA,SAAAF,CAAA,MAAAG,CAAA,EAAAC,CAAA,EAAAC,CAAA,GAAAC,MAAA,CAAAC,cAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,QAAAM,MAAA,CAAAN,CAAA,MAAAA,CAAA,SAAAQ,CAAA,MAAAV,KAAA,yBAAAa,OAAA,KAAAb,KAAA,OAAAa,OAAA,KAAAb,KAAA,QAAAA,KAAA,CAAAc,GAAA,CAAAZ,CAAA,UAAAF,KAAA,CAAAe,GAAA,CAAAb,CAAA,GAAAF,KAAA,CAAAgB,GAAA,CAAAd,CAAA,EAAAQ,CAAA,UAAAJ,CAAA,IAAAJ,CAAA,gBAAAI,CAAA,OAAAW,cAAA,CAAAC,IAAA,CAAAhB,CAAA,EAAAI,CAAA,OAAAD,CAAA,GAAAE,CAAA,IAAAC,MAAA,CAAAW,wBAAA,CAAAjB,CAAA,EAAAI,CAAA,OAAAD,CAAA,CAAAU,GAAA,IAAAV,CAAA,CAAAW,GAAA,IAAAT,CAAA,CAAAG,CAAA,EAAAJ,CAAA,EAAAD,CAAA,IAAAK,CAAA,CAAAJ,CAAA,IAAAJ,CAAA,CAAAI,CAAA,WAAAI,CAAA;AAE1D,MAAMU,SAAS,GAAG,sBAAsB;;AAExC;AACA,IAAIC,MAA0B;AAEvB,MAAMC,aAAa,GAAAC,OAAA,CAAAD,aAAA,GAAG;EAC3B;AACF;AACA;EACE,MAAME,IAAIA,CAAA,EAAkB;IAC1B,IAAAC,kCAAgB,EAAC;MACfC,mBAAmB,EAAEC,gBAAS,CAACC,QAAQ,CAAC,CAAC;MACzCC,uBAAuB,EAAEF,gBAAS,CAACC,QAAQ,CAAC,CAAC;MAC7CE,uBAAuB,EAAEH,gBAAS,CAACC,QAAQ,CAAC,CAAC;MAC7CG,6BAA6B,EAAEJ,gBAAS,CAACC,QAAQ,CAAC;IACpD,CAAC,CAAC;IAEF,IAAI,CAACI,OAAO,CAACC,GAAG,CAACP,mBAAmB,EAClC,MAAM,IAAIQ,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;IAEJ,IAAAC,kBAAW,EAAC;MACVhB,SAAS;MACTe,OAAO,EAAE,mCAAmC;MAC5CE,IAAI,EAAE;QAAEC,IAAI,EAAEN,OAAO,CAACC,GAAG,CAACP;MAAoB;IAChD,CAAC,CAAC;IAEF,MAAMa,MAAqB,GAAG;MAC5BC,IAAI,EAAER,OAAO,CAACC,GAAG,CAACP,mBAAmB;MACrCe,IAAI,EAAE;QACJC,QAAQ,EAAEV,OAAO,CAACC,GAAG,CAACJ,uBAAiC;QACvDc,QAAQ,EAAEX,OAAO,CAACC,GAAG,CAACH;MACxB,CAAC;MACDc,UAAU,EAAE,CAAC;MACbC,cAAc,EAAE,KAAK;MACrBC,YAAY,EAAE;IAChB,CAAC;;IAED;IACA,IAAId,OAAO,CAACC,GAAG,CAACc,MAAM,EAAE;MACtBR,MAAM,CAACS,GAAG,GAAG;QACXC,EAAE,EAAEjB,OAAO,CAACC,GAAG,CAACc,MAAM;QACtBG,kBAAkB,EAAElB,OAAO,CAACC,GAAG,CAACkB,QAAQ,KAAK;MAC/C,CAAC;MACD,IAAAf,kBAAW,EAAC;QACVhB,SAAS;QACTe,OAAO,EAAE;MACX,CAAC,CAAC;IACJ;IAEAd,MAAM,GAAG,IAAI+B,qBAAM,CAACb,MAAM,CAAC;;IAE3B;IACA,IAAI;MACF,MAAMlB,MAAM,CAACgC,IAAI,CAAC,CAAC;MACnB,IAAAjB,kBAAW,EAAC;QACVhB,SAAS;QACTe,OAAO,EAAE;MACX,CAAC,CAAC;IACJ,CAAC,CAAC,OAAOmB,KAAK,EAAE;MACd,MAAM,IAAIpB,wBAAW,CAAC;QACpBC,OAAO,EAAE,oCAAoC;QAC7CE,IAAI,EAAE;UAAEiB,KAAK,EAAGA,KAAK,CAAWnB;QAAQ;MAC1C,CAAC,CAAC;IACJ;;IAEA;IACA,IAAIH,OAAO,CAACC,GAAG,CAACkB,QAAQ,KAAK,MAAM,EAAE;MACnC,IAAAf,kBAAW,EAAC;QACVhB,SAAS;QACTe,OAAO,EAAE;MACX,CAAC,CAAC;MACF,MAAMd,MAAM,CAACkC,OAAO,CAACC,MAAM,CAAC;QAAEC,KAAK,EAAE;MAAI,CAAC,CAAC;IAC7C;IAEA,MAAM,IAAI,CAACC,OAAO,CAAC,CAAC;IACpBC,wCAAmB,CAACC,QAAQ,CAAC,IAAI,CAAC;IAElC,IAAAC,iBAAU,EAAC;MAAE1B,OAAO,EAAE;IAAyC,CAAC,CAAC;EACnE,CAAC;EAED;AACF;AACA;EACE2B,SAASA,CAAA,EAAuB;IAC9B,OAAOzC,MAAM;EACf,CAAC;EAED;AACF;AACA;AACA;EACE,MAAMqC,OAAOA,CAAA,EAAkB;IAC7B,IAAI,CAACrC,MAAM,EAAE,MAAM,IAAIa,wBAAW,CAAC;MAAEC,OAAO,EAAE;IAAoC,CAAC,CAAC;IAEpF,IAAAC,kBAAW,EAAC;MACVhB,SAAS;MACTe,OAAO,EAAE;IACX,CAAC,CAAC;IAEF,MAAM4B,aAAa,GAAGC,aAAI,CAACC,OAAO,CAChCjC,OAAO,CAACC,GAAG,CAACF,6BACd,CAAC;IAED,IAAImC,KAAe;IACnB,IAAI;MACFA,KAAK,GAAG,IAAAC,eAAW,EAACJ,aAAa,CAAC,CAACK,MAAM,CACvCC,CAAC,IAAIA,CAAC,CAACC,QAAQ,CAAC,KAAK,CAAC,IAAID,CAAC,CAACC,QAAQ,CAAC,KAAK,CAC5C,CAAC;IACH,CAAC,CAAC,OAAOhB,KAAK,EAAE;MACd,MAAM,IAAIpB,wBAAW,CAAC;QACpBC,OAAO,EAAE,oCAAoC;QAC7CE,IAAI,EAAE;UAAE2B,IAAI,EAAED,aAAa;UAAET,KAAK,EAAGA,KAAK,CAAWnB;QAAQ;MAC/D,CAAC,CAAC;IACJ;IAEA,MAAMoC,WAAW,GAAG,MAAMlD,MAAM,CAACkC,OAAO,CAACiB,MAAM,CAAC;MAC9Cf,KAAK,EAAE;IACT,CAAC,CAAC;IAEF,MAAMgB,GAAa,GAAG,EAAE;IAExB,KAAK,MAAMC,IAAI,IAAIR,KAAK,EAAE;MACxB,IAAIK,WAAW,EAAE;QACf,MAAMI,MAAM,GAAG,MAAMtD,MAAM,CAACuD,MAAM,CAAC;UACjCnB,KAAK,EAAE,YAAY;UACnBoB,KAAK,EAAE;YAAEC,KAAK,EAAE;cAAEJ;YAAK;UAAE;QAC3B,CAAC,CAAC;QAEF,MAAMK,KAAK,GAAG,OAAOJ,MAAM,CAACK,IAAI,CAACD,KAAK,KAAK,QAAQ,GAC/CJ,MAAM,CAACK,IAAI,CAACD,KAAK,GACjBJ,MAAM,CAACK,IAAI,CAACD,KAAK,EAAEE,KAAK,IAAI,CAAC;QAEjC,IAAIF,KAAK,GAAG,CAAC,EAAE;UACb,IAAA3C,kBAAW,EAAC;YACVhB,SAAS;YACTe,OAAO,EAAE,sBAAsBuC,IAAI;UACrC,CAAC,CAAC;UACF;QACF;MACF;MAEA,IAAAtC,kBAAW,EAAC;QACVhB,SAAS;QACTe,OAAO,EAAE,sBAAsBuC,IAAI;MACrC,CAAC,CAAC;MAEFD,GAAG,CAACS,IAAI,CAACR,IAAI,CAAC;MAEd,IAAI;QACF,MAAMS,SAAS,GAAI,OAAAC,SAAA,QAAAC,OAAA,CAAAhF,CAAA,IAAAA,CAAA,CAAA+E,SAAA,GAAAE,IAAA,CAAAC,CAAA,IAAAtF,uBAAA,CAAAT,OAAA,CAAA+F,CAAA,KACjB,GAAGxB,aAAa,IAAIW,IAAI,EAAE,CACA;QAE5B,MAAMS,SAAS,CAACzB,OAAO,CAACrC,MAAM,CAAC;QAE/B,MAAMA,MAAM,CAACoC,KAAK,CAAC;UACjBA,KAAK,EAAE,YAAY;UACnB+B,EAAE,EAAEd,IAAI;UACRe,QAAQ,EAAE;YAAEf,IAAI;YAAEgB,KAAK,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC;UAAE;QACpD,CAAC,CAAC;QAEF,IAAAxD,kBAAW,EAAC;UACVhB,SAAS;UACTe,OAAO,EAAE,+BAA+BuC,IAAI;QAC9C,CAAC,CAAC;MACJ,CAAC,CAAC,OAAOpB,KAAK,EAAE;QACd,IAAAuC,kBAAW,EACT,IAAI3D,wBAAW,CAAC;UACdC,OAAO,EAAE,qBAAqBuC,IAAI,EAAE;UACpCrC,IAAI,EAAE;YAAEiB,KAAK,EAAGA,KAAK,CAAWnB,OAAO;YAAE2D,KAAK,EAAGxC,KAAK,CAAWwC;UAAM;QACzE,CAAC,CACH,CAAC;QACD,MAAMxC,KAAK;MACb;IACF;IAEA,IAAAO,iBAAU,EAAC;MACT1B,OAAO,EAAE,sBAAsBsC,GAAG,CAACsB,MAAM,eAAe;MACxD1D,IAAI,EAAE;QAAE6B,KAAK,EAAEO;MAAI;IACrB,CAAC,CAAC;EACJ,CAAC;EAED;AACF;AACA;EACE,MAAMuB,QAAQA,CAAA,EAAkB;IAC9B,IAAI3E,MAAM,EAAE;MACV,IAAI;QACF,MAAMA,MAAM,CAAC4E,KAAK,CAAC,CAAC;QACpB,IAAA7D,kBAAW,EAAC;UACVhB,SAAS;UACTe,OAAO,EAAE;QACX,CAAC,CAAC;MACJ,CAAC,CAAC,OAAOmB,KAAK,EAAE;QACd,IAAAuC,kBAAW,EACT,IAAI3D,wBAAW,CAAC;UACdC,OAAO,EAAE,qCAAqC;UAC9CE,IAAI,EAAE;YAAEiB,KAAK,EAAGA,KAAK,CAAWnB;UAAQ;QAC1C,CAAC,CACH,CAAC;MACH;MACAd,MAAM,GAAG6E,SAAS;IACpB;EACF;AACF,CAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"ElasticSearch.js","names":["_fs","require","_path","_interopRequireDefault","_elasticsearch","_EngineError","_LifecycleController","_utils","_checkEnvironment","cache","_interopRequireWildcard","e","t","__esModule","r","c","a","Object","defineProperty","n","__proto__","default","WeakMap","has","get","set","hasOwnProperty","call","getOwnPropertyDescriptor","namespace","client","ElasticSearch","exports","init","checkEnvironment","ELASTIC_SEARCH_HOST","envAssert","isString","ELASTIC_SEARCH_USERNAME","ELASTIC_SEARCH_PASSWORD","ELASTIC_SEARCH_MIGRATION_PATH","process","env","EngineError","message","reportDebug","data","host","config","node","auth","username","password","maxRetries","requestTimeout","sniffOnStart","TLS_CA","tls","ca","rejectUnauthorized","NODE_ENV","Client","ping","error","indices","delete","index","migrate","LifecycleController","register","reportInfo","getClient","migrationPath","path","resolve","files","readdirSync","filter","f","endsWith","indexExists","exists","ran","file","result","search","query","match","total","hits","value","push","migration","specifier","Promise","then","s","id","document","ranAt","Date","toISOString","reportError","stack","length","shutdown","close","undefined"],"sources":["../../../src/entities/ElasticSearch/ElasticSearch.ts"],"sourcesContent":["import { readdirSync } from 'fs';\nimport path from 'path';\nimport { Client, ClientOptions } from '@elastic/elasticsearch';\nimport { ElasticSearchMigration } from './ElasticSearch.types';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { envAssert, reportError, reportInfo, reportDebug } from 'utils';\nimport { checkEnvironment } from 'utils/checkEnvironment';\n\nconst namespace = 'engine:elasticsearch';\n\n/** Elastic search client */\nlet client: undefined | Client;\n\nexport const ElasticSearch = {\n /**\n * Init function that should be called on server startup to establish the connection\n */\n async init(): Promise<void> {\n checkEnvironment({\n ELASTIC_SEARCH_HOST: envAssert.isString(),\n ELASTIC_SEARCH_USERNAME: envAssert.isString(),\n ELASTIC_SEARCH_PASSWORD: envAssert.isString(),\n ELASTIC_SEARCH_MIGRATION_PATH: envAssert.isString()\n });\n\n if (!process.env.ELASTIC_SEARCH_HOST)\n throw new EngineError({\n message: 'ElasticSearch Host not set in environment'\n });\n\n reportDebug({\n namespace,\n message: 'Initializing ElasticSearch client',\n data: { host: process.env.ELASTIC_SEARCH_HOST }\n });\n\n const config: ClientOptions = {\n node: process.env.ELASTIC_SEARCH_HOST,\n auth: {\n username: process.env.ELASTIC_SEARCH_USERNAME as string,\n password: process.env.ELASTIC_SEARCH_PASSWORD as string\n },\n maxRetries: 3,\n requestTimeout: 30000,\n sniffOnStart: false\n };\n\n // Add TLS configuration if TLS_CA is provided\n if (process.env.TLS_CA) {\n config.tls = {\n ca: process.env.TLS_CA,\n rejectUnauthorized: process.env.NODE_ENV === 'production'\n };\n reportDebug({\n namespace,\n message: 'TLS enabled for ElasticSearch connection'\n });\n }\n\n client = new Client(config);\n\n // Verify connection\n try {\n await client.ping();\n reportDebug({\n namespace,\n message: 'ElasticSearch connection established'\n });\n } catch (error) {\n throw new EngineError({\n message: 'Failed to connect to ElasticSearch',\n data: { error: (error as Error).message }\n });\n }\n\n // In test environment flush the database before running migrations\n if (process.env.NODE_ENV === 'test') {\n reportDebug({\n namespace,\n message: 'Test environment detected, flushing all indices'\n });\n await client.indices.delete({ index: '*' });\n }\n\n await this.migrate();\n LifecycleController.register(this);\n\n reportInfo({ message: 'ElasticSearch initialized successfully' });\n },\n\n /**\n * Get the ElasticSearch client (for advanced use cases)\n */\n getClient(): Client | undefined {\n return client;\n },\n\n /**\n * Migration function called during the init process\n * Manages the database structure\n */\n async migrate(): Promise<void> {\n if (!client)\n throw new EngineError({ message: 'ElasticSearch was not initialized' });\n\n reportDebug({\n namespace,\n message: 'Starting ElasticSearch migrations'\n });\n\n const migrationPath = path.resolve(\n process.env.ELASTIC_SEARCH_MIGRATION_PATH as string\n );\n\n let files: string[];\n try {\n files = readdirSync(migrationPath).filter(\n (f) => f.endsWith('.ts') || f.endsWith('.js')\n );\n } catch (error) {\n throw new EngineError({\n message: 'Failed to read migration directory',\n data: { path: migrationPath, error: (error as Error).message }\n });\n }\n\n const indexExists = await client.indices.exists({\n index: 'migrations'\n });\n\n const ran: string[] = [];\n\n for (const file of files) {\n if (indexExists) {\n const result = await client.search({\n index: 'migrations',\n query: { match: { file } }\n });\n\n const total =\n typeof result.hits.total === 'number'\n ? result.hits.total\n : (result.hits.total?.value ?? 0);\n\n if (total > 0) {\n reportDebug({\n namespace,\n message: `Skipping migration ${file} (already ran)`\n });\n continue;\n }\n }\n\n reportDebug({\n namespace,\n message: `Running migration: ${file}`\n });\n\n ran.push(file);\n\n try {\n const migration = (await import(\n `${migrationPath}/${file}`\n )) as ElasticSearchMigration;\n\n await migration.migrate(client);\n\n await client.index({\n index: 'migrations',\n id: file,\n document: { file, ranAt: new Date().toISOString() }\n });\n\n reportDebug({\n namespace,\n message: `Successfully ran migration: ${file}`\n });\n } catch (error) {\n reportError(\n new EngineError({\n message: `Migration failed: ${file}`,\n data: {\n error: (error as Error).message,\n stack: (error as Error).stack\n }\n })\n );\n throw error;\n }\n }\n\n reportInfo({\n message: `ElasticSearch: ran ${ran.length} migration(s)`,\n data: { files: ran }\n });\n },\n\n /**\n * Shutdown function that should be called on server stop to close the connection\n */\n async shutdown(): Promise<void> {\n if (client) {\n try {\n await client.close();\n reportDebug({\n namespace,\n message: 'ElasticSearch client disconnected'\n });\n } catch (error) {\n reportError(\n new EngineError({\n message: 'Error during ElasticSearch shutdown',\n data: { error: (error as Error).message }\n })\n );\n }\n client = undefined;\n }\n }\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Endpoint.types.js","names":["_middleware","require","EndpointMethod","exports","EndpointMethods","Object","values","EndpointAuthType","EndpointAuthTypes","EndpointAuthHandlers","NONE","undefined","JWT","authJwt","TLS","authTls","HMAC","authHmac","STATIC","authStatic"],"sources":["../../../src/entities/Endpoint/Endpoint.types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n ErrorRequestHandler,\n Request,\n Response,\n NextFunction,\n RequestHandler\n} from 'express';\nimport { ParamsDictionary } from 'express-serve-static-core';\nimport { Schema } from 'express-validator';\nimport { ParsedQs } from 'qs';\n\nimport {\n authJwt,\n authHmac,\n authTls,\n authStatic,\n FileUploaderConfig\n} from 'middleware';\nimport { MultiPartFileUploaderConfig } from 'middleware/multiPartFileUploader/multiPartFileUploader.types';\n\nexport enum EndpointMethod {\n GET = 'get',\n POST = 'post',\n PUT = 'put',\n PATCH = 'patch',\n DELETE = 'delete',\n HEAD = 'head',\n ALL = 'all'\n}\n\nexport const EndpointMethods = Object.values(EndpointMethod);\n\nexport enum EndpointAuthType {\n NONE = 'none',\n JWT = 'jwt',\n TLS = 'tls',\n HMAC = 'hmac',\n STATIC = 'static'\n}\n\nexport const EndpointAuthTypes = Object.values(EndpointAuthType);\n\nexport type Middleware<T extends EndpointAuthType> = (\n request: EndpointRequestType[T],\n response: Response,\n next: NextFunction\n) => unknown | Promise<unknown>;\n\nexport type MiddlewareChainElement<T extends EndpointAuthType> =\n
|
|
1
|
+
{"version":3,"file":"Endpoint.types.js","names":["_middleware","require","EndpointMethod","exports","EndpointMethods","Object","values","EndpointAuthType","EndpointAuthTypes","EndpointAuthHandlers","NONE","undefined","JWT","authJwt","TLS","authTls","HMAC","authHmac","STATIC","authStatic"],"sources":["../../../src/entities/Endpoint/Endpoint.types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n ErrorRequestHandler,\n Request,\n Response,\n NextFunction,\n RequestHandler\n} from 'express';\nimport { ParamsDictionary } from 'express-serve-static-core';\nimport { Schema } from 'express-validator';\nimport { ParsedQs } from 'qs';\n\nimport {\n authJwt,\n authHmac,\n authTls,\n authStatic,\n FileUploaderConfig\n} from 'middleware';\nimport { MultiPartFileUploaderConfig } from 'middleware/multiPartFileUploader/multiPartFileUploader.types';\n\nexport enum EndpointMethod {\n GET = 'get',\n POST = 'post',\n PUT = 'put',\n PATCH = 'patch',\n DELETE = 'delete',\n HEAD = 'head',\n ALL = 'all'\n}\n\nexport const EndpointMethods = Object.values(EndpointMethod);\n\nexport enum EndpointAuthType {\n NONE = 'none',\n JWT = 'jwt',\n TLS = 'tls',\n HMAC = 'hmac',\n STATIC = 'static'\n}\n\nexport const EndpointAuthTypes = Object.values(EndpointAuthType);\n\nexport type Middleware<T extends EndpointAuthType> = (\n request: EndpointRequestType[T],\n response: Response,\n next: NextFunction\n) => unknown | Promise<unknown>;\n\nexport type MiddlewareChainElement<T extends EndpointAuthType> =\n Array<Middleware<T>> | Middleware<T> | any;\n\n/** Auth related parameters used with HMAC authentication */\ninterface EndpointAuthHmacParams {\n /** [HMAC] Secret used for signature */\n secret?: string;\n /** [HMAC] For Github webhook, the standard differs slightly, so this option must be selected */\n isGithub?: boolean;\n}\n\n/** Auth related parameters used with mTLS authentication */\ninterface EndpointAuthTlsParams {\n /** [TLS] List oh hosts that are allowed to use the endpoint, this is compared to the claims in the certificate */\n whitelist?: Array<string>;\n}\n\n/** Mapping used to get auth specific parameters depending on the auth type used */\ninterface EndpointAuthSpecificParams {\n /** Auth parameters for no authentication */\n [EndpointAuthType.NONE]: any;\n /** Auth parameters for JWT authentication */\n [EndpointAuthType.JWT]: any;\n /** Auth parameters for mTLS authentication */\n [EndpointAuthType.TLS]: EndpointAuthTlsParams;\n /** Auth parameters for HMAC authentication */\n [EndpointAuthType.HMAC]: EndpointAuthHmacParams;\n /** Auth parameters for static authentication */\n [EndpointAuthType.STATIC]: any;\n}\n\nexport type EndpointAuthParams<T extends EndpointAuthType> =\n EndpointAuthSpecificParams[T] & {\n /** This will allow the business logic to run event if the authentication fails */\n acceptInvalid?: boolean;\n };\n\nexport type EndpointAuthHandler<T extends EndpointAuthType> = (\n options?: EndpointAuthParams<T>\n) => (\n request: Request,\n response: Response,\n next: NextFunction\n) => void | Promise<void>;\n\nexport const EndpointAuthHandlers = {\n /** Auth handler for no authentication */\n [EndpointAuthType.NONE]: undefined,\n /** Auth handler for JWT authentication */\n [EndpointAuthType.JWT]: authJwt,\n /** Auth handler for mTLS authentication */\n [EndpointAuthType.TLS]: authTls,\n /** Auth handler for HMAC authentication */\n [EndpointAuthType.HMAC]: authHmac,\n /** Auth handler for static authentication */\n [EndpointAuthType.STATIC]: authStatic\n};\n\nexport type EndpointHandler<T extends EndpointAuthType> = (\n request: EndpointRequestType[T],\n response: Response\n) => void | Promise<void>;\n\n/** Endpoint initialization options */\nexport interface EndpointOptions<T extends EndpointAuthType> {\n /** Path at which the endpoint is reachable */\n path: string;\n /** HTTP method of the endpoint */\n method: EndpointMethod;\n /** Function handling the endpoint's business logic */\n handler: EndpointHandler<T>;\n /** Validation schema that the request must pass before reaching the handler */\n validator: Schema;\n /** Authentication system required by this endpoint */\n authType: T;\n /** Authentication related options for this endpoint */\n authParams?: EndpointAuthParams<T>;\n /** @deprecated Setting to upload a file through this endpoint */\n file?: FileUploaderConfig;\n /** Settings to upload files through this endpoint (this will automatically switch the expected request to be a multipart) */\n files?: Array<FileUploaderConfig>;\n /** Settings to upload file parts (Chunks) through this endpoint (this will automatically switch the expected request to be a multipart) */\n multiPartFile?: MultiPartFileUploaderConfig;\n /** Express request handlers that should run on this endpoint before the business logic, they will run after the global middleware */\n middleware?: MiddlewareChainElement<T>;\n /** Express error handlers that should be registered for this endpoint. they will run before the global error handler */\n errorMiddleware?: ErrorRequestHandler | Array<ErrorRequestHandler>;\n}\n\n/** Request type when using JWT authentication */\nexport interface JwtRequest<\n P = ParamsDictionary,\n ResBody = any,\n ReqBody = any,\n ReqQuery = ParsedQs,\n Locals extends Record<string, any> = Record<string, any>\n> extends Request<P, ResBody, ReqBody, ReqQuery, Locals> {\n /** User that identified using a JWT */\n user: Record<string, any> | any;\n}\n\n/** Request type when using mTLS authentication */\nexport interface TlsRequest<\n P = ParamsDictionary,\n ResBody = any,\n ReqBody = any,\n ReqQuery = ParsedQs,\n Locals extends Record<string, any> = Record<string, any>\n> extends Request<P, ResBody, ReqBody, ReqQuery, Locals> {\n /** Host names provided by the mTLS authenticated client */\n hosts: Array<string>;\n}\n\n/** Mapping of request types in endpoints based on auth type used */\nexport interface EndpointRequestType {\n /** Request type for no authentication */\n [EndpointAuthType.NONE]: Request;\n /** Request type when using JWT authentication */\n [EndpointAuthType.JWT]: JwtRequest;\n /** Request type when using mTLS authentication */\n [EndpointAuthType.TLS]: TlsRequest;\n /** Request type when using HMAC authentication */\n [EndpointAuthType.HMAC]: Request;\n /** Auth handler for static authentication */\n [EndpointAuthType.STATIC]: Request;\n}\n\nexport type SafeMiddleWareChain = Array<\n RequestHandler | ErrorRequestHandler | SafeMiddleWareChain\n>;\n"],"mappings":";;;;;;AAYA,IAAAA,WAAA,GAAAC,OAAA;AAZA;AAAA,IAqBYC,cAAc,GAAAC,OAAA,CAAAD,cAAA,0BAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAA,OAAdA,cAAc;AAAA;AAUnB,MAAME,eAAe,GAAAD,OAAA,CAAAC,eAAA,GAAGC,MAAM,CAACC,MAAM,CAACJ,cAAc,CAAC;AAAC,IAEjDK,gBAAgB,GAAAJ,OAAA,CAAAI,gBAAA,0BAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAA,OAAhBA,gBAAgB;AAAA;AAQrB,MAAMC,iBAAiB,GAAAL,OAAA,CAAAK,iBAAA,GAAGH,MAAM,CAACC,MAAM,CAACC,gBAAgB,CAAC;;AAWhE;;AAQA;;AAMA;;AA4BO,MAAME,oBAAoB,GAAAN,OAAA,CAAAM,oBAAA,GAAG;EAClC;EACA,CAACF,gBAAgB,CAACG,IAAI,GAAGC,SAAS;EAClC;EACA,CAACJ,gBAAgB,CAACK,GAAG,GAAGC,mBAAO;EAC/B;EACA,CAACN,gBAAgB,CAACO,GAAG,GAAGC,mBAAO;EAC/B;EACA,CAACR,gBAAgB,CAACS,IAAI,GAAGC,oBAAQ;EACjC;EACA,CAACV,gBAAgB,CAACW,MAAM,GAAGC;AAC7B,CAAC;;AAOD;;AA0BA;;AAYA;;AAYA","ignoreList":[]}
|
|
@@ -17,7 +17,7 @@ const namespace = 'engine:google-cloud-storage';
|
|
|
17
17
|
/**
|
|
18
18
|
* Generic Google Cloud Storage wrapper for easy file operations
|
|
19
19
|
* Provides methods for uploading, downloading, streaming, and deleting files
|
|
20
|
-
*
|
|
20
|
+
*
|
|
21
21
|
* @example
|
|
22
22
|
* ```typescript
|
|
23
23
|
* // Initialize with custom configuration
|
|
@@ -25,17 +25,17 @@ const namespace = 'engine:google-cloud-storage';
|
|
|
25
25
|
* projectId: 'my-project',
|
|
26
26
|
* keyFilename: '/path/to/keyfile.json'
|
|
27
27
|
* });
|
|
28
|
-
*
|
|
28
|
+
*
|
|
29
29
|
* // Upload a file
|
|
30
30
|
* const result = await GoogleCloudStorage.upload(
|
|
31
31
|
* fileStream,
|
|
32
32
|
* 'my-bucket',
|
|
33
33
|
* { directory: 'uploads', mime: 'image/png' }
|
|
34
34
|
* );
|
|
35
|
-
*
|
|
35
|
+
*
|
|
36
36
|
* // Download a file
|
|
37
37
|
* const { data, metadata } = await GoogleCloudStorage.get('my-bucket', 'uploads/file.png');
|
|
38
|
-
*
|
|
38
|
+
*
|
|
39
39
|
* // Delete a file
|
|
40
40
|
* await GoogleCloudStorage.delete('my-bucket', 'uploads/file.png');
|
|
41
41
|
* ```
|
|
@@ -88,7 +88,7 @@ const GoogleCloudStorage = exports.GoogleCloudStorage = {
|
|
|
88
88
|
* @param storageOptions - Google Cloud Storage write stream options
|
|
89
89
|
* @param uploaderOptions - Additional options like maxSize
|
|
90
90
|
* @returns Promise with file metadata
|
|
91
|
-
*
|
|
91
|
+
*
|
|
92
92
|
* @example
|
|
93
93
|
* ```typescript
|
|
94
94
|
* const fileStream = fs.createReadStream('photo.jpg');
|
|
@@ -204,7 +204,7 @@ const GoogleCloudStorage = exports.GoogleCloudStorage = {
|
|
|
204
204
|
* @param bucket - Bucket name
|
|
205
205
|
* @param path - File path in the bucket
|
|
206
206
|
* @returns Promise with file data and metadata
|
|
207
|
-
*
|
|
207
|
+
*
|
|
208
208
|
* @example
|
|
209
209
|
* ```typescript
|
|
210
210
|
* const { data, metadata } = await GoogleCloudStorage.get('my-bucket', 'photos/image.jpg');
|
|
@@ -236,7 +236,7 @@ const GoogleCloudStorage = exports.GoogleCloudStorage = {
|
|
|
236
236
|
* @param bucket - Bucket name
|
|
237
237
|
* @param path - File path in the bucket
|
|
238
238
|
* @returns Promise with readable stream and metadata
|
|
239
|
-
*
|
|
239
|
+
*
|
|
240
240
|
* @example
|
|
241
241
|
* ```typescript
|
|
242
242
|
* const { stream, metadata } = await GoogleCloudStorage.download('my-bucket', 'videos/video.mp4');
|
|
@@ -267,7 +267,7 @@ const GoogleCloudStorage = exports.GoogleCloudStorage = {
|
|
|
267
267
|
* @param bucket - Bucket name
|
|
268
268
|
* @param path - File path in the bucket
|
|
269
269
|
* @returns Readable stream
|
|
270
|
-
*
|
|
270
|
+
*
|
|
271
271
|
* @example
|
|
272
272
|
* ```typescript
|
|
273
273
|
* const stream = GoogleCloudStorage.getFileStream('my-bucket', 'audio/song.mp3');
|
|
@@ -292,7 +292,7 @@ const GoogleCloudStorage = exports.GoogleCloudStorage = {
|
|
|
292
292
|
* @param bucket - Bucket name
|
|
293
293
|
* @param path - File path in the bucket
|
|
294
294
|
* @returns Promise that resolves when deletion is complete
|
|
295
|
-
*
|
|
295
|
+
*
|
|
296
296
|
* @example
|
|
297
297
|
* ```typescript
|
|
298
298
|
* await GoogleCloudStorage.delete('my-bucket', 'temp/old-file.txt');
|
|
@@ -315,13 +315,13 @@ const GoogleCloudStorage = exports.GoogleCloudStorage = {
|
|
|
315
315
|
* Useful for creating unique file names
|
|
316
316
|
* @param options - Options for file destination generation
|
|
317
317
|
* @returns Generated file path
|
|
318
|
-
*
|
|
318
|
+
*
|
|
319
319
|
* @example
|
|
320
320
|
* ```typescript
|
|
321
321
|
* // Generate UUID only
|
|
322
322
|
* const path1 = GoogleCloudStorage.generateFileDestination();
|
|
323
323
|
* // 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
|
324
|
-
*
|
|
324
|
+
*
|
|
325
325
|
* // With directory and MIME type
|
|
326
326
|
* const path2 = GoogleCloudStorage.generateFileDestination({
|
|
327
327
|
* directory: 'uploads/images',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleCloudStorage.js","names":["_crypto","require","_storage","_filesizeParser","_interopRequireDefault","_mimeTypes","_WebError","_report","_trimPathSlash","namespace","GoogleCloudStorage","exports","cloudStorage","init","config","storageConfig","projectId","keyFilename","credentials","apiEndpoint","process","env","GC_PROJECT","GOOGLE_APPLICATION_CREDENTIALS","CloudStorage","reportDebug","message","data","getStorageInstance","upload","readStream","bucket","destinationOptions","storageOptions","uploaderOptions","storage","maxSize","file","fileName","directory","trimmedDirectory","trimPathSlash","path","generateFileDestination","exists","Promise","resolve","reject","receivedSize","writeStream","createWriteStream","intMaxSize","fileSizeParser","on","length","WebError","statusCode","errorCode","hint","write","err","end","metadata","getMetadata","catch","error","get","all","download","stream","createReadStream","getFileStream","delete","options","mime","noExtension","extension","mimeTypes","undefined","fullName","randomUUID"],"sources":["../../../src/entities/GoogleCloudStorage/GoogleCloudStorage.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport { Readable } from 'stream';\nimport {\n Storage as CloudStorage,\n CreateWriteStreamOptions,\n File,\n StorageOptions\n} from '@google-cloud/storage';\nimport fileSizeParser from 'filesize-parser';\nimport mimeTypes from 'mime-types';\nimport {\n UploadDestinationOptions,\n StorageUploadedFile,\n UploaderOptions,\n StorageGetResponse,\n StorageDownloadResponse,\n GoogleCloudStorageConfig\n} from './GoogleCloudStorage.types';\nimport { WebError } from 'entities/WebError';\nimport { reportDebug } from 'utils/report';\nimport { trimPathSlash } from 'utils/trimPathSlash';\n\nconst namespace = 'engine:google-cloud-storage';\n\n/**\n * Generic Google Cloud Storage wrapper for easy file operations\n * Provides methods for uploading, downloading, streaming, and deleting files\n * \n * @example\n * ```typescript\n * // Initialize with custom configuration\n * GoogleCloudStorage.init({\n * projectId: 'my-project',\n * keyFilename: '/path/to/keyfile.json'\n * });\n * \n * // Upload a file\n * const result = await GoogleCloudStorage.upload(\n * fileStream,\n * 'my-bucket',\n * { directory: 'uploads', mime: 'image/png' }\n * );\n * \n * // Download a file\n * const { data, metadata } = await GoogleCloudStorage.get('my-bucket', 'uploads/file.png');\n * \n * // Delete a file\n * await GoogleCloudStorage.delete('my-bucket', 'uploads/file.png');\n * ```\n */\nexport const GoogleCloudStorage = {\n cloudStorage: null as CloudStorage | null,\n\n /**\n * Initialize Google Cloud Storage with configuration\n * Call this method before using any other methods\n * @param config - Google Cloud Storage configuration options\n */\n init(config?: GoogleCloudStorageConfig): void {\n const storageConfig: StorageOptions = {};\n\n if (config) {\n if (config.projectId) storageConfig.projectId = config.projectId;\n if (config.keyFilename) storageConfig.keyFilename = config.keyFilename;\n if (config.credentials) storageConfig.credentials = config.credentials;\n if (config.apiEndpoint) storageConfig.apiEndpoint = config.apiEndpoint;\n } else {\n // Use environment variables as fallback\n if (process.env.GC_PROJECT) storageConfig.projectId = process.env.GC_PROJECT;\n if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {\n storageConfig.keyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n }\n }\n\n this.cloudStorage = new CloudStorage(storageConfig);\n reportDebug({\n namespace,\n message: 'Google Cloud Storage initialized',\n data: { projectId: storageConfig.projectId }\n });\n },\n\n /**\n * Get the Cloud Storage instance (auto-initializes if needed)\n * @private\n */\n getStorageInstance(): CloudStorage {\n if (!this.cloudStorage) {\n this.init();\n }\n return this.cloudStorage!;\n },\n\n /**\n * Upload a file to Google Cloud Storage\n * @param readStream - Readable stream of the file content\n * @param bucket - Bucket name where the file should be stored\n * @param destinationOptions - Options for file destination (directory, fileName, etc.)\n * @param storageOptions - Google Cloud Storage write stream options\n * @param uploaderOptions - Additional options like maxSize\n * @returns Promise with file metadata\n * \n * @example\n * ```typescript\n * const fileStream = fs.createReadStream('photo.jpg');\n * const result = await GoogleCloudStorage.upload(\n * fileStream,\n * 'my-bucket',\n * { directory: 'photos', mime: 'image/jpeg' },\n * { metadata: { contentType: 'image/jpeg' } },\n * { maxSize: '5MB' }\n * );\n * console.log(result.name); // photos/uuid.jpeg\n * ```\n */\n async upload(\n readStream: Readable,\n bucket: string,\n destinationOptions: UploadDestinationOptions = {},\n storageOptions: CreateWriteStreamOptions = {},\n uploaderOptions: UploaderOptions = {}\n ): Promise<StorageUploadedFile> {\n const storage = this.getStorageInstance();\n const { maxSize } = uploaderOptions;\n\n let file: File;\n reportDebug({\n namespace,\n message: 'Uploading file to storage',\n data: { bucket, destinationOptions, storageOptions, uploaderOptions }\n });\n\n // Generate the file path\n const { fileName, directory } = destinationOptions;\n\n // Upload file with given file name\n if (fileName) {\n const trimmedDirectory = trimPathSlash(directory ?? '/');\n const path = trimmedDirectory ? `${trimmedDirectory}/${fileName}` : fileName;\n file = storage.bucket(bucket).file(path);\n }\n // Generate random destination for file and check that it is not already occupied\n else {\n do {\n const path = this.generateFileDestination(destinationOptions);\n file = storage.bucket(bucket).file(path);\n } while ((await file.exists())[0]);\n }\n\n // Pipe user's file stream to the storage\n return new Promise((resolve, reject) => {\n let receivedSize = 0;\n const writeStream = file.createWriteStream(storageOptions);\n const intMaxSize = maxSize && fileSizeParser(maxSize);\n \n // Calculate transferred size and write to storage stream\n readStream.on('data', function (data: Buffer) {\n receivedSize += data.length;\n // Fail if transferred data over max size\n if (intMaxSize && receivedSize > intMaxSize) {\n reject(\n new WebError({\n statusCode: 413,\n errorCode: 'file-too-large',\n message: 'File size exceeds the maximum allowed limit',\n hint: { maxSize },\n data: {\n bucket,\n destinationOptions,\n storageOptions,\n receivedSize,\n maxSize\n }\n })\n );\n return;\n }\n writeStream.write(data);\n });\n \n // Error handling\n readStream.on('error', (err) => {\n reject(err);\n });\n writeStream.on('error', (err) => {\n reject(err);\n });\n \n // Graceful termination of the read\n readStream.on('end', () => {\n writeStream.end();\n });\n \n // Graceful termination of the write\n writeStream.on('finish', () => {\n (async (): Promise<void> => {\n const [metadata] = (await file.getMetadata()) as [\n StorageUploadedFile,\n unknown\n ];\n reportDebug({\n namespace,\n message: 'File uploaded to storage',\n data: metadata\n });\n resolve(metadata);\n })().catch((error) => {\n reject(error);\n });\n });\n });\n },\n\n /**\n * Download a file from Google Cloud Storage and return its content as Buffer\n * @param bucket - Bucket name\n * @param path - File path in the bucket\n * @returns Promise with file data and metadata\n * \n * @example\n * ```typescript\n * const { data, metadata } = await GoogleCloudStorage.get('my-bucket', 'photos/image.jpg');\n * console.log(metadata.size); // File size in bytes\n * console.log(data); // Buffer with file content\n * ```\n */\n async get(bucket: string, path: string): Promise<StorageGetResponse> {\n const storage = this.getStorageInstance();\n const file = storage.bucket(bucket).file(path);\n const [[metadata], [data]] = (await Promise.all([\n file.getMetadata(),\n file.download()\n ])) as [[StorageUploadedFile, unknown], [Buffer]];\n reportDebug({\n namespace,\n message: 'Downloaded file from storage',\n data: { bucket, path, metadata }\n });\n return {\n data,\n metadata\n };\n },\n\n /**\n * Get a readable stream for a file from Google Cloud Storage\n * Use this for large files or when you need to stream the content\n * @param bucket - Bucket name\n * @param path - File path in the bucket\n * @returns Promise with readable stream and metadata\n * \n * @example\n * ```typescript\n * const { stream, metadata } = await GoogleCloudStorage.download('my-bucket', 'videos/video.mp4');\n * stream.pipe(res); // Stream to HTTP response\n * ```\n */\n async download(\n bucket: string,\n path: string\n ): Promise<StorageDownloadResponse> {\n const storage = this.getStorageInstance();\n const file = storage.bucket(bucket).file(path);\n const [metadata] = (await file.getMetadata()) as [\n StorageUploadedFile,\n unknown\n ];\n reportDebug({\n namespace,\n message: 'Fetched file stream from storage',\n data: { bucket, path, metadata }\n });\n return {\n stream: file.createReadStream(),\n metadata\n };\n },\n\n /**\n * Get a readable stream for a file (without fetching metadata)\n * Use this when you don't need metadata and want faster streaming\n * @param bucket - Bucket name\n * @param path - File path in the bucket\n * @returns Readable stream\n * \n * @example\n * ```typescript\n * const stream = GoogleCloudStorage.getFileStream('my-bucket', 'audio/song.mp3');\n * stream.pipe(res); // Direct streaming without metadata fetch\n * ```\n */\n getFileStream(bucket: string, path: string): Readable {\n const storage = this.getStorageInstance();\n const file = storage.bucket(bucket).file(path);\n reportDebug({\n namespace,\n message: \"Fetched file stream from storage's bucket\",\n data: { bucket, path }\n });\n return file.createReadStream();\n },\n\n /**\n * Delete a file from Google Cloud Storage\n * @param bucket - Bucket name\n * @param path - File path in the bucket\n * @returns Promise that resolves when deletion is complete\n * \n * @example\n * ```typescript\n * await GoogleCloudStorage.delete('my-bucket', 'temp/old-file.txt');\n * ```\n */\n async delete(bucket: string, path: string): Promise<void> {\n const storage = this.getStorageInstance();\n reportDebug({\n namespace,\n message: 'Deleting file from storage',\n data: { bucket, path }\n });\n await storage.bucket(bucket).file(path).delete();\n },\n\n /**\n * Generate a random file path with optional directory and extension\n * Useful for creating unique file names\n * @param options - Options for file destination generation\n * @returns Generated file path\n * \n * @example\n * ```typescript\n * // Generate UUID only\n * const path1 = GoogleCloudStorage.generateFileDestination();\n * // 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'\n * \n * // With directory and MIME type\n * const path2 = GoogleCloudStorage.generateFileDestination({\n * directory: 'uploads/images',\n * mime: 'image/jpeg'\n * });\n * // 'uploads/images/a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpeg'\n * ```\n */\n generateFileDestination(options: UploadDestinationOptions = {}): string {\n const { directory = '/', mime, noExtension = false } = options;\n\n // Determine file extension from MIME type\n const extension =\n mime && mimeTypes.extension(mime) ? mimeTypes.extension(mime) : undefined;\n \n // Build the full name with or without extension\n const fullName =\n extension && !noExtension ? `${randomUUID()}.${extension}` : randomUUID();\n \n // Clean up directory path\n const trimmedDirectory = trimPathSlash(directory);\n return `${trimmedDirectory ? `${trimmedDirectory}/` : ''}${fullName}`;\n }\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"GoogleCloudStorage.js","names":["_crypto","require","_storage","_filesizeParser","_interopRequireDefault","_mimeTypes","_WebError","_report","_trimPathSlash","namespace","GoogleCloudStorage","exports","cloudStorage","init","config","storageConfig","projectId","keyFilename","credentials","apiEndpoint","process","env","GC_PROJECT","GOOGLE_APPLICATION_CREDENTIALS","CloudStorage","reportDebug","message","data","getStorageInstance","upload","readStream","bucket","destinationOptions","storageOptions","uploaderOptions","storage","maxSize","file","fileName","directory","trimmedDirectory","trimPathSlash","path","generateFileDestination","exists","Promise","resolve","reject","receivedSize","writeStream","createWriteStream","intMaxSize","fileSizeParser","on","length","WebError","statusCode","errorCode","hint","write","err","end","metadata","getMetadata","catch","error","get","all","download","stream","createReadStream","getFileStream","delete","options","mime","noExtension","extension","mimeTypes","undefined","fullName","randomUUID"],"sources":["../../../src/entities/GoogleCloudStorage/GoogleCloudStorage.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport { Readable } from 'stream';\nimport {\n Storage as CloudStorage,\n CreateWriteStreamOptions,\n File,\n StorageOptions\n} from '@google-cloud/storage';\nimport fileSizeParser from 'filesize-parser';\nimport mimeTypes from 'mime-types';\nimport {\n UploadDestinationOptions,\n StorageUploadedFile,\n UploaderOptions,\n StorageGetResponse,\n StorageDownloadResponse,\n GoogleCloudStorageConfig\n} from './GoogleCloudStorage.types';\nimport { WebError } from 'entities/WebError';\nimport { reportDebug } from 'utils/report';\nimport { trimPathSlash } from 'utils/trimPathSlash';\n\nconst namespace = 'engine:google-cloud-storage';\n\n/**\n * Generic Google Cloud Storage wrapper for easy file operations\n * Provides methods for uploading, downloading, streaming, and deleting files\n *\n * @example\n * ```typescript\n * // Initialize with custom configuration\n * GoogleCloudStorage.init({\n * projectId: 'my-project',\n * keyFilename: '/path/to/keyfile.json'\n * });\n *\n * // Upload a file\n * const result = await GoogleCloudStorage.upload(\n * fileStream,\n * 'my-bucket',\n * { directory: 'uploads', mime: 'image/png' }\n * );\n *\n * // Download a file\n * const { data, metadata } = await GoogleCloudStorage.get('my-bucket', 'uploads/file.png');\n *\n * // Delete a file\n * await GoogleCloudStorage.delete('my-bucket', 'uploads/file.png');\n * ```\n */\nexport const GoogleCloudStorage = {\n cloudStorage: null as CloudStorage | null,\n\n /**\n * Initialize Google Cloud Storage with configuration\n * Call this method before using any other methods\n * @param config - Google Cloud Storage configuration options\n */\n init(config?: GoogleCloudStorageConfig): void {\n const storageConfig: StorageOptions = {};\n\n if (config) {\n if (config.projectId) storageConfig.projectId = config.projectId;\n if (config.keyFilename) storageConfig.keyFilename = config.keyFilename;\n if (config.credentials) storageConfig.credentials = config.credentials;\n if (config.apiEndpoint) storageConfig.apiEndpoint = config.apiEndpoint;\n } else {\n // Use environment variables as fallback\n if (process.env.GC_PROJECT)\n storageConfig.projectId = process.env.GC_PROJECT;\n if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {\n storageConfig.keyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n }\n }\n\n this.cloudStorage = new CloudStorage(storageConfig);\n reportDebug({\n namespace,\n message: 'Google Cloud Storage initialized',\n data: { projectId: storageConfig.projectId }\n });\n },\n\n /**\n * Get the Cloud Storage instance (auto-initializes if needed)\n * @private\n */\n getStorageInstance(): CloudStorage {\n if (!this.cloudStorage) {\n this.init();\n }\n return this.cloudStorage!;\n },\n\n /**\n * Upload a file to Google Cloud Storage\n * @param readStream - Readable stream of the file content\n * @param bucket - Bucket name where the file should be stored\n * @param destinationOptions - Options for file destination (directory, fileName, etc.)\n * @param storageOptions - Google Cloud Storage write stream options\n * @param uploaderOptions - Additional options like maxSize\n * @returns Promise with file metadata\n *\n * @example\n * ```typescript\n * const fileStream = fs.createReadStream('photo.jpg');\n * const result = await GoogleCloudStorage.upload(\n * fileStream,\n * 'my-bucket',\n * { directory: 'photos', mime: 'image/jpeg' },\n * { metadata: { contentType: 'image/jpeg' } },\n * { maxSize: '5MB' }\n * );\n * console.log(result.name); // photos/uuid.jpeg\n * ```\n */\n async upload(\n readStream: Readable,\n bucket: string,\n destinationOptions: UploadDestinationOptions = {},\n storageOptions: CreateWriteStreamOptions = {},\n uploaderOptions: UploaderOptions = {}\n ): Promise<StorageUploadedFile> {\n const storage = this.getStorageInstance();\n const { maxSize } = uploaderOptions;\n\n let file: File;\n reportDebug({\n namespace,\n message: 'Uploading file to storage',\n data: { bucket, destinationOptions, storageOptions, uploaderOptions }\n });\n\n // Generate the file path\n const { fileName, directory } = destinationOptions;\n\n // Upload file with given file name\n if (fileName) {\n const trimmedDirectory = trimPathSlash(directory ?? '/');\n const path = trimmedDirectory\n ? `${trimmedDirectory}/${fileName}`\n : fileName;\n file = storage.bucket(bucket).file(path);\n }\n // Generate random destination for file and check that it is not already occupied\n else {\n do {\n const path = this.generateFileDestination(destinationOptions);\n file = storage.bucket(bucket).file(path);\n } while ((await file.exists())[0]);\n }\n\n // Pipe user's file stream to the storage\n return new Promise((resolve, reject) => {\n let receivedSize = 0;\n const writeStream = file.createWriteStream(storageOptions);\n const intMaxSize = maxSize && fileSizeParser(maxSize);\n\n // Calculate transferred size and write to storage stream\n readStream.on('data', function (data: Buffer) {\n receivedSize += data.length;\n // Fail if transferred data over max size\n if (intMaxSize && receivedSize > intMaxSize) {\n reject(\n new WebError({\n statusCode: 413,\n errorCode: 'file-too-large',\n message: 'File size exceeds the maximum allowed limit',\n hint: { maxSize },\n data: {\n bucket,\n destinationOptions,\n storageOptions,\n receivedSize,\n maxSize\n }\n })\n );\n return;\n }\n writeStream.write(data);\n });\n\n // Error handling\n readStream.on('error', (err) => {\n reject(err);\n });\n writeStream.on('error', (err) => {\n reject(err);\n });\n\n // Graceful termination of the read\n readStream.on('end', () => {\n writeStream.end();\n });\n\n // Graceful termination of the write\n writeStream.on('finish', () => {\n (async (): Promise<void> => {\n const [metadata] = (await file.getMetadata()) as [\n StorageUploadedFile,\n unknown\n ];\n reportDebug({\n namespace,\n message: 'File uploaded to storage',\n data: metadata\n });\n resolve(metadata);\n })().catch((error) => {\n reject(error);\n });\n });\n });\n },\n\n /**\n * Download a file from Google Cloud Storage and return its content as Buffer\n * @param bucket - Bucket name\n * @param path - File path in the bucket\n * @returns Promise with file data and metadata\n *\n * @example\n * ```typescript\n * const { data, metadata } = await GoogleCloudStorage.get('my-bucket', 'photos/image.jpg');\n * console.log(metadata.size); // File size in bytes\n * console.log(data); // Buffer with file content\n * ```\n */\n async get(bucket: string, path: string): Promise<StorageGetResponse> {\n const storage = this.getStorageInstance();\n const file = storage.bucket(bucket).file(path);\n const [[metadata], [data]] = (await Promise.all([\n file.getMetadata(),\n file.download()\n ])) as [[StorageUploadedFile, unknown], [Buffer]];\n reportDebug({\n namespace,\n message: 'Downloaded file from storage',\n data: { bucket, path, metadata }\n });\n return {\n data,\n metadata\n };\n },\n\n /**\n * Get a readable stream for a file from Google Cloud Storage\n * Use this for large files or when you need to stream the content\n * @param bucket - Bucket name\n * @param path - File path in the bucket\n * @returns Promise with readable stream and metadata\n *\n * @example\n * ```typescript\n * const { stream, metadata } = await GoogleCloudStorage.download('my-bucket', 'videos/video.mp4');\n * stream.pipe(res); // Stream to HTTP response\n * ```\n */\n async download(\n bucket: string,\n path: string\n ): Promise<StorageDownloadResponse> {\n const storage = this.getStorageInstance();\n const file = storage.bucket(bucket).file(path);\n const [metadata] = (await file.getMetadata()) as [\n StorageUploadedFile,\n unknown\n ];\n reportDebug({\n namespace,\n message: 'Fetched file stream from storage',\n data: { bucket, path, metadata }\n });\n return {\n stream: file.createReadStream(),\n metadata\n };\n },\n\n /**\n * Get a readable stream for a file (without fetching metadata)\n * Use this when you don't need metadata and want faster streaming\n * @param bucket - Bucket name\n * @param path - File path in the bucket\n * @returns Readable stream\n *\n * @example\n * ```typescript\n * const stream = GoogleCloudStorage.getFileStream('my-bucket', 'audio/song.mp3');\n * stream.pipe(res); // Direct streaming without metadata fetch\n * ```\n */\n getFileStream(bucket: string, path: string): Readable {\n const storage = this.getStorageInstance();\n const file = storage.bucket(bucket).file(path);\n reportDebug({\n namespace,\n message: \"Fetched file stream from storage's bucket\",\n data: { bucket, path }\n });\n return file.createReadStream();\n },\n\n /**\n * Delete a file from Google Cloud Storage\n * @param bucket - Bucket name\n * @param path - File path in the bucket\n * @returns Promise that resolves when deletion is complete\n *\n * @example\n * ```typescript\n * await GoogleCloudStorage.delete('my-bucket', 'temp/old-file.txt');\n * ```\n */\n async delete(bucket: string, path: string): Promise<void> {\n const storage = this.getStorageInstance();\n reportDebug({\n namespace,\n message: 'Deleting file from storage',\n data: { bucket, path }\n });\n await storage.bucket(bucket).file(path).delete();\n },\n\n /**\n * Generate a random file path with optional directory and extension\n * Useful for creating unique file names\n * @param options - Options for file destination generation\n * @returns Generated file path\n *\n * @example\n * ```typescript\n * // Generate UUID only\n * const path1 = GoogleCloudStorage.generateFileDestination();\n * // 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'\n *\n * // With directory and MIME type\n * const path2 = GoogleCloudStorage.generateFileDestination({\n * directory: 'uploads/images',\n * mime: 'image/jpeg'\n * });\n * // 'uploads/images/a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpeg'\n * ```\n */\n generateFileDestination(options: UploadDestinationOptions = {}): string {\n const { directory = '/', mime, noExtension = false } = options;\n\n // Determine file extension from MIME type\n const extension =\n mime && mimeTypes.extension(mime) ? mimeTypes.extension(mime) : undefined;\n\n // Build the full name with or without extension\n const fullName =\n extension && !noExtension ? `${randomUUID()}.${extension}` : randomUUID();\n\n // Clean up directory path\n const trimmedDirectory = trimPathSlash(directory);\n return `${trimmedDirectory ? `${trimmedDirectory}/` : ''}${fullName}`;\n }\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeySet.js","names":["_crypto","require","_fs","_const","_EngineError","_report","_request","_tlsRequest","namespace","KEY_REFRESH_INTERVAL","KeySet","exports","url","options","_classCallCheck2","default","_defineProperty2","internal","file","pem","_createClass2","key","value","init","fetch","interval","setInterval","error","reportError","catch","shutdown","clearInterval","getKey","keyId","keySet","getKeys","reportDebug","message","data","kid","calculateKeyId","set","JSON","parse","readFileSync","keys","Array","EngineError","severity","LogSeverity","ERROR","reduce","createPublicKey","format","export","type","requestOptions","method","tlsRequest","request","Object","length","keyIds","hash","createHash","update","trim","digest"],"sources":["../../../src/entities/KeySet/KeySet.ts"],"sourcesContent":["import { createPublicKey, createHash } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { Method } from 'axios';\nimport { KeySetOptions, KeySetValues, JWKS } from './KeySet.types';\nimport { LogSeverity } from 'const';\nimport { EngineError } from 'entities/EngineError';\nimport { reportDebug, reportError } from 'utils/report';\nimport { request } from 'utils/request';\nimport { tlsRequest } from 'utils/tlsRequest';\n\nconst namespace = 'engine:keySet';\n\n// Number of seconds between each key refresh\nconst KEY_REFRESH_INTERVAL = 300;\n\n/**\n * Fetch Json Web Key Sets and cache them\n * Keys can then be used for Json Web Token authentication\n */\nexport class KeySet {\n /** Latest known value for the keys in the set, indexed by the key id */\n private keySet: KeySetValues = {};\n /** URL at which the key set can be fetched */\n private url: string;\n /** This resource is located on a service inside of our private cluster */\n private internal: boolean;\n /** This URL is actually a path to a local key file encoded in PEM */\n private file: boolean;\n /** This input is actually a full PEM string representation of a key */\n private pem: boolean;\n /** Timer for the key fetching interval */\n private interval?: NodeJS.Timeout | string | number | undefined;\n\n /** Create a new Key Set */\n public constructor(url: string, options: KeySetOptions = {}) {\n this.url = url;\n this.internal = options.internal ?? false;\n this.file = options.file ?? false;\n this.pem = options.pem ?? false;\n }\n\n /** Calculate key ID from PEM string */\n private static calculateKeyId(pem: string): string {\n // We use the md5 hash of the PEM file to defined the key ID\n const hash = createHash('md5');\n hash.update(pem.trim());\n const kid = hash.digest('base64url');\n reportDebug({\n namespace,\n message: `Calculated Key ID: \"${kid}\"`,\n data: { key: pem }\n });\n return kid;\n }\n\n /** Initialize a KeySet, should be run on server startup to avoid any misconfiguration */\n public async init(): Promise<void> {\n await this.fetch();\n this.interval = setInterval(() => {\n (async (): Promise<void> => {\n try {\n await this.fetch();\n } catch (error) {\n reportError(error);\n }\n })().catch((error) => {\n reportError(error);\n });\n }, KEY_REFRESH_INTERVAL * 1000);\n }\n\n /** Clear any pending timers to avoid pending process */\n public shutdown(): void {\n if (this.interval) clearInterval(this.interval);\n }\n\n /** Get the PEM encoded version of a key by its id */\n public getKey(keyId: string): string | undefined {\n return this.keySet[keyId];\n }\n\n /** Get all the keys in the set mapped by their ID */\n public getKeys(): KeySetValues {\n return this.keySet;\n }\n\n /** Fetch the latest version of the key set */\n private async fetch(): Promise<void> {\n reportDebug({\n namespace,\n message: `Fetching JWKS`,\n data: { url: this.url }\n });\n\n if (this.pem) {\n // Read the key from the parameter directly\n reportDebug({\n namespace,\n message: 'Processing key from given PEM string'\n });\n\n const kid = KeySet.calculateKeyId(this.url);\n\n this.keySet = { [kid]: this.url };\n } else if (this.file) {\n // Read the key from a file\n reportDebug({\n namespace,\n message: `Reading key on disk at path \"${this.url}\"`\n });\n const set = JSON.parse(readFileSync(this.url, 'utf-8'));\n\n // Check that the returned data has the shape of a JWKS\n if (!(set.keys && set.keys instanceof Array))\n throw new EngineError({\n severity: LogSeverity.ERROR,\n message: 'Fetched key set is not in an appropriate format',\n data: { url: this.url, set }\n });\n\n // Create a node.crypto public key object for each key in the set\n this.keySet = set.keys.reduce(\n (set: { [x: string]: string; }, key: { kid: string | number; }) => {\n set[key.kid] = createPublicKey({ key, format: 'jwk' }).export({\n format: 'pem',\n type: 'spki'\n }) as string;\n return set;\n },\n {} as Record<string, string>\n );\n } else {\n // Fetch key by making a network request\n reportDebug({\n namespace,\n message: `Making network request to \"${this.url}\"`\n });\n\n const requestOptions = { url: this.url, method: 'get' as Method };\n // For services inside of our cluster we use the TLS authenticated request method\n const { data: set } = await (this.internal\n ? tlsRequest<JWKS>(requestOptions)\n : request<JWKS>(requestOptions));\n\n // Check that the returned data has the shape of a JWKS\n if (!(set.keys && set.keys instanceof Array))\n throw new EngineError({\n severity: LogSeverity.ERROR,\n message: 'Fetched key set is not in an appropriate format',\n data: { url: this.url, set }\n });\n\n // Create a node.crypto public key object for each key in the set\n this.keySet = set.keys.reduce(\n (set, key) => {\n set[key.kid] = createPublicKey({ key, format: 'jwk' }).export({\n format: 'pem',\n type: 'spki'\n }) as string;\n return set;\n },\n {} as Record<string, string>\n );\n }\n\n reportDebug({\n namespace,\n message: `Stored ${Object.keys(this.keySet).length} keys`,\n data: { keyIds: Object.keys(this.keySet) }\n });\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"KeySet.js","names":["_crypto","require","_fs","_const","_EngineError","_report","_request","_tlsRequest","namespace","KEY_REFRESH_INTERVAL","KeySet","exports","url","options","_classCallCheck2","default","_defineProperty2","internal","file","pem","_createClass2","key","value","init","fetch","interval","setInterval","error","reportError","catch","shutdown","clearInterval","getKey","keyId","keySet","getKeys","reportDebug","message","data","kid","calculateKeyId","set","JSON","parse","readFileSync","keys","Array","EngineError","severity","LogSeverity","ERROR","reduce","createPublicKey","format","export","type","requestOptions","method","tlsRequest","request","Object","length","keyIds","hash","createHash","update","trim","digest"],"sources":["../../../src/entities/KeySet/KeySet.ts"],"sourcesContent":["import { createPublicKey, createHash } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { Method } from 'axios';\nimport { KeySetOptions, KeySetValues, JWKS } from './KeySet.types';\nimport { LogSeverity } from 'const';\nimport { EngineError } from 'entities/EngineError';\nimport { reportDebug, reportError } from 'utils/report';\nimport { request } from 'utils/request';\nimport { tlsRequest } from 'utils/tlsRequest';\n\nconst namespace = 'engine:keySet';\n\n// Number of seconds between each key refresh\nconst KEY_REFRESH_INTERVAL = 300;\n\n/**\n * Fetch Json Web Key Sets and cache them\n * Keys can then be used for Json Web Token authentication\n */\nexport class KeySet {\n /** Latest known value for the keys in the set, indexed by the key id */\n private keySet: KeySetValues = {};\n /** URL at which the key set can be fetched */\n private url: string;\n /** This resource is located on a service inside of our private cluster */\n private internal: boolean;\n /** This URL is actually a path to a local key file encoded in PEM */\n private file: boolean;\n /** This input is actually a full PEM string representation of a key */\n private pem: boolean;\n /** Timer for the key fetching interval */\n private interval?: NodeJS.Timeout | string | number | undefined;\n\n /** Create a new Key Set */\n public constructor(url: string, options: KeySetOptions = {}) {\n this.url = url;\n this.internal = options.internal ?? false;\n this.file = options.file ?? false;\n this.pem = options.pem ?? false;\n }\n\n /** Calculate key ID from PEM string */\n private static calculateKeyId(pem: string): string {\n // We use the md5 hash of the PEM file to defined the key ID\n const hash = createHash('md5');\n hash.update(pem.trim());\n const kid = hash.digest('base64url');\n reportDebug({\n namespace,\n message: `Calculated Key ID: \"${kid}\"`,\n data: { key: pem }\n });\n return kid;\n }\n\n /** Initialize a KeySet, should be run on server startup to avoid any misconfiguration */\n public async init(): Promise<void> {\n await this.fetch();\n this.interval = setInterval(() => {\n (async (): Promise<void> => {\n try {\n await this.fetch();\n } catch (error) {\n reportError(error);\n }\n })().catch((error) => {\n reportError(error);\n });\n }, KEY_REFRESH_INTERVAL * 1000);\n }\n\n /** Clear any pending timers to avoid pending process */\n public shutdown(): void {\n if (this.interval) clearInterval(this.interval);\n }\n\n /** Get the PEM encoded version of a key by its id */\n public getKey(keyId: string): string | undefined {\n return this.keySet[keyId];\n }\n\n /** Get all the keys in the set mapped by their ID */\n public getKeys(): KeySetValues {\n return this.keySet;\n }\n\n /** Fetch the latest version of the key set */\n private async fetch(): Promise<void> {\n reportDebug({\n namespace,\n message: `Fetching JWKS`,\n data: { url: this.url }\n });\n\n if (this.pem) {\n // Read the key from the parameter directly\n reportDebug({\n namespace,\n message: 'Processing key from given PEM string'\n });\n\n const kid = KeySet.calculateKeyId(this.url);\n\n this.keySet = { [kid]: this.url };\n } else if (this.file) {\n // Read the key from a file\n reportDebug({\n namespace,\n message: `Reading key on disk at path \"${this.url}\"`\n });\n const set = JSON.parse(readFileSync(this.url, 'utf-8'));\n\n // Check that the returned data has the shape of a JWKS\n if (!(set.keys && set.keys instanceof Array))\n throw new EngineError({\n severity: LogSeverity.ERROR,\n message: 'Fetched key set is not in an appropriate format',\n data: { url: this.url, set }\n });\n\n // Create a node.crypto public key object for each key in the set\n this.keySet = set.keys.reduce(\n (set: { [x: string]: string }, key: { kid: string | number }) => {\n set[key.kid] = createPublicKey({ key, format: 'jwk' }).export({\n format: 'pem',\n type: 'spki'\n }) as string;\n return set;\n },\n {} as Record<string, string>\n );\n } else {\n // Fetch key by making a network request\n reportDebug({\n namespace,\n message: `Making network request to \"${this.url}\"`\n });\n\n const requestOptions = { url: this.url, method: 'get' as Method };\n // For services inside of our cluster we use the TLS authenticated request method\n const { data: set } = await (this.internal\n ? tlsRequest<JWKS>(requestOptions)\n : request<JWKS>(requestOptions));\n\n // Check that the returned data has the shape of a JWKS\n if (!(set.keys && set.keys instanceof Array))\n throw new EngineError({\n severity: LogSeverity.ERROR,\n message: 'Fetched key set is not in an appropriate format',\n data: { url: this.url, set }\n });\n\n // Create a node.crypto public key object for each key in the set\n this.keySet = set.keys.reduce(\n (set, key) => {\n set[key.kid] = createPublicKey({ key, format: 'jwk' }).export({\n format: 'pem',\n type: 'spki'\n }) as string;\n return set;\n },\n {} as Record<string, string>\n );\n }\n\n reportDebug({\n namespace,\n message: `Stored ${Object.keys(this.keySet).length} keys`,\n data: { keyIds: Object.keys(this.keySet) }\n });\n }\n}\n"],"mappings":"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","ignoreList":[]}
|