cadenlane-cli-2 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE +21 -0
  3. package/README.md +333 -0
  4. package/bin.js +2 -0
  5. package/dist/application/config/config.manager.d.ts +62 -0
  6. package/dist/application/config/config.manager.d.ts.map +1 -0
  7. package/dist/application/config/config.manager.js +146 -0
  8. package/dist/application/config/config.manager.js.map +1 -0
  9. package/dist/application/services/application.service.d.ts +35 -0
  10. package/dist/application/services/application.service.d.ts.map +1 -0
  11. package/dist/application/services/application.service.js +174 -0
  12. package/dist/application/services/application.service.js.map +1 -0
  13. package/dist/application/services/download.service.d.ts +27 -0
  14. package/dist/application/services/download.service.d.ts.map +1 -0
  15. package/dist/application/services/download.service.js +197 -0
  16. package/dist/application/services/download.service.js.map +1 -0
  17. package/dist/application/services/file-naming.service.d.ts +34 -0
  18. package/dist/application/services/file-naming.service.d.ts.map +1 -0
  19. package/dist/application/services/file-naming.service.js +142 -0
  20. package/dist/application/services/file-naming.service.js.map +1 -0
  21. package/dist/application/services/queue.service.d.ts +53 -0
  22. package/dist/application/services/queue.service.d.ts.map +1 -0
  23. package/dist/application/services/queue.service.js +82 -0
  24. package/dist/application/services/queue.service.js.map +1 -0
  25. package/dist/cli/commands/start.command.d.ts +39 -0
  26. package/dist/cli/commands/start.command.d.ts.map +1 -0
  27. package/dist/cli/commands/start.command.js +196 -0
  28. package/dist/cli/commands/start.command.js.map +1 -0
  29. package/dist/cli/index.d.ts +3 -0
  30. package/dist/cli/index.d.ts.map +1 -0
  31. package/dist/cli/index.js +86 -0
  32. package/dist/cli/index.js.map +1 -0
  33. package/dist/domain/constants/config.constants.d.ts +54 -0
  34. package/dist/domain/constants/config.constants.d.ts.map +1 -0
  35. package/dist/domain/constants/config.constants.js +142 -0
  36. package/dist/domain/constants/config.constants.js.map +1 -0
  37. package/dist/domain/dtos/index.d.ts +4 -0
  38. package/dist/domain/dtos/index.d.ts.map +1 -0
  39. package/dist/domain/dtos/index.js +10 -0
  40. package/dist/domain/dtos/index.js.map +1 -0
  41. package/dist/domain/dtos/log-entry.dto.d.ts +15 -0
  42. package/dist/domain/dtos/log-entry.dto.d.ts.map +1 -0
  43. package/dist/domain/dtos/log-entry.dto.js +64 -0
  44. package/dist/domain/dtos/log-entry.dto.js.map +1 -0
  45. package/dist/domain/dtos/message.dto.d.ts +27 -0
  46. package/dist/domain/dtos/message.dto.d.ts.map +1 -0
  47. package/dist/domain/dtos/message.dto.js +140 -0
  48. package/dist/domain/dtos/message.dto.js.map +1 -0
  49. package/dist/domain/dtos/queue-message.dto.d.ts +10 -0
  50. package/dist/domain/dtos/queue-message.dto.d.ts.map +1 -0
  51. package/dist/domain/dtos/queue-message.dto.js +39 -0
  52. package/dist/domain/dtos/queue-message.dto.js.map +1 -0
  53. package/dist/domain/entities/cli-instance.entity.d.ts +55 -0
  54. package/dist/domain/entities/cli-instance.entity.d.ts.map +1 -0
  55. package/dist/domain/entities/cli-instance.entity.js +132 -0
  56. package/dist/domain/entities/cli-instance.entity.js.map +1 -0
  57. package/dist/domain/entities/index.d.ts +3 -0
  58. package/dist/domain/entities/index.d.ts.map +1 -0
  59. package/dist/domain/entities/index.js +8 -0
  60. package/dist/domain/entities/index.js.map +1 -0
  61. package/dist/domain/entities/log-entry.entity.d.ts +60 -0
  62. package/dist/domain/entities/log-entry.entity.d.ts.map +1 -0
  63. package/dist/domain/entities/log-entry.entity.js +101 -0
  64. package/dist/domain/entities/log-entry.entity.js.map +1 -0
  65. package/dist/domain/entities/message.entity.d.ts +64 -0
  66. package/dist/domain/entities/message.entity.d.ts.map +1 -0
  67. package/dist/domain/entities/message.entity.js +110 -0
  68. package/dist/domain/entities/message.entity.js.map +1 -0
  69. package/dist/domain/enums/error-category.enum.d.ts +11 -0
  70. package/dist/domain/enums/error-category.enum.d.ts.map +1 -0
  71. package/dist/domain/enums/error-category.enum.js +15 -0
  72. package/dist/domain/enums/error-category.enum.js.map +1 -0
  73. package/dist/domain/enums/index.d.ts +4 -0
  74. package/dist/domain/enums/index.d.ts.map +1 -0
  75. package/dist/domain/enums/index.js +10 -0
  76. package/dist/domain/enums/index.js.map +1 -0
  77. package/dist/domain/enums/log-level.enum.d.ts +11 -0
  78. package/dist/domain/enums/log-level.enum.d.ts.map +1 -0
  79. package/dist/domain/enums/log-level.enum.js +15 -0
  80. package/dist/domain/enums/log-level.enum.js.map +1 -0
  81. package/dist/domain/enums/message-status.enum.d.ts +11 -0
  82. package/dist/domain/enums/message-status.enum.d.ts.map +1 -0
  83. package/dist/domain/enums/message-status.enum.js +15 -0
  84. package/dist/domain/enums/message-status.enum.js.map +1 -0
  85. package/dist/domain/interfaces/adapters/ifilesystem.adapter.d.ts +34 -0
  86. package/dist/domain/interfaces/adapters/ifilesystem.adapter.d.ts.map +1 -0
  87. package/dist/domain/interfaces/adapters/ifilesystem.adapter.js +3 -0
  88. package/dist/domain/interfaces/adapters/ifilesystem.adapter.js.map +1 -0
  89. package/dist/domain/interfaces/adapters/ihttp.adapter.d.ts +22 -0
  90. package/dist/domain/interfaces/adapters/ihttp.adapter.d.ts.map +1 -0
  91. package/dist/domain/interfaces/adapters/ihttp.adapter.js +3 -0
  92. package/dist/domain/interfaces/adapters/ihttp.adapter.js.map +1 -0
  93. package/dist/domain/interfaces/adapters/index.d.ts +4 -0
  94. package/dist/domain/interfaces/adapters/index.d.ts.map +1 -0
  95. package/dist/domain/interfaces/adapters/index.js +3 -0
  96. package/dist/domain/interfaces/adapters/index.js.map +1 -0
  97. package/dist/domain/interfaces/adapters/isupabase.adapter.d.ts +27 -0
  98. package/dist/domain/interfaces/adapters/isupabase.adapter.d.ts.map +1 -0
  99. package/dist/domain/interfaces/adapters/isupabase.adapter.js +3 -0
  100. package/dist/domain/interfaces/adapters/isupabase.adapter.js.map +1 -0
  101. package/dist/domain/interfaces/repositories/ilog.repository.d.ts +32 -0
  102. package/dist/domain/interfaces/repositories/ilog.repository.d.ts.map +1 -0
  103. package/dist/domain/interfaces/repositories/ilog.repository.js +3 -0
  104. package/dist/domain/interfaces/repositories/ilog.repository.js.map +1 -0
  105. package/dist/domain/interfaces/repositories/imessage.repository.d.ts +39 -0
  106. package/dist/domain/interfaces/repositories/imessage.repository.d.ts.map +1 -0
  107. package/dist/domain/interfaces/repositories/imessage.repository.js +3 -0
  108. package/dist/domain/interfaces/repositories/imessage.repository.js.map +1 -0
  109. package/dist/domain/interfaces/repositories/index.d.ts +4 -0
  110. package/dist/domain/interfaces/repositories/index.d.ts.map +1 -0
  111. package/dist/domain/interfaces/repositories/index.js +3 -0
  112. package/dist/domain/interfaces/repositories/index.js.map +1 -0
  113. package/dist/domain/interfaces/repositories/iqueue.repository.d.ts +75 -0
  114. package/dist/domain/interfaces/repositories/iqueue.repository.d.ts.map +1 -0
  115. package/dist/domain/interfaces/repositories/iqueue.repository.js +3 -0
  116. package/dist/domain/interfaces/repositories/iqueue.repository.js.map +1 -0
  117. package/dist/domain/interfaces/services/idownload.service.d.ts +28 -0
  118. package/dist/domain/interfaces/services/idownload.service.d.ts.map +1 -0
  119. package/dist/domain/interfaces/services/idownload.service.js +3 -0
  120. package/dist/domain/interfaces/services/idownload.service.js.map +1 -0
  121. package/dist/domain/interfaces/services/iqueue.service.d.ts +35 -0
  122. package/dist/domain/interfaces/services/iqueue.service.d.ts.map +1 -0
  123. package/dist/domain/interfaces/services/iqueue.service.js +3 -0
  124. package/dist/domain/interfaces/services/iqueue.service.js.map +1 -0
  125. package/dist/domain/services/path-resolver.service.d.ts +94 -0
  126. package/dist/domain/services/path-resolver.service.d.ts.map +1 -0
  127. package/dist/domain/services/path-resolver.service.js +332 -0
  128. package/dist/domain/services/path-resolver.service.js.map +1 -0
  129. package/dist/domain/validators/index.d.ts +4 -0
  130. package/dist/domain/validators/index.d.ts.map +1 -0
  131. package/dist/domain/validators/index.js +10 -0
  132. package/dist/domain/validators/index.js.map +1 -0
  133. package/dist/domain/validators/message.validator.d.ts +20 -0
  134. package/dist/domain/validators/message.validator.d.ts.map +1 -0
  135. package/dist/domain/validators/message.validator.js +31 -0
  136. package/dist/domain/validators/message.validator.js.map +1 -0
  137. package/dist/domain/validators/path.validator.d.ts +44 -0
  138. package/dist/domain/validators/path.validator.d.ts.map +1 -0
  139. package/dist/domain/validators/path.validator.js +156 -0
  140. package/dist/domain/validators/path.validator.js.map +1 -0
  141. package/dist/domain/validators/url.validator.d.ts +19 -0
  142. package/dist/domain/validators/url.validator.d.ts.map +1 -0
  143. package/dist/domain/validators/url.validator.js +46 -0
  144. package/dist/domain/validators/url.validator.js.map +1 -0
  145. package/dist/index.d.ts +11 -0
  146. package/dist/index.d.ts.map +1 -0
  147. package/dist/index.js +27 -0
  148. package/dist/index.js.map +1 -0
  149. package/dist/infrastructure/adapters/filesystem.adapter.d.ts +35 -0
  150. package/dist/infrastructure/adapters/filesystem.adapter.d.ts.map +1 -0
  151. package/dist/infrastructure/adapters/filesystem.adapter.js +103 -0
  152. package/dist/infrastructure/adapters/filesystem.adapter.js.map +1 -0
  153. package/dist/infrastructure/adapters/http.adapter.d.ts +15 -0
  154. package/dist/infrastructure/adapters/http.adapter.d.ts.map +1 -0
  155. package/dist/infrastructure/adapters/http.adapter.js +80 -0
  156. package/dist/infrastructure/adapters/http.adapter.js.map +1 -0
  157. package/dist/infrastructure/adapters/index.d.ts +4 -0
  158. package/dist/infrastructure/adapters/index.d.ts.map +1 -0
  159. package/dist/infrastructure/adapters/index.js +10 -0
  160. package/dist/infrastructure/adapters/index.js.map +1 -0
  161. package/dist/infrastructure/adapters/pgmq.adapter.d.ts +29 -0
  162. package/dist/infrastructure/adapters/pgmq.adapter.d.ts.map +1 -0
  163. package/dist/infrastructure/adapters/pgmq.adapter.js +84 -0
  164. package/dist/infrastructure/adapters/pgmq.adapter.js.map +1 -0
  165. package/dist/infrastructure/adapters/supabase.adapter.d.ts +79 -0
  166. package/dist/infrastructure/adapters/supabase.adapter.d.ts.map +1 -0
  167. package/dist/infrastructure/adapters/supabase.adapter.js +97 -0
  168. package/dist/infrastructure/adapters/supabase.adapter.js.map +1 -0
  169. package/dist/infrastructure/database/supabase.client.d.ts +20 -0
  170. package/dist/infrastructure/database/supabase.client.d.ts.map +1 -0
  171. package/dist/infrastructure/database/supabase.client.js +36 -0
  172. package/dist/infrastructure/database/supabase.client.js.map +1 -0
  173. package/dist/infrastructure/di/container.d.ts +18 -0
  174. package/dist/infrastructure/di/container.d.ts.map +1 -0
  175. package/dist/infrastructure/di/container.js +103 -0
  176. package/dist/infrastructure/di/container.js.map +1 -0
  177. package/dist/infrastructure/repositories/cli-instance.repository.d.ts +64 -0
  178. package/dist/infrastructure/repositories/cli-instance.repository.d.ts.map +1 -0
  179. package/dist/infrastructure/repositories/cli-instance.repository.js +154 -0
  180. package/dist/infrastructure/repositories/cli-instance.repository.js.map +1 -0
  181. package/dist/infrastructure/repositories/config.repository.d.ts +52 -0
  182. package/dist/infrastructure/repositories/config.repository.d.ts.map +1 -0
  183. package/dist/infrastructure/repositories/config.repository.js +130 -0
  184. package/dist/infrastructure/repositories/config.repository.js.map +1 -0
  185. package/dist/infrastructure/repositories/index.d.ts +4 -0
  186. package/dist/infrastructure/repositories/index.d.ts.map +1 -0
  187. package/dist/infrastructure/repositories/index.js +10 -0
  188. package/dist/infrastructure/repositories/index.js.map +1 -0
  189. package/dist/infrastructure/repositories/log.repository.d.ts +44 -0
  190. package/dist/infrastructure/repositories/log.repository.d.ts.map +1 -0
  191. package/dist/infrastructure/repositories/log.repository.js +108 -0
  192. package/dist/infrastructure/repositories/log.repository.js.map +1 -0
  193. package/dist/infrastructure/repositories/message.repository.d.ts +51 -0
  194. package/dist/infrastructure/repositories/message.repository.d.ts.map +1 -0
  195. package/dist/infrastructure/repositories/message.repository.js +161 -0
  196. package/dist/infrastructure/repositories/message.repository.js.map +1 -0
  197. package/dist/infrastructure/repositories/queue.repository.d.ts +69 -0
  198. package/dist/infrastructure/repositories/queue.repository.d.ts.map +1 -0
  199. package/dist/infrastructure/repositories/queue.repository.js +130 -0
  200. package/dist/infrastructure/repositories/queue.repository.js.map +1 -0
  201. package/dist/infrastructure/utils/connection-health.util.d.ts +23 -0
  202. package/dist/infrastructure/utils/connection-health.util.d.ts.map +1 -0
  203. package/dist/infrastructure/utils/connection-health.util.js +64 -0
  204. package/dist/infrastructure/utils/connection-health.util.js.map +1 -0
  205. package/package.json +105 -0
  206. package/pm2.config.js +104 -0
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ApplicationService = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const crypto_1 = require("crypto");
18
+ const os_1 = require("os");
19
+ const queue_service_1 = require("./queue.service");
20
+ const download_service_1 = require("./download.service");
21
+ const message_repository_1 = require("../../infrastructure/repositories/message.repository");
22
+ const log_repository_1 = require("../../infrastructure/repositories/log.repository");
23
+ const entities_1 = require("../../domain/entities");
24
+ const enums_1 = require("../../domain/enums");
25
+ /**
26
+ * Application Service
27
+ * Main orchestrator for message processing workflow
28
+ */
29
+ let ApplicationService = class ApplicationService {
30
+ queueService;
31
+ downloadService;
32
+ messageRepository;
33
+ logRepository;
34
+ constructor(queueService, downloadService, messageRepository, logRepository) {
35
+ this.queueService = queueService;
36
+ this.downloadService = downloadService;
37
+ this.messageRepository = messageRepository;
38
+ this.logRepository = logRepository;
39
+ }
40
+ /**
41
+ * Processes the next message from the queue
42
+ * @returns true if a message was processed, false if queue is empty
43
+ */
44
+ async processNextMessage() {
45
+ try {
46
+ // Poll for a message
47
+ const queueMessage = await this.queueService.pollMessage();
48
+ if (!queueMessage) {
49
+ return false; // Queue is empty
50
+ }
51
+ return await this.processMessage(queueMessage);
52
+ }
53
+ catch (error) {
54
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
55
+ console.error('Error processing message:', errorMessage);
56
+ return false;
57
+ }
58
+ }
59
+ /**
60
+ * Processes a specific message (used when message is pre-fetched)
61
+ * @param queueMessage - The PGMQ message to process
62
+ * @returns true if processed successfully
63
+ */
64
+ async processMessage(queueMessage) {
65
+ try {
66
+ const pgmqMessageId = queueMessage.msg_id;
67
+ const { file_url, target_folder } = queueMessage.message;
68
+ const queueName = this.queueService.getQueueName();
69
+ console.log(`📋 Message ID: ${pgmqMessageId}`);
70
+ console.log(`📮 Queue: ${queueName}`);
71
+ console.log(`🔗 File URL: ${file_url}`);
72
+ console.log(`📁 Target Folder: ${target_folder}`);
73
+ // Create message record with instance tracking
74
+ console.log('💾 Creating message record in database...');
75
+ const instanceId = process.env.CLI_INSTANCE_ID || `${(0, os_1.hostname)()}-${(0, os_1.platform)()}`;
76
+ const messageEntity = new entities_1.MessageEntity((0, crypto_1.randomUUID)(), pgmqMessageId, file_url, target_folder, enums_1.MessageStatus.RECEIVED, new Date(), undefined, // processed_by_instance_id (UUID - not used)
77
+ instanceId, // processed_by_instance_name (our CLI_INSTANCE_ID)
78
+ (0, os_1.hostname)(), // processed_by_hostname
79
+ (0, os_1.platform)() // processed_by_platform
80
+ );
81
+ await this.messageRepository.create(messageEntity);
82
+ await this.logInfo(messageEntity.id, 'Message received from queue');
83
+ console.log('✅ Message record created');
84
+ // Mark as processing
85
+ console.log('⚙️ Marking message as processing...');
86
+ messageEntity.markAsProcessing();
87
+ await this.messageRepository.update(messageEntity);
88
+ await this.logInfo(messageEntity.id, 'Started processing message');
89
+ console.log('✅ Status updated to processing');
90
+ // Download the image
91
+ console.log('⬇️ Starting image download...');
92
+ const downloadResult = await this.downloadService.downloadImage(messageEntity);
93
+ if (downloadResult.success) {
94
+ // Mark as completed
95
+ console.log(`✅ Download completed successfully!`);
96
+ console.log(` 📄 File: ${downloadResult.fileName}`);
97
+ console.log(` 📦 Size: ${(downloadResult.fileSizeBytes / 1024).toFixed(2)} KB`);
98
+ console.log(` ⏱️ Duration: ${downloadResult.durationMs}ms`);
99
+ messageEntity.markAsCompleted(downloadResult.fileName, downloadResult.filePath, downloadResult.fileSizeBytes, downloadResult.durationMs);
100
+ await this.messageRepository.update(messageEntity);
101
+ await this.logInfo(messageEntity.id, 'Download completed successfully', {
102
+ fileName: downloadResult.fileName,
103
+ filePath: downloadResult.filePath,
104
+ fileSizeBytes: downloadResult.fileSizeBytes,
105
+ durationMs: downloadResult.durationMs,
106
+ });
107
+ }
108
+ else {
109
+ // Mark as failed
110
+ console.log(`❌ Download failed!`);
111
+ console.log(` Error: ${downloadResult.error.message}`);
112
+ console.log(` Category: ${downloadResult.error.category}`);
113
+ messageEntity.markAsFailed(downloadResult.error.message, downloadResult.error.category);
114
+ await this.messageRepository.update(messageEntity);
115
+ await this.logError(messageEntity.id, 'Download failed', new Error(downloadResult.error.message), { category: downloadResult.error.category });
116
+ }
117
+ // Mark message as deleted from queue
118
+ console.log('🗑️ Removing message from queue...');
119
+ messageEntity.markAsDeletedFromQueue();
120
+ await this.messageRepository.update(messageEntity);
121
+ // Acknowledge message (delete from queue)
122
+ await this.queueService.acknowledgeMessage(pgmqMessageId);
123
+ await this.logInfo(messageEntity.id, 'Message acknowledged and removed from queue');
124
+ console.log('✅ Message removed from queue');
125
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
126
+ return true;
127
+ }
128
+ catch (error) {
129
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
130
+ console.error('❌ Error processing message:', errorMessage);
131
+ if (error instanceof Error && error.stack) {
132
+ console.error('Stack trace:', error.stack);
133
+ }
134
+ return false;
135
+ }
136
+ }
137
+ /**
138
+ * Logs an info message
139
+ */
140
+ async logInfo(messageId, message, data) {
141
+ try {
142
+ const logEntry = entities_1.LogEntryEntity.createInfo(messageId, message, data);
143
+ await this.logRepository.create(logEntry);
144
+ }
145
+ catch (error) {
146
+ console.error('Failed to create log entry:', error);
147
+ }
148
+ }
149
+ /**
150
+ * Logs an error message
151
+ */
152
+ async logError(messageId, message, error, data) {
153
+ try {
154
+ const logEntry = entities_1.LogEntryEntity.createError(messageId, message, error, data);
155
+ await this.logRepository.create(logEntry);
156
+ }
157
+ catch (err) {
158
+ console.error('Failed to create error log entry:', err);
159
+ }
160
+ }
161
+ };
162
+ exports.ApplicationService = ApplicationService;
163
+ exports.ApplicationService = ApplicationService = __decorate([
164
+ (0, tsyringe_1.injectable)(),
165
+ __param(0, (0, tsyringe_1.inject)(queue_service_1.QueueService)),
166
+ __param(1, (0, tsyringe_1.inject)(download_service_1.DownloadService)),
167
+ __param(2, (0, tsyringe_1.inject)(message_repository_1.MessageRepository)),
168
+ __param(3, (0, tsyringe_1.inject)(log_repository_1.LogRepository)),
169
+ __metadata("design:paramtypes", [queue_service_1.QueueService,
170
+ download_service_1.DownloadService,
171
+ message_repository_1.MessageRepository,
172
+ log_repository_1.LogRepository])
173
+ ], ApplicationService);
174
+ //# sourceMappingURL=application.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"application.service.js","sourceRoot":"","sources":["../../../src/application/services/application.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { IDownloadService, DownloadResult } from '../../domain/interfaces/services/idownload.service';
2
+ import { MessageEntity } from '../../domain/entities';
3
+ import { HttpAdapter } from '../../infrastructure/adapters/http.adapter';
4
+ import { FileSystemAdapter } from '../../infrastructure/adapters/filesystem.adapter';
5
+ import { UrlValidator } from '../../domain/validators/url.validator';
6
+ import { PathValidator } from '../../domain/validators/path.validator';
7
+ import { FileNamingService } from './file-naming.service';
8
+ /**
9
+ * Download Service
10
+ * Handles image download operations with validation
11
+ */
12
+ export declare class DownloadService implements IDownloadService {
13
+ private httpAdapter;
14
+ private fsAdapter;
15
+ private urlValidator;
16
+ private pathValidator;
17
+ private fileNamingService;
18
+ private readonly pathResolver;
19
+ constructor(httpAdapter: HttpAdapter, fsAdapter: FileSystemAdapter, urlValidator: UrlValidator, pathValidator: PathValidator, fileNamingService: FileNamingService);
20
+ /**
21
+ * Downloads an image from URL and saves to target folder
22
+ * @param message - Message entity containing download details
23
+ * @returns Download result
24
+ */
25
+ downloadImage(message: MessageEntity): Promise<DownloadResult>;
26
+ }
27
+ //# sourceMappingURL=download.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.service.d.ts","sourceRoot":"","sources":["../../../src/application/services/download.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAClG,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAEnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;GAGG;AACH,qBACa,eAAgB,YAAW,gBAAgB;IAI/B,OAAO,CAAC,WAAW;IACb,OAAO,CAAC,SAAS;IACtB,OAAO,CAAC,YAAY;IACnB,OAAO,CAAC,aAAa;IACjB,OAAO,CAAC,iBAAiB;IAPtD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;gBAGpB,WAAW,EAAE,WAAW,EAClB,SAAS,EAAE,iBAAiB,EACjC,YAAY,EAAE,YAAY,EACzB,aAAa,EAAE,aAAa,EACxB,iBAAiB,EAAE,iBAAiB;IAKzE;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;CAqHrE"}
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
45
+ return function (target, key) { decorator(target, key, paramIndex); }
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.DownloadService = void 0;
49
+ const tsyringe_1 = require("tsyringe");
50
+ const path = __importStar(require("path"));
51
+ const enums_1 = require("../../domain/enums");
52
+ const http_adapter_1 = require("../../infrastructure/adapters/http.adapter");
53
+ const filesystem_adapter_1 = require("../../infrastructure/adapters/filesystem.adapter");
54
+ const url_validator_1 = require("../../domain/validators/url.validator");
55
+ const path_validator_1 = require("../../domain/validators/path.validator");
56
+ const path_resolver_service_1 = require("../../domain/services/path-resolver.service");
57
+ const file_naming_service_1 = require("./file-naming.service");
58
+ /**
59
+ * Download Service
60
+ * Handles image download operations with validation
61
+ */
62
+ let DownloadService = class DownloadService {
63
+ httpAdapter;
64
+ fsAdapter;
65
+ urlValidator;
66
+ pathValidator;
67
+ fileNamingService;
68
+ pathResolver;
69
+ constructor(httpAdapter, fsAdapter, urlValidator, pathValidator, fileNamingService) {
70
+ this.httpAdapter = httpAdapter;
71
+ this.fsAdapter = fsAdapter;
72
+ this.urlValidator = urlValidator;
73
+ this.pathValidator = pathValidator;
74
+ this.fileNamingService = fileNamingService;
75
+ this.pathResolver = new path_resolver_service_1.PathResolverService();
76
+ }
77
+ /**
78
+ * Downloads an image from URL and saves to target folder
79
+ * @param message - Message entity containing download details
80
+ * @returns Download result
81
+ */
82
+ async downloadImage(message) {
83
+ const startTime = Date.now();
84
+ try {
85
+ // Validate URL
86
+ if (!this.urlValidator.isValid(message.file_url)) {
87
+ return {
88
+ success: false,
89
+ error: {
90
+ message: `Invalid URL: ${message.file_url}`,
91
+ category: enums_1.ErrorCategory.VALIDATION,
92
+ },
93
+ };
94
+ }
95
+ // Validate target folder using basic validator
96
+ if (!this.pathValidator.isValid(message.target_folder)) {
97
+ return {
98
+ success: false,
99
+ error: {
100
+ message: `Invalid target folder: ${message.target_folder}`,
101
+ category: enums_1.ErrorCategory.VALIDATION,
102
+ },
103
+ };
104
+ }
105
+ // Check for path traversal using basic validator
106
+ if (!this.pathValidator.isSafe(message.target_folder)) {
107
+ return {
108
+ success: false,
109
+ error: {
110
+ message: `Unsafe path detected: ${message.target_folder}`,
111
+ category: enums_1.ErrorCategory.VALIDATION,
112
+ },
113
+ };
114
+ }
115
+ // Resolve path using PathResolverService for cross-platform support
116
+ const pathResolution = this.pathResolver.resolve(message.target_folder);
117
+ if (!pathResolution.isValid) {
118
+ return {
119
+ success: false,
120
+ error: {
121
+ message: pathResolution.error || 'Path resolution failed',
122
+ category: enums_1.ErrorCategory.VALIDATION,
123
+ },
124
+ };
125
+ }
126
+ const targetDir = pathResolution.absolutePath;
127
+ // Additional safety check after resolution
128
+ if (!this.pathResolver.isSafePath(targetDir)) {
129
+ return {
130
+ success: false,
131
+ error: {
132
+ message: `Path contains directory traversal after resolution: ${targetDir}`,
133
+ category: enums_1.ErrorCategory.VALIDATION,
134
+ },
135
+ };
136
+ }
137
+ // Extract filename from URL
138
+ let fileName = this.urlValidator.extractFilename(message.file_url);
139
+ // Download the image
140
+ const downloadResult = await this.httpAdapter.download(message.file_url, 30000);
141
+ // Ensure filename has extension (use content-type or default to .jpg)
142
+ fileName = this.fileNamingService.ensureExtension(fileName, downloadResult.contentType || null);
143
+ // Ensure target directory exists
144
+ await this.fsAdapter.ensureDir(targetDir);
145
+ // Ensure filename is unique in target directory
146
+ fileName = await this.fileNamingService.ensureUniqueFilename(targetDir, fileName);
147
+ const fullPath = path.join(targetDir, fileName);
148
+ // Write file to disk
149
+ await this.fsAdapter.writeFile(fullPath, downloadResult.buffer);
150
+ // Get file stats
151
+ const stats = await this.fsAdapter.getFileStats(fullPath);
152
+ const durationMs = Date.now() - startTime;
153
+ return {
154
+ success: true,
155
+ fileName,
156
+ filePath: fullPath,
157
+ fileSizeBytes: stats.size,
158
+ durationMs,
159
+ };
160
+ }
161
+ catch (error) {
162
+ const durationMs = Date.now() - startTime;
163
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
164
+ // Categorize error
165
+ let category = enums_1.ErrorCategory.UNKNOWN;
166
+ if (errorMessage.includes('timeout') || errorMessage.includes('network') || errorMessage.includes('HTTP')) {
167
+ category = enums_1.ErrorCategory.NETWORK;
168
+ }
169
+ else if (errorMessage.includes('Permission') || errorMessage.includes('EACCES') || errorMessage.includes('ENOENT')) {
170
+ category = enums_1.ErrorCategory.FILESYSTEM;
171
+ }
172
+ return {
173
+ success: false,
174
+ durationMs,
175
+ error: {
176
+ message: errorMessage,
177
+ category,
178
+ },
179
+ };
180
+ }
181
+ }
182
+ };
183
+ exports.DownloadService = DownloadService;
184
+ exports.DownloadService = DownloadService = __decorate([
185
+ (0, tsyringe_1.injectable)(),
186
+ __param(0, (0, tsyringe_1.inject)(http_adapter_1.HttpAdapter)),
187
+ __param(1, (0, tsyringe_1.inject)(filesystem_adapter_1.FileSystemAdapter)),
188
+ __param(2, (0, tsyringe_1.inject)(url_validator_1.UrlValidator)),
189
+ __param(3, (0, tsyringe_1.inject)(path_validator_1.PathValidator)),
190
+ __param(4, (0, tsyringe_1.inject)(file_naming_service_1.FileNamingService)),
191
+ __metadata("design:paramtypes", [http_adapter_1.HttpAdapter,
192
+ filesystem_adapter_1.FileSystemAdapter,
193
+ url_validator_1.UrlValidator,
194
+ path_validator_1.PathValidator,
195
+ file_naming_service_1.FileNamingService])
196
+ ], DownloadService);
197
+ //# sourceMappingURL=download.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.service.js","sourceRoot":"","sources":["../../../src/application/services/download.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { FileSystemAdapter } from '../../infrastructure/adapters/filesystem.adapter';
2
+ /**
3
+ * File Naming Service
4
+ * Handles file naming logic including deduplication and extension detection
5
+ */
6
+ export declare class FileNamingService {
7
+ private fsAdapter;
8
+ private readonly MAX_ATTEMPTS;
9
+ private readonly CONTENT_TYPE_MAP;
10
+ constructor(fsAdapter: FileSystemAdapter);
11
+ /**
12
+ * Ensures the filename has an extension
13
+ * Priority: existing extension > content-type header > default .jpg
14
+ * @param filename - Original filename
15
+ * @param contentType - HTTP Content-Type header (optional)
16
+ * @returns Filename with extension
17
+ */
18
+ ensureExtension(filename: string, contentType: string | null): string;
19
+ /**
20
+ * Ensures the filename is unique in the target directory
21
+ * Appends _1, _2, _3, etc. if file already exists
22
+ * @param targetDir - Target directory path
23
+ * @param filename - Desired filename
24
+ * @returns Unique filename
25
+ */
26
+ ensureUniqueFilename(targetDir: string, filename: string): Promise<string>;
27
+ /**
28
+ * Extracts file extension from Content-Type header
29
+ * @param contentType - HTTP Content-Type header
30
+ * @returns File extension without dot, or null if not found
31
+ */
32
+ private getExtensionFromContentType;
33
+ }
34
+ //# sourceMappingURL=file-naming.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-naming.service.d.ts","sourceRoot":"","sources":["../../../src/application/services/file-naming.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AAEjF;;;GAGG;AACH,qBACa,iBAAiB;IAgBC,OAAO,CAAC,SAAS;IAf9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAO;IAGpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAS/B;gBAGmC,SAAS,EAAE,iBAAiB;IAGjE;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;IAmBrE;;;;;;OAMG;IACG,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6BhF;;;;OAIG;IACH,OAAO,CAAC,2BAA2B;CAMpC"}
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
45
+ return function (target, key) { decorator(target, key, paramIndex); }
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.FileNamingService = void 0;
49
+ const tsyringe_1 = require("tsyringe");
50
+ const path = __importStar(require("path"));
51
+ const filesystem_adapter_1 = require("../../infrastructure/adapters/filesystem.adapter");
52
+ /**
53
+ * File Naming Service
54
+ * Handles file naming logic including deduplication and extension detection
55
+ */
56
+ let FileNamingService = class FileNamingService {
57
+ fsAdapter;
58
+ MAX_ATTEMPTS = 100;
59
+ // Map content types to file extensions
60
+ CONTENT_TYPE_MAP = {
61
+ 'image/jpeg': 'jpg',
62
+ 'image/jpg': 'jpg',
63
+ 'image/png': 'png',
64
+ 'image/gif': 'gif',
65
+ 'image/webp': 'webp',
66
+ 'image/svg+xml': 'svg',
67
+ 'image/bmp': 'bmp',
68
+ 'image/tiff': 'tiff',
69
+ };
70
+ constructor(fsAdapter) {
71
+ this.fsAdapter = fsAdapter;
72
+ }
73
+ /**
74
+ * Ensures the filename has an extension
75
+ * Priority: existing extension > content-type header > default .jpg
76
+ * @param filename - Original filename
77
+ * @param contentType - HTTP Content-Type header (optional)
78
+ * @returns Filename with extension
79
+ */
80
+ ensureExtension(filename, contentType) {
81
+ // Check if filename already has an extension
82
+ const ext = path.extname(filename);
83
+ if (ext) {
84
+ return filename; // Already has extension, keep it
85
+ }
86
+ // Try to get extension from content type
87
+ if (contentType) {
88
+ const extension = this.getExtensionFromContentType(contentType);
89
+ if (extension) {
90
+ return `${filename}.${extension}`;
91
+ }
92
+ }
93
+ // Default to .jpg
94
+ return `${filename}.jpg`;
95
+ }
96
+ /**
97
+ * Ensures the filename is unique in the target directory
98
+ * Appends _1, _2, _3, etc. if file already exists
99
+ * @param targetDir - Target directory path
100
+ * @param filename - Desired filename
101
+ * @returns Unique filename
102
+ */
103
+ async ensureUniqueFilename(targetDir, filename) {
104
+ const ext = path.extname(filename);
105
+ const basename = path.basename(filename, ext);
106
+ // Check if original filename is available
107
+ const originalPath = path.join(targetDir, filename);
108
+ const exists = await this.fsAdapter.fileExists(originalPath);
109
+ if (!exists) {
110
+ return filename;
111
+ }
112
+ // Try with counter suffix
113
+ for (let counter = 1; counter <= this.MAX_ATTEMPTS; counter++) {
114
+ const newFilename = ext
115
+ ? `${basename}_${counter}${ext}`
116
+ : `${basename}_${counter}`;
117
+ const newPath = path.join(targetDir, newFilename);
118
+ const exists = await this.fsAdapter.fileExists(newPath);
119
+ if (!exists) {
120
+ return newFilename;
121
+ }
122
+ }
123
+ throw new Error(`Could not find unique filename after ${this.MAX_ATTEMPTS} attempts`);
124
+ }
125
+ /**
126
+ * Extracts file extension from Content-Type header
127
+ * @param contentType - HTTP Content-Type header
128
+ * @returns File extension without dot, or null if not found
129
+ */
130
+ getExtensionFromContentType(contentType) {
131
+ // Remove charset and other parameters
132
+ const mimeType = contentType.split(';')[0].trim().toLowerCase();
133
+ return this.CONTENT_TYPE_MAP[mimeType] || null;
134
+ }
135
+ };
136
+ exports.FileNamingService = FileNamingService;
137
+ exports.FileNamingService = FileNamingService = __decorate([
138
+ (0, tsyringe_1.injectable)(),
139
+ __param(0, (0, tsyringe_1.inject)(filesystem_adapter_1.FileSystemAdapter)),
140
+ __metadata("design:paramtypes", [filesystem_adapter_1.FileSystemAdapter])
141
+ ], FileNamingService);
142
+ //# sourceMappingURL=file-naming.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-naming.service.js","sourceRoot":"","sources":["../../../src/application/services/file-naming.service.ts"],"names":[],"mappings":"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"}