@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,320 @@
1
+ import { randomUUID } from "crypto";
2
+ import logger, { serializeError } from "../logger.js";
3
+ /**
4
+ * Normalize params to a consistent JSON string. Sorts keys alphabetically so
5
+ * the same params always produce the same string regardless of key order.
6
+ */
7
+ function normalizeParamsJson(params) {
8
+ if (!params || typeof params !== "object") {
9
+ return JSON.stringify(params);
10
+ }
11
+ const sortedKeys = Object.keys(params).sort();
12
+ const normalized = {};
13
+ for (const key of sortedKeys) {
14
+ normalized[key] = params[key];
15
+ }
16
+ return JSON.stringify(normalized);
17
+ }
18
+ /**
19
+ * SQLite-backed VideoJobStore, used by the self-hosted app. Takes the
20
+ * database instance as a constructor argument rather than importing a
21
+ * global, so callers control which database (and which schema/migrations)
22
+ * it operates against.
23
+ */
24
+ export class SqliteVideoJobStore {
25
+ db;
26
+ constructor(db) {
27
+ this.db = db;
28
+ }
29
+ createJob(filePath, params, cachePath, priority = 2) {
30
+ const jobId = randomUUID();
31
+ const paramsJson = normalizeParamsJson(params);
32
+ const now = Date.now();
33
+ try {
34
+ // Check if a job with the same file_path and params already exists
35
+ const existingJob = this.db
36
+ .prepare("SELECT id, status FROM video_jobs WHERE file_path = ? AND params_json = ? AND status IN ('pending', 'processing')")
37
+ .get(filePath, paramsJson);
38
+ if (existingJob) {
39
+ logger.debug({
40
+ existingJobId: existingJob.id,
41
+ status: existingJob.status,
42
+ filePath,
43
+ }, "Job already exists, returning existing job ID");
44
+ return existingJob.id;
45
+ }
46
+ // Create new job
47
+ this.db
48
+ .prepare(`INSERT INTO video_jobs (
49
+ id, file_path, params_json, cache_path, status, priority,
50
+ progress, retry_count, max_retries, created_at
51
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
52
+ .run(jobId, filePath, paramsJson, cachePath, "pending", priority, 0, 0, 3, now);
53
+ logger.info({ jobId, filePath, priority }, "Created new video job");
54
+ return jobId;
55
+ }
56
+ catch (error) {
57
+ logger.error({ error: serializeError(error), filePath }, "Failed to create job");
58
+ throw error;
59
+ }
60
+ }
61
+ getNextPendingJob() {
62
+ try {
63
+ const getAndUpdate = this.db.transaction(() => {
64
+ const job = this.db
65
+ .prepare(`SELECT * FROM video_jobs
66
+ WHERE status = 'pending'
67
+ ORDER BY priority ASC, created_at ASC
68
+ LIMIT 1`)
69
+ .get();
70
+ if (!job) {
71
+ return null;
72
+ }
73
+ const now = Date.now();
74
+ this.db
75
+ .prepare("UPDATE video_jobs SET status = 'processing', started_at = ? WHERE id = ?")
76
+ .run(now, job.id);
77
+ return { ...job, status: "processing", started_at: now };
78
+ });
79
+ const job = getAndUpdate();
80
+ if (job) {
81
+ logger.debug({ jobId: job.id, filePath: job.file_path }, "Retrieved next pending job");
82
+ }
83
+ return job;
84
+ }
85
+ catch (error) {
86
+ logger.error({ error: serializeError(error) }, "Failed to get next pending job");
87
+ return null;
88
+ }
89
+ }
90
+ updateJobStatus(jobId, status, progress, error) {
91
+ try {
92
+ const updates = ["status = ?"];
93
+ const values = [status];
94
+ if (progress !== undefined) {
95
+ updates.push("progress = ?");
96
+ values.push(progress);
97
+ }
98
+ if (error !== undefined) {
99
+ updates.push("error = ?");
100
+ values.push(error);
101
+ }
102
+ if (status === "completed" ||
103
+ status === "error" ||
104
+ status === "cancelled") {
105
+ updates.push("completed_at = ?");
106
+ values.push(Date.now());
107
+ }
108
+ values.push(jobId);
109
+ const query = `UPDATE video_jobs SET ${updates.join(", ")} WHERE id = ?`;
110
+ this.db.prepare(query).run(...values);
111
+ logger.debug({ jobId, status, progress }, "Updated job status");
112
+ }
113
+ catch (error) {
114
+ logger.error({ error: serializeError(error), jobId, status }, "Failed to update job status");
115
+ throw error;
116
+ }
117
+ }
118
+ getJobByFileAndParams(filePath, params) {
119
+ try {
120
+ const paramsJson = normalizeParamsJson(params);
121
+ const job = this.db
122
+ .prepare("SELECT * FROM video_jobs WHERE file_path = ? AND params_json = ? ORDER BY created_at DESC LIMIT 1")
123
+ .get(filePath, paramsJson);
124
+ return job || null;
125
+ }
126
+ catch (error) {
127
+ logger.error({ error: serializeError(error), filePath }, "Failed to get job by file and params");
128
+ return null;
129
+ }
130
+ }
131
+ getJobById(jobId) {
132
+ try {
133
+ const job = this.db
134
+ .prepare("SELECT * FROM video_jobs WHERE id = ?")
135
+ .get(jobId);
136
+ return job || null;
137
+ }
138
+ catch (error) {
139
+ logger.error({ error: serializeError(error), jobId }, "Failed to get job by ID");
140
+ return null;
141
+ }
142
+ }
143
+ getJobStats() {
144
+ try {
145
+ const stats = this.db
146
+ .prepare(`SELECT
147
+ COUNT(*) as total,
148
+ SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending,
149
+ SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END) as processing,
150
+ SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
151
+ SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) as error
152
+ FROM video_jobs`)
153
+ .get();
154
+ return stats;
155
+ }
156
+ catch (error) {
157
+ logger.error({ error: serializeError(error) }, "Failed to get job stats");
158
+ return { total: 0, pending: 0, processing: 0, completed: 0, error: 0 };
159
+ }
160
+ }
161
+ getRecentJobs(limit = 50, offset = 0) {
162
+ try {
163
+ return this.db
164
+ .prepare("SELECT * FROM video_jobs ORDER BY created_at DESC LIMIT ? OFFSET ?")
165
+ .all(limit, offset);
166
+ }
167
+ catch (error) {
168
+ logger.error({ error: serializeError(error), limit, offset }, "Failed to get recent jobs");
169
+ return [];
170
+ }
171
+ }
172
+ getJobsByStatus(status, limit = 50) {
173
+ try {
174
+ return this.db
175
+ .prepare("SELECT * FROM video_jobs WHERE status = ? ORDER BY created_at DESC LIMIT ?")
176
+ .all(status, limit);
177
+ }
178
+ catch (error) {
179
+ logger.error({ error: serializeError(error), status, limit }, "Failed to get jobs by status");
180
+ return [];
181
+ }
182
+ }
183
+ countProcessingJobs() {
184
+ try {
185
+ const result = this.db
186
+ .prepare("SELECT COUNT(*) as count FROM video_jobs WHERE status = 'processing'")
187
+ .get();
188
+ return result.count;
189
+ }
190
+ catch (error) {
191
+ logger.error({ error: serializeError(error) }, "Failed to count processing jobs");
192
+ return 0;
193
+ }
194
+ }
195
+ cleanupOldJobs(olderThanHours = 24) {
196
+ try {
197
+ const cutoffTime = Date.now() - olderThanHours * 60 * 60 * 1000;
198
+ const result = this.db
199
+ .prepare(`DELETE FROM video_jobs
200
+ WHERE status IN ('completed', 'error', 'cancelled')
201
+ AND completed_at < ?`)
202
+ .run(cutoffTime);
203
+ if (result.changes > 0) {
204
+ logger.info({ deletedCount: result.changes, olderThanHours }, "Cleaned up old jobs");
205
+ }
206
+ return result.changes;
207
+ }
208
+ catch (error) {
209
+ logger.error({ error: serializeError(error), olderThanHours }, "Failed to cleanup old jobs");
210
+ return 0;
211
+ }
212
+ }
213
+ retryFailedJob(jobId) {
214
+ try {
215
+ const job = this.getJobById(jobId);
216
+ if (!job) {
217
+ logger.warn({ jobId }, "Cannot retry: job not found");
218
+ return false;
219
+ }
220
+ if (job.status !== "error") {
221
+ logger.warn({ jobId, status: job.status }, "Cannot retry: job is not in error state");
222
+ return false;
223
+ }
224
+ if (job.retry_count >= job.max_retries) {
225
+ logger.warn({ jobId, retry_count: job.retry_count }, "Cannot retry: max retries reached");
226
+ return false;
227
+ }
228
+ this.db
229
+ .prepare(`UPDATE video_jobs
230
+ SET status = 'pending',
231
+ retry_count = retry_count + 1,
232
+ error = NULL,
233
+ started_at = NULL,
234
+ completed_at = NULL
235
+ WHERE id = ?`)
236
+ .run(jobId);
237
+ logger.info({ jobId, retry_count: job.retry_count + 1 }, "Job scheduled for retry");
238
+ return true;
239
+ }
240
+ catch (error) {
241
+ logger.error({ error: serializeError(error), jobId }, "Failed to retry job");
242
+ return false;
243
+ }
244
+ }
245
+ cancelJob(jobId) {
246
+ try {
247
+ const job = this.getJobById(jobId);
248
+ if (!job) {
249
+ logger.warn({ jobId }, "Cannot cancel: job not found");
250
+ return false;
251
+ }
252
+ if (job.status !== "pending") {
253
+ logger.warn({ jobId, status: job.status }, "Cannot cancel: job is not pending");
254
+ return false;
255
+ }
256
+ this.db
257
+ .prepare("UPDATE video_jobs SET status = 'cancelled', completed_at = ? WHERE id = ?")
258
+ .run(Date.now(), jobId);
259
+ logger.info({ jobId }, "Job cancelled");
260
+ return true;
261
+ }
262
+ catch (error) {
263
+ logger.error({ error: serializeError(error), jobId }, "Failed to cancel job");
264
+ return false;
265
+ }
266
+ }
267
+ deleteJob(jobId) {
268
+ try {
269
+ const result = this.db
270
+ .prepare("DELETE FROM video_jobs WHERE id = ?")
271
+ .run(jobId);
272
+ if (result.changes > 0) {
273
+ logger.info({ jobId }, "Job deleted");
274
+ return true;
275
+ }
276
+ logger.warn({ jobId }, "Job not found for deletion");
277
+ return false;
278
+ }
279
+ catch (error) {
280
+ logger.error({ error: serializeError(error), jobId }, "Failed to delete job");
281
+ return false;
282
+ }
283
+ }
284
+ resetOrphanedProcessingJobs() {
285
+ try {
286
+ const result = this.db
287
+ .prepare(`UPDATE video_jobs
288
+ SET status = 'pending', started_at = NULL
289
+ WHERE status = 'processing'`)
290
+ .run();
291
+ if (result.changes > 0) {
292
+ logger.warn({ resetCount: result.changes }, "Reset orphaned processing jobs to pending");
293
+ }
294
+ return result.changes;
295
+ }
296
+ catch (error) {
297
+ logger.error({ error: serializeError(error) }, "Failed to reset orphaned processing jobs");
298
+ return 0;
299
+ }
300
+ }
301
+ deleteJobsByFilePath(filePath) {
302
+ try {
303
+ const result = this.db
304
+ .prepare("DELETE FROM video_jobs WHERE file_path = ?")
305
+ .run(filePath);
306
+ if (result.changes > 0) {
307
+ logger.info({ filePath, deletedCount: result.changes }, "Deleted jobs for file path");
308
+ }
309
+ else {
310
+ logger.debug({ filePath }, "No jobs found for file path");
311
+ }
312
+ return result.changes;
313
+ }
314
+ catch (error) {
315
+ logger.error({ error: serializeError(error), filePath }, "Failed to delete jobs by file path");
316
+ return 0;
317
+ }
318
+ }
319
+ }
320
+ //# sourceMappingURL=sqlite-video-job-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-video-job-store.js","sourceRoot":"","sources":["../../../src/utils/video/sqlite-video-job-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { TransformFunction } from './types';
2
+ /**
3
+ * Apply thumbnail extraction transformation
4
+ * Extracts a single frame from the video at the specified time
5
+ */
6
+ export declare const applyThumbnailExtraction: TransformFunction;
7
+ //# sourceMappingURL=thumbnail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thumbnail.d.ts","sourceRoot":"","sources":["../../../src/utils/video/thumbnail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBAsBtC,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Apply thumbnail extraction transformation
3
+ * Extracts a single frame from the video at the specified time
4
+ */
5
+ export const applyThumbnailExtraction = (command, context) => {
6
+ if (!context.isThumbnail) {
7
+ return command;
8
+ }
9
+ // Determine the time to extract the thumbnail from
10
+ // Priority: thumbnailTime > startOffset > 0
11
+ const time = context.params.thumbnailTime ??
12
+ context.params.startOffset ??
13
+ 0;
14
+ // Seek to the specified time and extract a single frame.
15
+ // Do NOT force "-f image2" here: ffmpeg infers the correct muxer from the
16
+ // output file extension (e.g. .webp → webp muxer, .png → png muxer).
17
+ // Forcing image2 would override that and break webp/avif/png output.
18
+ return command
19
+ .seekInput(time)
20
+ .frames(1);
21
+ };
22
+ //# sourceMappingURL=thumbnail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thumbnail.js","sourceRoot":"","sources":["../../../src/utils/video/thumbnail.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAsB,CACzD,OAAO,EACP,OAAO,EACP,EAAE;IACF,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,mDAAmD;IACnD,4CAA4C;IAC5C,MAAM,IAAI,GACR,OAAO,CAAC,MAAM,CAAC,aAAa;QAC5B,OAAO,CAAC,MAAM,CAAC,WAAW;QAC1B,CAAC,CAAC;IAEJ,yDAAyD;IACzD,0EAA0E;IAC1E,qEAAqE;IACrE,qEAAqE;IACrE,OAAO,OAAO;SACX,SAAS,CAAC,IAAI,CAAC;SACf,MAAM,CAAC,CAAC,CAAC,CAAC;AACf,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { TransformFunction } from './types';
2
+ /**
3
+ * Apply temporal trimming transformation
4
+ * Cuts the video based on startOffset and endOffset parameters
5
+ */
6
+ export declare const applyTrimming: TransformFunction;
7
+ //# sourceMappingURL=trim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim.d.ts","sourceRoot":"","sources":["../../../src/utils/video/trim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,iBAqC3B,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Apply temporal trimming transformation
3
+ * Cuts the video based on startOffset and endOffset parameters
4
+ */
5
+ export const applyTrimming = (command, context) => {
6
+ // Skip trimming for thumbnail extraction
7
+ if (context.isThumbnail) {
8
+ return command;
9
+ }
10
+ const { startOffset, endOffset } = context.params;
11
+ // Apply start offset if specified
12
+ if (startOffset !== undefined && startOffset >= 0) {
13
+ command = command.seekInput(startOffset);
14
+ }
15
+ // Calculate and apply duration if end offset is specified
16
+ let durationSeconds;
17
+ if (endOffset !== undefined && endOffset >= 0) {
18
+ if (startOffset !== undefined && startOffset >= 0) {
19
+ // Duration = endOffset - startOffset (trim between start and end)
20
+ const diff = endOffset - startOffset;
21
+ if (diff > 0) {
22
+ durationSeconds = diff;
23
+ }
24
+ }
25
+ else {
26
+ // Only endOffset specified → interpret as "play first endOffset seconds"
27
+ durationSeconds = endOffset;
28
+ }
29
+ }
30
+ // Apply duration if calculated
31
+ if (durationSeconds !== undefined && durationSeconds > 0) {
32
+ command = command.duration(durationSeconds);
33
+ }
34
+ return command;
35
+ };
36
+ //# sourceMappingURL=trim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim.js","sourceRoot":"","sources":["../../../src/utils/video/trim.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAsB,CAC9C,OAAO,EACP,OAAO,EACP,EAAE;IACF,yCAAyC;IACzC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAElD,kCAAkC;IAClC,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QAClD,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,0DAA0D;IAC1D,IAAI,eAAmC,CAAC;IACxC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAC9C,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;YAClD,kEAAkE;YAClE,MAAM,IAAI,GAAG,SAAS,GAAG,WAAW,CAAC;YACrC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;gBACb,eAAe,GAAG,IAAI,CAAC;YACzB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,yEAAyE;YACzE,eAAe,GAAG,SAAS,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,IAAI,eAAe,KAAK,SAAS,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { FfmpegCommand } from 'fluent-ffmpeg';
2
+ import type { VideoTransformParams } from '../../types';
3
+ /**
4
+ * Context object containing all information needed for video transformation
5
+ */
6
+ export interface VideoContext {
7
+ inputPath: string;
8
+ outputPath: string;
9
+ tmpDir: string;
10
+ params: VideoTransformParams;
11
+ isImageOutput: boolean;
12
+ isThumbnail: boolean;
13
+ }
14
+ /**
15
+ * Transform function type that takes an ffmpeg command and context,
16
+ * applies a transformation, and returns the modified command
17
+ */
18
+ export type TransformFunction = (command: FfmpegCommand, context: VideoContext) => FfmpegCommand;
19
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/video/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC9B,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,YAAY,KAClB,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/video/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Video information extracted from ffprobe
3
+ */
4
+ export interface VideoInfo {
5
+ width: number;
6
+ height: number;
7
+ duration: number;
8
+ bitrate: number;
9
+ codec: string;
10
+ size: number;
11
+ }
12
+ /**
13
+ * Get video metadata using ffprobe
14
+ * Useful for detecting resolution before processing
15
+ */
16
+ export declare function getVideoInfo(filePath: string): Promise<VideoInfo>;
17
+ /**
18
+ * Check if video resolution is considered "large" (4K or higher)
19
+ */
20
+ export declare function isLargeResolution(info: VideoInfo): boolean;
21
+ /**
22
+ * Get human-readable resolution label
23
+ */
24
+ export declare function getResolutionLabel(info: VideoInfo): string;
25
+ //# sourceMappingURL=video-info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-info.d.ts","sourceRoot":"","sources":["../../../src/utils/video/video-info.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CA4BvE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAG1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAQ1D"}
@@ -0,0 +1,58 @@
1
+ import ffmpeg from 'fluent-ffmpeg';
2
+ /**
3
+ * Get video metadata using ffprobe
4
+ * Useful for detecting resolution before processing
5
+ */
6
+ export async function getVideoInfo(filePath) {
7
+ return new Promise((resolve, reject) => {
8
+ ffmpeg.ffprobe(filePath, (err, metadata) => {
9
+ if (err) {
10
+ reject(new Error(`Failed to read video metadata: ${err.message}`));
11
+ return;
12
+ }
13
+ const videoStream = metadata.streams.find(s => s.codec_type === 'video');
14
+ if (!videoStream) {
15
+ reject(new Error('No video stream found in file'));
16
+ return;
17
+ }
18
+ resolve({
19
+ width: videoStream.width || 0,
20
+ height: videoStream.height || 0,
21
+ duration: metadata.format.duration || 0,
22
+ bitrate: metadata.format.bit_rate
23
+ ? (typeof metadata.format.bit_rate === 'string'
24
+ ? parseInt(metadata.format.bit_rate)
25
+ : metadata.format.bit_rate)
26
+ : 0,
27
+ codec: videoStream.codec_name || 'unknown',
28
+ size: metadata.format.size || 0,
29
+ });
30
+ });
31
+ });
32
+ }
33
+ /**
34
+ * Check if video resolution is considered "large" (4K or higher)
35
+ */
36
+ export function isLargeResolution(info) {
37
+ // 4K is 3840x2160, we'll consider anything >= 3000 pixels wide as large
38
+ return info.width >= 3000 || info.height >= 2000;
39
+ }
40
+ /**
41
+ * Get human-readable resolution label
42
+ */
43
+ export function getResolutionLabel(info) {
44
+ if (info.width >= 7000)
45
+ return '8K';
46
+ if (info.width >= 5000)
47
+ return '5K';
48
+ if (info.width >= 3000)
49
+ return '4K';
50
+ if (info.width >= 2500)
51
+ return '2.5K';
52
+ if (info.width >= 1900)
53
+ return '1080p';
54
+ if (info.width >= 1200)
55
+ return '720p';
56
+ return `${info.width}x${info.height}`;
57
+ }
58
+ //# sourceMappingURL=video-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-info.js","sourceRoot":"","sources":["../../../src/utils/video/video-info.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,eAAe,CAAC;AAcnC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;YACzC,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACnE,OAAO;YACT,CAAC;YAED,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC;YACzE,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;gBACnD,OAAO;YACT,CAAC;YAED,OAAO,CAAC;gBACN,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC;gBAC7B,MAAM,EAAE,WAAW,CAAC,MAAM,IAAI,CAAC;gBAC/B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC;gBACvC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;oBAC/B,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ;wBAC3C,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;wBACpC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;oBAC/B,CAAC,CAAC,CAAC;gBACL,KAAK,EAAE,WAAW,CAAC,UAAU,IAAI,SAAS;gBAC1C,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;aAChC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAe;IAC/C,wEAAwE;IACxE,OAAO,IAAI,CAAC,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAe;IAChD,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;QAAE,OAAO,MAAM,CAAC;IACtC,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;QAAE,OAAO,MAAM,CAAC;IACtC,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { EventEmitter } from "events";
2
+ import type { CloudStorage } from "../storage/index";
3
+ import type { VideoJob, VideoJobStore } from "./queue-store";
4
+ export interface WorkerEvents {
5
+ "job:created": (job: VideoJob) => void;
6
+ "job:started": (job: VideoJob) => void;
7
+ "job:progress": (job: VideoJob, progress: number) => void;
8
+ "job:completed": (job: VideoJob) => void;
9
+ "job:error": (job: VideoJob, error: Error) => void;
10
+ }
11
+ /**
12
+ * Background worker for processing video jobs
13
+ */
14
+ export declare class VideoWorker extends EventEmitter {
15
+ private intervalId;
16
+ private maxConcurrent;
17
+ private pollInterval;
18
+ private storage;
19
+ private store;
20
+ private isAcquiring;
21
+ constructor(storage: CloudStorage | null, store: VideoJobStore);
22
+ /**
23
+ * Start the worker
24
+ */
25
+ start(): void;
26
+ /**
27
+ * Stop the worker
28
+ */
29
+ stop(): void;
30
+ /**
31
+ * Set maximum concurrent jobs
32
+ */
33
+ setMaxConcurrent(n: number): void;
34
+ /**
35
+ * Fill every free concurrency slot with pending jobs (runs on each poll tick)
36
+ */
37
+ fillAvailableSlots(): Promise<void>;
38
+ /**
39
+ * Process a single video job (runs concurrently with other jobs)
40
+ */
41
+ private processJob;
42
+ /**
43
+ * Get worker statistics
44
+ */
45
+ getStats(): {
46
+ maxConcurrent: number;
47
+ pollInterval: number;
48
+ isRunning: boolean;
49
+ processingCount: number;
50
+ };
51
+ }
52
+ //# sourceMappingURL=video-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-worker.d.ts","sourceRoot":"","sources":["../../../src/utils/video/video-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI7D,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,aAAa,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,eAAe,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACzC,WAAW,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,WAAW,CAAkB;gBAEzB,OAAO,EAAE,YAAY,GAAG,IAAI,EAAE,KAAK,EAAE,aAAa;IAQ9D;;OAEG;IACH,KAAK,IAAI,IAAI;IA2Cb;;OAEG;IACH,IAAI,IAAI,IAAI;IAQZ;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAKjC;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAiDzC;;OAEG;YACW,UAAU;IAgGxB;;OAEG;IACH,QAAQ;;;;;;CAQT"}