@openinary/core 1.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.
Files changed (242) hide show
  1. package/LICENSE +661 -0
  2. package/dist/config/deps.d.ts +14 -0
  3. package/dist/config/deps.d.ts.map +1 -0
  4. package/dist/config/deps.js +2 -0
  5. package/dist/config/deps.js.map +1 -0
  6. package/dist/index.d.ts +27 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +28 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/routes/authenticated.d.ts +4 -0
  11. package/dist/routes/authenticated.d.ts.map +1 -0
  12. package/dist/routes/authenticated.js +130 -0
  13. package/dist/routes/authenticated.js.map +1 -0
  14. package/dist/routes/download-folder.d.ts +4 -0
  15. package/dist/routes/download-folder.d.ts.map +1 -0
  16. package/dist/routes/download-folder.js +101 -0
  17. package/dist/routes/download-folder.js.map +1 -0
  18. package/dist/routes/download-zip.d.ts +15 -0
  19. package/dist/routes/download-zip.d.ts.map +1 -0
  20. package/dist/routes/download-zip.js +147 -0
  21. package/dist/routes/download-zip.js.map +1 -0
  22. package/dist/routes/download.d.ts +4 -0
  23. package/dist/routes/download.d.ts.map +1 -0
  24. package/dist/routes/download.js +83 -0
  25. package/dist/routes/download.js.map +1 -0
  26. package/dist/routes/invalidate.d.ts +4 -0
  27. package/dist/routes/invalidate.d.ts.map +1 -0
  28. package/dist/routes/invalidate.js +114 -0
  29. package/dist/routes/invalidate.js.map +1 -0
  30. package/dist/routes/queue-events.d.ts +4 -0
  31. package/dist/routes/queue-events.d.ts.map +1 -0
  32. package/dist/routes/queue-events.js +125 -0
  33. package/dist/routes/queue-events.js.map +1 -0
  34. package/dist/routes/queue.d.ts +4 -0
  35. package/dist/routes/queue.d.ts.map +1 -0
  36. package/dist/routes/queue.js +130 -0
  37. package/dist/routes/queue.js.map +1 -0
  38. package/dist/routes/storage.d.ts +4 -0
  39. package/dist/routes/storage.d.ts.map +1 -0
  40. package/dist/routes/storage.js +694 -0
  41. package/dist/routes/storage.js.map +1 -0
  42. package/dist/routes/transform-helpers.d.ts +62 -0
  43. package/dist/routes/transform-helpers.d.ts.map +1 -0
  44. package/dist/routes/transform-helpers.js +372 -0
  45. package/dist/routes/transform-helpers.js.map +1 -0
  46. package/dist/routes/transform.d.ts +4 -0
  47. package/dist/routes/transform.d.ts.map +1 -0
  48. package/dist/routes/transform.js +65 -0
  49. package/dist/routes/transform.js.map +1 -0
  50. package/dist/routes/video-status.d.ts +4 -0
  51. package/dist/routes/video-status.d.ts.map +1 -0
  52. package/dist/routes/video-status.js +208 -0
  53. package/dist/routes/video-status.js.map +1 -0
  54. package/dist/services/transform.service.d.ts +71 -0
  55. package/dist/services/transform.service.d.ts.map +1 -0
  56. package/dist/services/transform.service.js +362 -0
  57. package/dist/services/transform.service.js.map +1 -0
  58. package/dist/types.d.ts +82 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +2 -0
  61. package/dist/types.js.map +1 -0
  62. package/dist/utils/asset-deletion.d.ts +16 -0
  63. package/dist/utils/asset-deletion.d.ts.map +1 -0
  64. package/dist/utils/asset-deletion.js +131 -0
  65. package/dist/utils/asset-deletion.js.map +1 -0
  66. package/dist/utils/cache.d.ts +44 -0
  67. package/dist/utils/cache.d.ts.map +1 -0
  68. package/dist/utils/cache.js +248 -0
  69. package/dist/utils/cache.js.map +1 -0
  70. package/dist/utils/get-unique-file-path.d.ts +8 -0
  71. package/dist/utils/get-unique-file-path.d.ts.map +1 -0
  72. package/dist/utils/get-unique-file-path.js +26 -0
  73. package/dist/utils/get-unique-file-path.js.map +1 -0
  74. package/dist/utils/image/aspect-ratio.d.ts +7 -0
  75. package/dist/utils/image/aspect-ratio.d.ts.map +1 -0
  76. package/dist/utils/image/aspect-ratio.js +40 -0
  77. package/dist/utils/image/aspect-ratio.js.map +1 -0
  78. package/dist/utils/image/background.d.ts +6 -0
  79. package/dist/utils/image/background.d.ts.map +1 -0
  80. package/dist/utils/image/background.js +22 -0
  81. package/dist/utils/image/background.js.map +1 -0
  82. package/dist/utils/image/compression.d.ts +44 -0
  83. package/dist/utils/image/compression.d.ts.map +1 -0
  84. package/dist/utils/image/compression.js +345 -0
  85. package/dist/utils/image/compression.js.map +1 -0
  86. package/dist/utils/image/gravity.d.ts +6 -0
  87. package/dist/utils/image/gravity.d.ts.map +1 -0
  88. package/dist/utils/image/gravity.js +24 -0
  89. package/dist/utils/image/gravity.js.map +1 -0
  90. package/dist/utils/image/index.d.ts +8 -0
  91. package/dist/utils/image/index.d.ts.map +1 -0
  92. package/dist/utils/image/index.js +77 -0
  93. package/dist/utils/image/index.js.map +1 -0
  94. package/dist/utils/image/param-registry.d.ts +63 -0
  95. package/dist/utils/image/param-registry.d.ts.map +1 -0
  96. package/dist/utils/image/param-registry.js +196 -0
  97. package/dist/utils/image/param-registry.js.map +1 -0
  98. package/dist/utils/image/quality.d.ts +8 -0
  99. package/dist/utils/image/quality.d.ts.map +1 -0
  100. package/dist/utils/image/quality.js +9 -0
  101. package/dist/utils/image/quality.js.map +1 -0
  102. package/dist/utils/image/resize.d.ts +7 -0
  103. package/dist/utils/image/resize.d.ts.map +1 -0
  104. package/dist/utils/image/resize.js +62 -0
  105. package/dist/utils/image/resize.js.map +1 -0
  106. package/dist/utils/image/rotation.d.ts +6 -0
  107. package/dist/utils/image/rotation.d.ts.map +1 -0
  108. package/dist/utils/image/rotation.js +20 -0
  109. package/dist/utils/image/rotation.js.map +1 -0
  110. package/dist/utils/image/round-corners.d.ts +12 -0
  111. package/dist/utils/image/round-corners.d.ts.map +1 -0
  112. package/dist/utils/image/round-corners.js +102 -0
  113. package/dist/utils/image/round-corners.js.map +1 -0
  114. package/dist/utils/image/types.d.ts +2 -0
  115. package/dist/utils/image/types.d.ts.map +1 -0
  116. package/dist/utils/image/types.js +2 -0
  117. package/dist/utils/image/types.js.map +1 -0
  118. package/dist/utils/logger.d.ts +21 -0
  119. package/dist/utils/logger.d.ts.map +1 -0
  120. package/dist/utils/logger.js +82 -0
  121. package/dist/utils/logger.js.map +1 -0
  122. package/dist/utils/parser.d.ts +8 -0
  123. package/dist/utils/parser.d.ts.map +1 -0
  124. package/dist/utils/parser.js +226 -0
  125. package/dist/utils/parser.js.map +1 -0
  126. package/dist/utils/signature.d.ts +35 -0
  127. package/dist/utils/signature.d.ts.map +1 -0
  128. package/dist/utils/signature.js +100 -0
  129. package/dist/utils/signature.js.map +1 -0
  130. package/dist/utils/storage/cache.d.ts +41 -0
  131. package/dist/utils/storage/cache.d.ts.map +1 -0
  132. package/dist/utils/storage/cache.js +90 -0
  133. package/dist/utils/storage/cache.js.map +1 -0
  134. package/dist/utils/storage/cloud-storage.d.ts +188 -0
  135. package/dist/utils/storage/cloud-storage.d.ts.map +1 -0
  136. package/dist/utils/storage/cloud-storage.js +514 -0
  137. package/dist/utils/storage/cloud-storage.js.map +1 -0
  138. package/dist/utils/storage/factory.d.ts +10 -0
  139. package/dist/utils/storage/factory.d.ts.map +1 -0
  140. package/dist/utils/storage/factory.js +17 -0
  141. package/dist/utils/storage/factory.js.map +1 -0
  142. package/dist/utils/storage/index.d.ts +7 -0
  143. package/dist/utils/storage/index.d.ts.map +1 -0
  144. package/dist/utils/storage/index.js +8 -0
  145. package/dist/utils/storage/index.js.map +1 -0
  146. package/dist/utils/storage/key-generator.d.ts +11 -0
  147. package/dist/utils/storage/key-generator.d.ts.map +1 -0
  148. package/dist/utils/storage/key-generator.js +23 -0
  149. package/dist/utils/storage/key-generator.js.map +1 -0
  150. package/dist/utils/storage/listing-cache.d.ts +14 -0
  151. package/dist/utils/storage/listing-cache.d.ts.map +1 -0
  152. package/dist/utils/storage/listing-cache.js +29 -0
  153. package/dist/utils/storage/listing-cache.js.map +1 -0
  154. package/dist/utils/storage/s3-client.d.ts +97 -0
  155. package/dist/utils/storage/s3-client.d.ts.map +1 -0
  156. package/dist/utils/storage/s3-client.js +297 -0
  157. package/dist/utils/storage/s3-client.js.map +1 -0
  158. package/dist/utils/storage/stats-tracker.d.ts +45 -0
  159. package/dist/utils/storage/stats-tracker.d.ts.map +1 -0
  160. package/dist/utils/storage/stats-tracker.js +97 -0
  161. package/dist/utils/storage/stats-tracker.js.map +1 -0
  162. package/dist/utils/storage/types.d.ts +2 -0
  163. package/dist/utils/storage/types.d.ts.map +1 -0
  164. package/dist/utils/storage/types.js +2 -0
  165. package/dist/utils/storage/types.js.map +1 -0
  166. package/dist/utils/storage-level.d.ts +66 -0
  167. package/dist/utils/storage-level.d.ts.map +1 -0
  168. package/dist/utils/storage-level.js +106 -0
  169. package/dist/utils/storage-level.js.map +1 -0
  170. package/dist/utils/storage-tree.d.ts +30 -0
  171. package/dist/utils/storage-tree.d.ts.map +1 -0
  172. package/dist/utils/storage-tree.js +81 -0
  173. package/dist/utils/storage-tree.js.map +1 -0
  174. package/dist/utils/upload-signature.d.ts +25 -0
  175. package/dist/utils/upload-signature.d.ts.map +1 -0
  176. package/dist/utils/upload-signature.js +56 -0
  177. package/dist/utils/upload-signature.js.map +1 -0
  178. package/dist/utils/video/auto-downscale.d.ts +12 -0
  179. package/dist/utils/video/auto-downscale.d.ts.map +1 -0
  180. package/dist/utils/video/auto-downscale.js +29 -0
  181. package/dist/utils/video/auto-downscale.js.map +1 -0
  182. package/dist/utils/video/command-builder.d.ts +22 -0
  183. package/dist/utils/video/command-builder.d.ts.map +1 -0
  184. package/dist/utils/video/command-builder.js +79 -0
  185. package/dist/utils/video/command-builder.js.map +1 -0
  186. package/dist/utils/video/config.d.ts +51 -0
  187. package/dist/utils/video/config.d.ts.map +1 -0
  188. package/dist/utils/video/config.js +170 -0
  189. package/dist/utils/video/config.js.map +1 -0
  190. package/dist/utils/video/format.d.ts +22 -0
  191. package/dist/utils/video/format.d.ts.map +1 -0
  192. package/dist/utils/video/format.js +64 -0
  193. package/dist/utils/video/format.js.map +1 -0
  194. package/dist/utils/video/index.d.ts +25 -0
  195. package/dist/utils/video/index.d.ts.map +1 -0
  196. package/dist/utils/video/index.js +104 -0
  197. package/dist/utils/video/index.js.map +1 -0
  198. package/dist/utils/video/param-registry.d.ts +64 -0
  199. package/dist/utils/video/param-registry.d.ts.map +1 -0
  200. package/dist/utils/video/param-registry.js +201 -0
  201. package/dist/utils/video/param-registry.js.map +1 -0
  202. package/dist/utils/video/quality.d.ts +12 -0
  203. package/dist/utils/video/quality.d.ts.map +1 -0
  204. package/dist/utils/video/quality.js +45 -0
  205. package/dist/utils/video/quality.js.map +1 -0
  206. package/dist/utils/video/queue-store.d.ts +51 -0
  207. package/dist/utils/video/queue-store.d.ts.map +1 -0
  208. package/dist/utils/video/queue-store.js +2 -0
  209. package/dist/utils/video/queue-store.js.map +1 -0
  210. package/dist/utils/video/resize.d.ts +7 -0
  211. package/dist/utils/video/resize.d.ts.map +1 -0
  212. package/dist/utils/video/resize.js +40 -0
  213. package/dist/utils/video/resize.js.map +1 -0
  214. package/dist/utils/video/sqlite-video-job-store.d.ts +29 -0
  215. package/dist/utils/video/sqlite-video-job-store.d.ts.map +1 -0
  216. package/dist/utils/video/sqlite-video-job-store.js +320 -0
  217. package/dist/utils/video/sqlite-video-job-store.js.map +1 -0
  218. package/dist/utils/video/thumbnail.d.ts +7 -0
  219. package/dist/utils/video/thumbnail.d.ts.map +1 -0
  220. package/dist/utils/video/thumbnail.js +22 -0
  221. package/dist/utils/video/thumbnail.js.map +1 -0
  222. package/dist/utils/video/trim.d.ts +7 -0
  223. package/dist/utils/video/trim.d.ts.map +1 -0
  224. package/dist/utils/video/trim.js +36 -0
  225. package/dist/utils/video/trim.js.map +1 -0
  226. package/dist/utils/video/types.d.ts +19 -0
  227. package/dist/utils/video/types.d.ts.map +1 -0
  228. package/dist/utils/video/types.js +2 -0
  229. package/dist/utils/video/types.js.map +1 -0
  230. package/dist/utils/video/video-info.d.ts +25 -0
  231. package/dist/utils/video/video-info.d.ts.map +1 -0
  232. package/dist/utils/video/video-info.js +58 -0
  233. package/dist/utils/video/video-info.js.map +1 -0
  234. package/dist/utils/video/video-worker.d.ts +52 -0
  235. package/dist/utils/video/video-worker.d.ts.map +1 -0
  236. package/dist/utils/video/video-worker.js +192 -0
  237. package/dist/utils/video/video-worker.js.map +1 -0
  238. package/dist/utils/video-job-queue.d.ts +62 -0
  239. package/dist/utils/video-job-queue.d.ts.map +1 -0
  240. package/dist/utils/video-job-queue.js +122 -0
  241. package/dist/utils/video-job-queue.js.map +1 -0
  242. package/package.json +51 -0
@@ -0,0 +1,514 @@
1
+ import { StorageCache } from "./cache.js";
2
+ import { KeyGenerator } from "./key-generator.js";
3
+ import { S3ClientWrapper } from "./s3-client.js";
4
+ import logger, { serializeError } from "../logger.js";
5
+ import { FOLDER_SUMMARY_MAX_KEYS, shapeFolderSummary, shapeLevel, } from "../storage-level.js";
6
+ import { adjustBucketStats, } from "./stats-tracker.js";
7
+ // Lives at the bucket root, outside public/ and cache/, so it never shows up
8
+ // in media listings or cache stats
9
+ const STATS_OBJECT_KEY = ".openinary/stats.json";
10
+ function isAggregateStats(value) {
11
+ return (typeof value === "object" &&
12
+ value !== null &&
13
+ typeof value.size === "number" &&
14
+ typeof value.fileCount === "number");
15
+ }
16
+ export class CloudStorage {
17
+ s3Client;
18
+ cache;
19
+ constructor(config, clientOptions) {
20
+ this.s3Client = new S3ClientWrapper(config, clientOptions);
21
+ this.cache = new StorageCache();
22
+ }
23
+ /**
24
+ * Lists objects in storage (cloud only)
25
+ */
26
+ async list(prefix) {
27
+ return await this.s3Client.listObjects(prefix);
28
+ }
29
+ /**
30
+ * Lists one directory level (direct child prefixes + objects) using Delimiter: "/"
31
+ */
32
+ async listDelimited(prefix) {
33
+ return await this.s3Client.listDelimited(prefix);
34
+ }
35
+ /**
36
+ * Lists a single page of one directory level (bounded by maxKeys)
37
+ */
38
+ async listDelimitedPage(prefix, maxKeys) {
39
+ return await this.s3Client.listDelimitedPage(prefix, maxKeys);
40
+ }
41
+ /**
42
+ * Lists all objects under a prefix by fanning out one recursive listing per
43
+ * top-level folder in parallel, instead of a single sequential pagination
44
+ */
45
+ async listAllParallel(prefix) {
46
+ const topLevel = await this.s3Client.listDelimited(prefix);
47
+ const results = [...topLevel.objects];
48
+ const batchSize = 16;
49
+ for (let i = 0; i < topLevel.prefixes.length; i += batchSize) {
50
+ const batch = topLevel.prefixes.slice(i, i + batchSize);
51
+ const nested = await Promise.all(batch.map((folderPrefix) => this.s3Client.listObjects(folderPrefix)));
52
+ for (const objects of nested) {
53
+ results.push(...objects);
54
+ }
55
+ }
56
+ return results;
57
+ }
58
+ /**
59
+ * Lists one directory level of original files (under public/)
60
+ */
61
+ async listLevel(folderPath) {
62
+ const storagePrefix = folderPath ? `public/${folderPath}/` : "public/";
63
+ const delimited = await this.s3Client.listDelimited(storagePrefix);
64
+ return shapeLevel(storagePrefix, folderPath, delimited);
65
+ }
66
+ /**
67
+ * Gets a bounded summary of a folder (direct child count, truncation flag,
68
+ * media preview items) from a single delimiter-listed page
69
+ */
70
+ async getFolderSummary(folderPath, maxKeys = FOLDER_SUMMARY_MAX_KEYS) {
71
+ const storagePrefix = `public/${folderPath}/`;
72
+ const page = await this.s3Client.listDelimitedPage(storagePrefix, maxKeys);
73
+ return shapeFolderSummary(storagePrefix, folderPath, page);
74
+ }
75
+ /**
76
+ * Creates a folder marker object so empty folders are visible in S3-compatible storage
77
+ */
78
+ async createFolder(folderPath) {
79
+ const normalized = folderPath.replace(/^\/+/, "").replace(/\/+$/, "");
80
+ const storageKey = `public/${normalized}/`;
81
+ await this.s3Client.createFolderMarker(storageKey);
82
+ }
83
+ /**
84
+ * Checks whether a folder exists (marker or any object with the folder prefix)
85
+ */
86
+ async folderExists(folderPath) {
87
+ const normalized = folderPath.replace(/^\/+/, "").replace(/\/+$/, "");
88
+ const markerKey = `public/${normalized}/`;
89
+ if (await this.s3Client.objectExists(markerKey)) {
90
+ return true;
91
+ }
92
+ const prefixedObjects = await this.s3Client.listObjects(markerKey, 1);
93
+ return prefixedObjects.length > 0;
94
+ }
95
+ /**
96
+ * Renames/moves all objects under a folder prefix to a new prefix (copy + delete each)
97
+ */
98
+ async renameFolder(oldFolderPath, newFolderPath) {
99
+ const normalizedOld = oldFolderPath.replace(/^\/+/, "").replace(/\/+$/, "");
100
+ const normalizedNew = newFolderPath.replace(/^\/+/, "").replace(/\/+$/, "");
101
+ const prefix = `public/${normalizedOld}/`;
102
+ const objects = await this.s3Client.listObjects(prefix);
103
+ for (const obj of objects) {
104
+ const relativeKey = obj.key.slice(prefix.length);
105
+ const destKey = `public/${normalizedNew}/${relativeKey}`;
106
+ await this.s3Client.copyObject(obj.key, destKey);
107
+ await this.s3Client.deleteObject(obj.key);
108
+ }
109
+ this.cache.delete(`original:${normalizedOld}`);
110
+ }
111
+ /**
112
+ * Deletes all objects under a folder prefix (marker + contents)
113
+ */
114
+ async deleteFolder(folderPath) {
115
+ const normalized = folderPath.replace(/^\/+/, "").replace(/\/+$/, "");
116
+ const prefix = `public/${normalized}/`;
117
+ const objects = await this.s3Client.listObjects(prefix);
118
+ if (objects.length === 0) {
119
+ return 0;
120
+ }
121
+ const keys = objects.map((obj) => obj.key);
122
+ const deleted = await this.s3Client.deleteObjects(keys);
123
+ // Folder markers are excluded from stats, so only count real files
124
+ let deletedSize = 0;
125
+ let deletedFiles = 0;
126
+ for (const obj of objects) {
127
+ if (obj.key.endsWith("/"))
128
+ continue;
129
+ deletedSize += obj.size ?? 0;
130
+ deletedFiles += 1;
131
+ }
132
+ if (deletedFiles > 0) {
133
+ adjustBucketStats(this, "storage", {
134
+ size: -deletedSize,
135
+ fileCount: -deletedFiles,
136
+ });
137
+ }
138
+ // Invalidate in-memory cache for all deleted keys
139
+ this.cache.delete(`original:${normalized}`);
140
+ return deleted;
141
+ }
142
+ /**
143
+ * Checks file existence with intelligent caching for transformed files
144
+ */
145
+ async exists(originalPath, params) {
146
+ const key = KeyGenerator.generateKey(originalPath, params);
147
+ const cacheKey = `exists:${key}`;
148
+ const cached = this.cache.get(cacheKey);
149
+ // OPTIMIZATION: Cache hit = 0 Class B operation
150
+ if (cached) {
151
+ return cached.exists;
152
+ }
153
+ // Only if not in cache
154
+ const exists = await this.s3Client.objectExists(key);
155
+ this.cache.set(cacheKey, {
156
+ exists,
157
+ timestamp: Date.now(),
158
+ });
159
+ return exists;
160
+ }
161
+ /**
162
+ * Checks the existence of an original file with cache (by original path)
163
+ */
164
+ async existsOriginal(originalPath) {
165
+ return this.existsOriginalPath(originalPath);
166
+ }
167
+ /**
168
+ * Checks the existence of an original file WITHOUT using cache
169
+ * Used after deletion to ensure we don't serve stale cache data
170
+ */
171
+ async existsOriginalNoCache(originalPath) {
172
+ const storageKey = `public/${originalPath}`;
173
+ try {
174
+ const exists = await this.s3Client.objectExists(storageKey);
175
+ // Update cache with the fresh result
176
+ this.cache.set(`original:${originalPath}`, {
177
+ exists,
178
+ timestamp: Date.now(),
179
+ });
180
+ return exists;
181
+ }
182
+ catch (error) {
183
+ logger.error({
184
+ error: error.message,
185
+ filePath: originalPath,
186
+ metadata: error.$metadata,
187
+ }, "Cloud storage error while checking original path (no cache)");
188
+ return false;
189
+ }
190
+ }
191
+ /**
192
+ * Checks existence of an arbitrary original-path key (without params),
193
+ * using the same semantics as uploadOriginal/downloadOriginal.
194
+ * This is useful for detecting duplicate uploads by full path.
195
+ */
196
+ async existsOriginalPath(filePath) {
197
+ const cacheKey = `original:${filePath}`;
198
+ const cached = this.cache.get(cacheKey);
199
+ if (cached) {
200
+ return cached.exists;
201
+ }
202
+ const storageKey = `public/${filePath}`;
203
+ try {
204
+ const exists = await this.s3Client.objectExists(storageKey);
205
+ this.cache.set(cacheKey, {
206
+ exists,
207
+ timestamp: Date.now(),
208
+ });
209
+ return exists;
210
+ }
211
+ catch (error) {
212
+ logger.error({
213
+ error: error.message,
214
+ filePath,
215
+ metadata: error.$metadata,
216
+ }, "Cloud storage error while checking original path");
217
+ this.cache.set(cacheKey, {
218
+ exists: false,
219
+ timestamp: Date.now(),
220
+ });
221
+ return false;
222
+ }
223
+ }
224
+ /**
225
+ * Retrieves an original (unprocessed) file from the bucket
226
+ */
227
+ async downloadOriginal(originalPath) {
228
+ // Add public/ prefix for storage
229
+ const storageKey = `public/${originalPath}`;
230
+ return await this.s3Client.downloadObject(storageKey);
231
+ }
232
+ /**
233
+ * Retrieves an original (unprocessed) file as a stream, without buffering
234
+ * it in memory. Used to serve large originals (e.g. videos still being
235
+ * optimized) directly to clients.
236
+ */
237
+ async downloadOriginalStream(originalPath) {
238
+ const storageKey = `public/${originalPath}`;
239
+ return await this.s3Client.downloadObjectStream(storageKey);
240
+ }
241
+ /**
242
+ * Uploads an original (unprocessed) file to the bucket
243
+ */
244
+ async uploadOriginal(filePath, buffer, contentType) {
245
+ // Add public/ prefix for storage
246
+ const storageKey = `public/${filePath}`;
247
+ await this.s3Client.uploadObject(storageKey, buffer, contentType);
248
+ adjustBucketStats(this, "storage", { size: buffer.length, fileCount: 1 });
249
+ // Mark the file as existing in the cache
250
+ this.cache.set(`original:${filePath}`, {
251
+ exists: true,
252
+ timestamp: Date.now(),
253
+ });
254
+ // Returns the public URL (without public/ prefix since it's internal)
255
+ return this.s3Client.getPublicUrl(storageKey);
256
+ }
257
+ /**
258
+ * Upload with cache invalidation
259
+ */
260
+ async upload(originalPath, params, buffer, contentType) {
261
+ const key = KeyGenerator.generateKey(originalPath, params);
262
+ // Add metadata for easy cleanup later
263
+ // Encoded because x-amz-meta-* header values must be ASCII-safe;
264
+ // some S3-compatible providers reject non-ASCII bytes outright.
265
+ const metadata = {
266
+ "x-original-path": encodeURIComponent(originalPath),
267
+ };
268
+ await this.s3Client.uploadObject(key, buffer, contentType, metadata);
269
+ adjustBucketStats(this, "cache", { size: buffer.length, fileCount: 1 });
270
+ // Mark the file as existing in the cache
271
+ this.cache.set(`exists:${key}`, {
272
+ exists: true,
273
+ timestamp: Date.now(),
274
+ });
275
+ // Returns the public URL
276
+ return this.s3Client.getPublicUrl(key);
277
+ }
278
+ /**
279
+ * Retrieves a file from the bucket
280
+ */
281
+ async download(originalPath, params) {
282
+ const key = KeyGenerator.generateKey(originalPath, params);
283
+ return await this.s3Client.downloadObject(key);
284
+ }
285
+ /**
286
+ * Generates a signed URL for temporary access (optional)
287
+ */
288
+ async getSignedUrl(originalPath, params, expiresIn = 3600) {
289
+ const key = KeyGenerator.generateKey(originalPath, params);
290
+ return await this.s3Client.getSignedUrl(key, expiresIn);
291
+ }
292
+ /**
293
+ * Deletes an original file from storage
294
+ */
295
+ async deleteOriginal(originalPath) {
296
+ // Add public/ prefix for storage
297
+ const storageKey = `public/${originalPath}`;
298
+ // HEAD first: the deleted object's size is needed for stats tracking,
299
+ // and a delete on a missing key succeeds silently
300
+ const metadata = await this.s3Client.getObjectMetadata(storageKey);
301
+ await this.s3Client.deleteObject(storageKey);
302
+ if (metadata) {
303
+ adjustBucketStats(this, "storage", {
304
+ size: -metadata.size,
305
+ fileCount: -1,
306
+ });
307
+ }
308
+ // Invalidate cache
309
+ this.cache.delete(`original:${originalPath}`);
310
+ }
311
+ /**
312
+ * Copies an original file to a new path within storage
313
+ */
314
+ async copyOriginal(sourcePath, destPath) {
315
+ const sourceKey = `public/${sourcePath}`;
316
+ const destKey = `public/${destPath}`;
317
+ await this.s3Client.copyObject(sourceKey, destKey);
318
+ const metadata = await this.s3Client.getObjectMetadata(destKey);
319
+ if (metadata) {
320
+ adjustBucketStats(this, "storage", {
321
+ size: metadata.size,
322
+ fileCount: 1,
323
+ });
324
+ }
325
+ // Mark the new file as existing in the cache
326
+ this.cache.set(`original:${destPath}`, {
327
+ exists: true,
328
+ timestamp: Date.now(),
329
+ });
330
+ }
331
+ /**
332
+ * Renames/moves an original file to a new path (copy + delete)
333
+ */
334
+ async renameOriginal(sourcePath, destPath) {
335
+ await this.copyOriginal(sourcePath, destPath);
336
+ await this.deleteOriginal(sourcePath);
337
+ }
338
+ /**
339
+ * Gets metadata for an original file (size, dates)
340
+ */
341
+ async getOriginalMetadata(originalPath) {
342
+ const storageKey = `public/${originalPath}`;
343
+ const metadata = await this.s3Client.getObjectMetadata(storageKey);
344
+ if (!metadata) {
345
+ return null;
346
+ }
347
+ // For S3, we use lastModified for both dates since S3 doesn't track creation time separately
348
+ return {
349
+ size: metadata.size,
350
+ createdAt: metadata.lastModified,
351
+ updatedAt: metadata.lastModified,
352
+ };
353
+ }
354
+ /**
355
+ * Gets metadata for an optimized/transformed file (size only)
356
+ */
357
+ async getOptimizedMetadata(originalPath, params) {
358
+ const key = KeyGenerator.generateKey(originalPath, params);
359
+ const metadata = await this.s3Client.getObjectMetadata(key);
360
+ if (!metadata) {
361
+ return null;
362
+ }
363
+ return {
364
+ size: metadata.size,
365
+ };
366
+ }
367
+ /**
368
+ * Invalidates the cache for a specific file
369
+ */
370
+ invalidateCache(originalPath, params) {
371
+ if (params) {
372
+ const key = KeyGenerator.generateKey(originalPath, params);
373
+ this.cache.delete(`exists:${key}`);
374
+ }
375
+ this.cache.delete(`original:${originalPath}`);
376
+ }
377
+ /**
378
+ * Deletes all cached transformations for an original file from cloud storage
379
+ * Uses metadata to identify files belonging to the original path
380
+ */
381
+ async deleteAllCachedTransformations(originalPath) {
382
+ try {
383
+ // List all objects with cache/ prefix
384
+ const cacheObjects = await this.s3Client.listObjects("cache/");
385
+ const keysToDelete = [];
386
+ let sizeToDelete = 0;
387
+ // Check each object's metadata to see if it belongs to this original path
388
+ for (const obj of cacheObjects) {
389
+ try {
390
+ const metadata = await this.s3Client.getObjectMetadata(obj.key);
391
+ if (metadata?.metadata?.["x-original-path"] ===
392
+ encodeURIComponent(originalPath)) {
393
+ keysToDelete.push(obj.key);
394
+ sizeToDelete += obj.size ?? 0;
395
+ }
396
+ }
397
+ catch (error) {
398
+ // If we can't get metadata, skip this object
399
+ logger.warn({ error: serializeError(error), key: obj.key }, "Failed to get metadata for cache object");
400
+ }
401
+ }
402
+ if (keysToDelete.length === 0) {
403
+ logger.debug({ originalPath }, "No cached transformations found in cloud storage");
404
+ return 0;
405
+ }
406
+ // Delete all identified objects
407
+ const deletedCount = await this.s3Client.deleteObjects(keysToDelete);
408
+ adjustBucketStats(this, "cache", {
409
+ size: -sizeToDelete,
410
+ fileCount: -keysToDelete.length,
411
+ });
412
+ logger.info({ originalPath, deletedCount, totalFound: keysToDelete.length }, "Deleted cached transformations from cloud storage");
413
+ return deletedCount;
414
+ }
415
+ catch (error) {
416
+ logger.error({ error: serializeError(error), originalPath }, "Failed to delete cached transformations");
417
+ throw error;
418
+ }
419
+ }
420
+ /**
421
+ * Loads the persisted aggregate stats object, or null when it doesn't
422
+ * exist yet or is unreadable (triggering a recomputation)
423
+ */
424
+ async loadPersistedStats() {
425
+ if (!(await this.s3Client.objectExists(STATS_OBJECT_KEY))) {
426
+ return null;
427
+ }
428
+ try {
429
+ const buffer = await this.s3Client.downloadObject(STATS_OBJECT_KEY);
430
+ const parsed = JSON.parse(buffer.toString("utf-8"));
431
+ if (isAggregateStats(parsed?.storage) &&
432
+ isAggregateStats(parsed?.cache) &&
433
+ typeof parsed.updatedAt === "string") {
434
+ return parsed;
435
+ }
436
+ logger.warn("Persisted bucket stats have an unexpected shape, recomputing");
437
+ return null;
438
+ }
439
+ catch (error) {
440
+ logger.warn({ error: serializeError(error) }, "Failed to load persisted bucket stats, recomputing");
441
+ return null;
442
+ }
443
+ }
444
+ /**
445
+ * Persists the aggregate stats object to the bucket
446
+ */
447
+ async persistStats(stats) {
448
+ await this.s3Client.uploadObject(STATS_OBJECT_KEY, Buffer.from(JSON.stringify(stats)), "application/json");
449
+ }
450
+ /**
451
+ * Recomputes aggregate stats from full bucket listings. O(n) in object
452
+ * count - only used to seed the tracker and for explicit reconciliation,
453
+ * never on the /storage/stats read path.
454
+ */
455
+ async computeBucketStats() {
456
+ const [publicObjects, cacheObjects] = await Promise.all([
457
+ this.listAllParallel("public/"),
458
+ this.s3Client.listObjects("cache/"),
459
+ ]);
460
+ const storage = { size: 0, fileCount: 0 };
461
+ for (const obj of publicObjects) {
462
+ if (obj.key.endsWith("/"))
463
+ continue; // folder markers
464
+ storage.size += obj.size ?? 0;
465
+ storage.fileCount += 1;
466
+ }
467
+ const cache = { size: 0, fileCount: 0 };
468
+ for (const obj of cacheObjects) {
469
+ cache.size += obj.size ?? 0;
470
+ cache.fileCount += 1;
471
+ }
472
+ return { storage, cache };
473
+ }
474
+ /**
475
+ * Deletes all cached transformations from cloud storage and clears the in-memory cache
476
+ */
477
+ async clearAllCache() {
478
+ const cacheObjects = await this.s3Client.listObjects("cache/");
479
+ const deletedCount = cacheObjects.length === 0
480
+ ? 0
481
+ : await this.s3Client.deleteObjects(cacheObjects.map((obj) => obj.key));
482
+ if (cacheObjects.length > 0) {
483
+ adjustBucketStats(this, "cache", {
484
+ size: -cacheObjects.reduce((sum, obj) => sum + (obj.size ?? 0), 0),
485
+ fileCount: -cacheObjects.length,
486
+ });
487
+ }
488
+ this.cache.clear();
489
+ return deletedCount;
490
+ }
491
+ /**
492
+ * Invalidates all cache entries for a given original path
493
+ * This clears the in-memory cache for both the original file and all its transformations
494
+ */
495
+ invalidateAllCacheEntries(originalPath) {
496
+ // Clear the original file cache
497
+ this.cache.delete(`original:${originalPath}`);
498
+ // Clear all transformation caches that might exist
499
+ // We need to iterate through all cache keys and remove those related to this original path
500
+ const allKeys = this.cache.getAllKeys();
501
+ let deletedCount = 0;
502
+ for (const key of allKeys) {
503
+ // Keys for transformations contain the original path in their storage key
504
+ // Format: exists:cache/${originalPath}-${hash}.ext
505
+ if (key.includes(originalPath) ||
506
+ key.startsWith(`exists:cache/${originalPath}`)) {
507
+ this.cache.delete(key);
508
+ deletedCount++;
509
+ }
510
+ }
511
+ logger.debug({ originalPath, deletedCount }, "Invalidated cache entries for original path");
512
+ }
513
+ }
514
+ //# sourceMappingURL=cloud-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-storage.js","sourceRoot":"","sources":["../../../src/utils/storage/cloud-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { StorageConfig, StorageClientOptions } from './types';
2
+ import { CloudStorage } from './cloud-storage';
3
+ /**
4
+ * Pure factory: builds a storage client from an explicit config, with no
5
+ * knowledge of where that config came from (env vars, a database row, a
6
+ * per-tenant resolver, ...). Callers own resolving the config.
7
+ */
8
+ export declare function createStorageClient(config: StorageConfig, clientOptions?: StorageClientOptions): CloudStorage | null;
9
+ export declare const createOptimizedStorageClient: typeof createStorageClient;
10
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,aAAa,CAAC,EAAE,oBAAoB,GACnC,YAAY,GAAG,IAAI,CAOrB;AAGD,eAAO,MAAM,4BAA4B,4BAAsB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { CloudStorage } from './cloud-storage.js';
2
+ import logger from '../logger.js';
3
+ /**
4
+ * Pure factory: builds a storage client from an explicit config, with no
5
+ * knowledge of where that config came from (env vars, a database row, a
6
+ * per-tenant resolver, ...). Callers own resolving the config.
7
+ */
8
+ export function createStorageClient(config, clientOptions) {
9
+ if (!config.accessKeyId || !config.secretAccessKey || !config.bucketName) {
10
+ logger.warn('Storage configuration incomplete. Cloud storage disabled.');
11
+ return null;
12
+ }
13
+ return new CloudStorage(config, clientOptions);
14
+ }
15
+ // Alias for compatibility
16
+ export const createOptimizedStorageClient = createStorageClient;
17
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/utils/storage/factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,MAAM,MAAM,WAAW,CAAC;AAE/B;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAqB,EACrB,aAAoC;IAEpC,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACzE,MAAM,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,YAAY,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AACjD,CAAC;AAED,0BAA0B;AAC1B,MAAM,CAAC,MAAM,4BAA4B,GAAG,mBAAmB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type { StorageConfig, CacheEntry } from './types';
2
+ export { CloudStorage } from './cloud-storage';
3
+ export { StorageCache } from './cache';
4
+ export { S3ClientWrapper } from './s3-client';
5
+ export { KeyGenerator } from './key-generator';
6
+ export { createStorageClient, createOptimizedStorageClient } from './factory';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,8 @@
1
+ // Main classes
2
+ export { CloudStorage } from './cloud-storage.js';
3
+ export { StorageCache } from './cache.js';
4
+ export { S3ClientWrapper } from './s3-client.js';
5
+ export { KeyGenerator } from './key-generator.js';
6
+ // Factory functions
7
+ export { createStorageClient, createOptimizedStorageClient } from './factory.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/storage/index.ts"],"names":[],"mappings":"AAGA,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,oBAAoB;AACpB,OAAO,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare class KeyGenerator {
2
+ /**
3
+ * Generates a unique key for the file based on path and parameters
4
+ */
5
+ static generateKey(originalPath: string, params: any): string;
6
+ /**
7
+ * Generates cache key for existence check
8
+ */
9
+ static generateCacheKey(originalPath: string, params?: any): string;
10
+ }
11
+ //# sourceMappingURL=key-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-generator.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/key-generator.ts"],"names":[],"mappings":"AAEA,qBAAa,YAAY;IACvB;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,MAAM;IAO7D;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,MAAM;CAOpE"}
@@ -0,0 +1,23 @@
1
+ import { createHash } from 'crypto';
2
+ export class KeyGenerator {
3
+ /**
4
+ * Generates a unique key for the file based on path and parameters
5
+ */
6
+ static generateKey(originalPath, params) {
7
+ const paramsString = JSON.stringify(params);
8
+ const hash = createHash('md5').update(originalPath + paramsString).digest('hex');
9
+ const ext = originalPath.split('.').pop();
10
+ return `cache/${hash}.${ext}`;
11
+ }
12
+ /**
13
+ * Generates cache key for existence check
14
+ */
15
+ static generateCacheKey(originalPath, params) {
16
+ if (params) {
17
+ const key = this.generateKey(originalPath, params);
18
+ return `exists:${key}`;
19
+ }
20
+ return `original:${originalPath}`;
21
+ }
22
+ }
23
+ //# sourceMappingURL=key-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-generator.js","sourceRoot":"","sources":["../../../src/utils/storage/key-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,MAAM,OAAO,YAAY;IACvB;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,YAAoB,EAAE,MAAW;QAClD,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjF,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC1C,OAAO,SAAS,IAAI,IAAI,GAAG,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,YAAoB,EAAE,MAAY;QACxD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YACnD,OAAO,UAAU,GAAG,EAAE,CAAC;QACzB,CAAC;QACD,OAAO,YAAY,YAAY,EAAE,CAAC;IACpC,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ type ListedObject = {
2
+ key: string;
3
+ size?: number;
4
+ lastModified?: Date;
5
+ };
6
+ /**
7
+ * Returns the cached full bucket listing, fetching it at most once per TTL.
8
+ * The promise itself is cached so concurrent callers (e.g. GET /storage and
9
+ * GET /storage/stats firing together on dashboard load) share one S3 fan-out.
10
+ */
11
+ export declare function getCachedFullListing(fetcher: () => Promise<ListedObject[]>): Promise<ListedObject[]>;
12
+ export declare function invalidateListingCache(): void;
13
+ export {};
14
+ //# sourceMappingURL=listing-cache.d.ts.map