@bedolla/enrivision 0.1.4 → 0.1.6

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 (64) hide show
  1. package/README.md +31 -6
  2. package/dist/client/EnriProxyClient.d.ts +289 -244
  3. package/dist/client/EnriProxyClient.d.ts.map +1 -1
  4. package/dist/client/EnriProxyClient.js +841 -115
  5. package/dist/client/EnriProxyClient.js.map +1 -1
  6. package/dist/client/EnriProxyClientContract.d.ts +425 -0
  7. package/dist/client/EnriProxyClientContract.d.ts.map +1 -0
  8. package/dist/client/EnriProxyClientContract.js +87 -0
  9. package/dist/client/EnriProxyClientContract.js.map +1 -0
  10. package/dist/index.js +23 -12
  11. package/dist/index.js.map +1 -1
  12. package/dist/package-info.d.ts +28 -0
  13. package/dist/package-info.d.ts.map +1 -1
  14. package/dist/package-info.js +28 -0
  15. package/dist/package-info.js.map +1 -1
  16. package/dist/server/EnriVisionServer.d.ts +186 -0
  17. package/dist/server/EnriVisionServer.d.ts.map +1 -1
  18. package/dist/server/EnriVisionServer.js +780 -93
  19. package/dist/server/EnriVisionServer.js.map +1 -1
  20. package/dist/shared/codepointTruncation.d.ts +61 -0
  21. package/dist/shared/codepointTruncation.d.ts.map +1 -0
  22. package/dist/shared/codepointTruncation.js +73 -0
  23. package/dist/shared/codepointTruncation.js.map +1 -0
  24. package/dist/shared/mediaUrlFetcher.d.ts +247 -9
  25. package/dist/shared/mediaUrlFetcher.d.ts.map +1 -1
  26. package/dist/shared/mediaUrlFetcher.js +712 -53
  27. package/dist/shared/mediaUrlFetcher.js.map +1 -1
  28. package/dist/shared/tar.d.ts +82 -2
  29. package/dist/shared/tar.d.ts.map +1 -1
  30. package/dist/shared/tar.js +106 -43
  31. package/dist/shared/tar.js.map +1 -1
  32. package/dist/shared/validation.d.ts +96 -2
  33. package/dist/shared/validation.d.ts.map +1 -1
  34. package/dist/shared/validation.js +169 -10
  35. package/dist/shared/validation.js.map +1 -1
  36. package/dist/tools/AnalyzeMediaContract.d.ts +457 -0
  37. package/dist/tools/AnalyzeMediaContract.d.ts.map +1 -0
  38. package/dist/tools/AnalyzeMediaContract.js +161 -0
  39. package/dist/tools/AnalyzeMediaContract.js.map +1 -0
  40. package/dist/tools/AnalyzeMediaExtractionSanitizer.d.ts +35 -0
  41. package/dist/tools/AnalyzeMediaExtractionSanitizer.d.ts.map +1 -0
  42. package/dist/tools/AnalyzeMediaExtractionSanitizer.js +214 -0
  43. package/dist/tools/AnalyzeMediaExtractionSanitizer.js.map +1 -0
  44. package/dist/tools/AnalyzeMediaInputResolver.d.ts +250 -0
  45. package/dist/tools/AnalyzeMediaInputResolver.d.ts.map +1 -0
  46. package/dist/tools/AnalyzeMediaInputResolver.js +430 -0
  47. package/dist/tools/AnalyzeMediaInputResolver.js.map +1 -0
  48. package/dist/tools/AnalyzeMediaParamParser.d.ts +299 -0
  49. package/dist/tools/AnalyzeMediaParamParser.d.ts.map +1 -0
  50. package/dist/tools/AnalyzeMediaParamParser.js +824 -0
  51. package/dist/tools/AnalyzeMediaParamParser.js.map +1 -0
  52. package/dist/tools/AnalyzeMediaResumableUploader.d.ts +244 -0
  53. package/dist/tools/AnalyzeMediaResumableUploader.d.ts.map +1 -0
  54. package/dist/tools/AnalyzeMediaResumableUploader.js +549 -0
  55. package/dist/tools/AnalyzeMediaResumableUploader.js.map +1 -0
  56. package/dist/tools/AnalyzeMediaTarPackager.d.ts +42 -0
  57. package/dist/tools/AnalyzeMediaTarPackager.d.ts.map +1 -0
  58. package/dist/tools/AnalyzeMediaTarPackager.js +245 -0
  59. package/dist/tools/AnalyzeMediaTarPackager.js.map +1 -0
  60. package/dist/tools/AnalyzeMediaTool.d.ts +155 -294
  61. package/dist/tools/AnalyzeMediaTool.d.ts.map +1 -1
  62. package/dist/tools/AnalyzeMediaTool.js +600 -457
  63. package/dist/tools/AnalyzeMediaTool.js.map +1 -1
  64. package/package.json +2 -1
@@ -0,0 +1,245 @@
1
+ /**
2
+ * ANALYZE MEDIA TAR PACKAGER
3
+ *
4
+ * Packages multiple local images into a single EnriVision media-set tar
5
+ * archive and uploads it through a resumable EnriProxy session. A single
6
+ * archive avoids creating many concurrent upload sessions (capped per API
7
+ * key) and enables server-side batching plus reduce for large screenshot
8
+ * sets.
9
+ *
10
+ * @module tools/AnalyzeMediaTarPackager
11
+ */
12
+ import { extname } from "node:path";
13
+ import { stat } from "node:fs/promises";
14
+ import { computeTarSizeBytes, TarStream } from "../shared/tar.js";
15
+ import { ANALYZE_MEDIA_LIMITS } from "./AnalyzeMediaContract.js";
16
+ import { assertNoForwardGap, describeFileIdentity, effectiveChunkSizeBytes, MAX_CONSECUTIVE_NO_ADVANCE, resolveChunkTimeoutMs, resolveUploadDeadlineMs, shouldRecheckIdentity, UploadProgressLogger, withResumableRetry, } from "./AnalyzeMediaResumableUploader.js";
17
+ /**
18
+ * Content type for EnriVision media-set archives (tar, no compression).
19
+ */
20
+ const ENRIVISION_MEDIA_SET_TAR_CONTENT_TYPE = "application/vnd.enrivision.media-set+tar";
21
+ /**
22
+ * Fixed manifest entry name inside EnriVision media-set tar archives.
23
+ */
24
+ const ENRIVISION_MEDIA_SET_TAR_MANIFEST_NAME = "manifest.json";
25
+ /**
26
+ * Packages and uploads multi-image sets as one media-set tar archive.
27
+ */
28
+ export class AnalyzeMediaTarPackager {
29
+ /**
30
+ * Chunk uploader used for the tar byte stream.
31
+ */
32
+ uploader;
33
+ /**
34
+ * Creates a new {@link AnalyzeMediaTarPackager}.
35
+ *
36
+ * @param uploader - Resumable chunk uploader.
37
+ */
38
+ constructor(uploader) {
39
+ this.uploader = uploader;
40
+ }
41
+ /**
42
+ * Uploads multiple local images as a single media-set tar archive.
43
+ *
44
+ * @param client - EnriProxy client.
45
+ * @param inputs - Resolved media inputs (URLs already materialized).
46
+ * @param timeoutMs - Request timeout per HTTP request.
47
+ * @param clientTraceId - Client trace id for correlation.
48
+ * @param signal - Optional cancellation signal.
49
+ * @returns Upload id for the created tar session.
50
+ * @throws Error with an Spanish-first bilingual message when inputs are not images or the upload stalls.
51
+ */
52
+ async uploadImageSetAsMediaSetTar(client, inputs, timeoutMs, clientTraceId, signal) {
53
+ if (inputs.length < 2) {
54
+ throw new Error("Se requieren al menos 2 archivos de imagen para el tar de conjunto. / At least 2 image files are required for the set tar.");
55
+ }
56
+ // Snapshot full file identity at stage time (ino:size:mtime:birthtime:nlink):
57
+ // a concurrent writer that truncates, grows, or same-size-replaces a file
58
+ // mid-upload must fail loudly instead of shipping zero-filled entries.
59
+ const stagedIdentities = new Map();
60
+ for (const input of inputs) {
61
+ const current = await stat(input.localPath);
62
+ if (current.size !== input.sizeBytes) {
63
+ throw new Error(`El archivo cambió antes de la subida (${input.localPath}); reintente la llamada. / File changed before upload (${input.localPath}); retry the call.`);
64
+ }
65
+ // Same-size swaps ship wrong bytes silently without this gate
66
+ // (mirrors the single-file upload identity check).
67
+ if (input.stagedIdentity !== undefined && describeFileIdentity(current) !== input.stagedIdentity) {
68
+ throw new Error(`El archivo cambió antes de la subida (${input.localPath}); reintente la llamada. / File changed before upload (${input.localPath}); retry the call.`);
69
+ }
70
+ stagedIdentities.set(input.localPath, describeFileIdentity(current));
71
+ }
72
+ const files = inputs.map((input, position) => {
73
+ if (!input.contentType.toLowerCase().startsWith("image/")) {
74
+ throw new Error(`paths debe contener sólo archivos de imagen. No es imagen: ${input.localPath} (${input.contentType}) / paths must contain only image files. Not an image: ${input.localPath} (${input.contentType}).`);
75
+ }
76
+ const extRaw = extname(input.filename).toLowerCase();
77
+ const ext = extRaw && /^[a-z0-9.]+$/.test(extRaw) ? extRaw : ".img";
78
+ return {
79
+ index: position + 1,
80
+ filename: input.filename,
81
+ path: input.localPath,
82
+ sizeBytes: input.sizeBytes,
83
+ contentType: input.contentType,
84
+ entryName: `${String(position + 1).padStart(6, "0")}${ext}`,
85
+ };
86
+ });
87
+ const manifest = {
88
+ type: "enrivision_media_set",
89
+ version: 1,
90
+ media_type: "image_set",
91
+ items: files.map((file) => ({
92
+ index: file.index,
93
+ name: file.entryName,
94
+ filename: file.filename,
95
+ content_type: file.contentType,
96
+ size_bytes: file.sizeBytes,
97
+ })),
98
+ };
99
+ const manifestBuffer = Buffer.from(JSON.stringify(manifest), "utf8");
100
+ const nowSeconds = Math.floor(Date.now() / 1000);
101
+ const entries = [
102
+ {
103
+ name: ENRIVISION_MEDIA_SET_TAR_MANIFEST_NAME,
104
+ source: { type: "buffer", buffer: manifestBuffer },
105
+ mtimeSeconds: nowSeconds,
106
+ },
107
+ ...files.map((file) => ({
108
+ name: file.entryName,
109
+ source: {
110
+ type: "file",
111
+ path: file.path,
112
+ sizeBytes: file.sizeBytes,
113
+ expectedIdentity: stagedIdentities.get(file.path),
114
+ },
115
+ mtimeSeconds: nowSeconds,
116
+ })),
117
+ ];
118
+ const tarSizeBytes = computeTarSizeBytes(entries);
119
+ if (tarSizeBytes > ANALYZE_MEDIA_LIMITS.maxUploadBytes) {
120
+ throw new Error(`El conjunto de imágenes excede el límite de subida de 4 GiB (${String(tarSizeBytes)} bytes); divida el conjunto en varias llamadas. / Image set exceeds the 4 GiB upload limit (${String(tarSizeBytes)} bytes); split the set into several calls.`);
121
+ }
122
+ const tar = new TarStream(entries, { describeIdentity: describeFileIdentity });
123
+ if (tar.getSizeBytes() !== tarSizeBytes) {
124
+ throw new Error("Error interno: discrepancia en el tamaño del tar. / Internal error: tar size mismatch.");
125
+ }
126
+ const session = await withResumableRetry(() => client.createUploadSession({
127
+ filename: "enrivision-image-set.tar",
128
+ sizeBytes: tarSizeBytes,
129
+ contentType: ENRIVISION_MEDIA_SET_TAR_CONTENT_TYPE,
130
+ clientTraceId,
131
+ signal,
132
+ }), signal);
133
+ const serverMaxBytes = typeof session.max_file_size_bytes === "number"
134
+ && Number.isFinite(session.max_file_size_bytes)
135
+ && session.max_file_size_bytes > 0
136
+ ? Math.floor(session.max_file_size_bytes)
137
+ : null;
138
+ if (serverMaxBytes !== null && tarSizeBytes > serverMaxBytes) {
139
+ try {
140
+ await client.deleteUploadSession(session.upload_id, AbortSignal.timeout(15_000));
141
+ }
142
+ catch {
143
+ // Best-effort: the size error always wins.
144
+ }
145
+ throw new Error(`El conjunto excede el tamaño máximo del servidor (${String(serverMaxBytes)} bytes); divida el conjunto en varias llamadas. / Set exceeds the server maximum size (${String(serverMaxBytes)} bytes); split the set into several calls.`);
146
+ }
147
+ const chunkSize = effectiveChunkSizeBytes(session.chunk_size_bytes);
148
+ let offset = await withResumableRetry(() => client.getUploadOffset(session.upload_id, signal), signal);
149
+ if (!Number.isFinite(offset) || offset < 0 || offset > tarSizeBytes) {
150
+ throw new Error(`Offset del servidor inválido para la subida del tar: ${offset} / Invalid server offset for the tar upload: ${offset}.`);
151
+ }
152
+ const uploadStartedAt = Date.now();
153
+ const uploadDeadlineMs = resolveUploadDeadlineMs(tarSizeBytes);
154
+ let chunksSinceIdentityCheck = 0;
155
+ let lastIdentityCheckAt = 0;
156
+ // Consecutive outer iterations that uploaded bytes without advancing the
157
+ // server offset (2xx same-offset responses): the third one fails fast
158
+ // with the inconsistent-protocol error instead of spinning to the
159
+ // 20 min deadline (mirrors the single-file same-offset 409 guard).
160
+ let consecutiveNoAdvance = 0;
161
+ const progress = new UploadProgressLogger(tarSizeBytes);
162
+ while (offset < tarSizeBytes) {
163
+ if (signal?.aborted) {
164
+ throw new Error("La solicitud fue cancelada por el cliente. / Request cancelled by the client.");
165
+ }
166
+ if (Date.now() - uploadStartedAt > uploadDeadlineMs) {
167
+ try {
168
+ await client.deleteUploadSession(session.upload_id, AbortSignal.timeout(15_000));
169
+ }
170
+ catch {
171
+ // Best-effort: the deadline error always wins.
172
+ }
173
+ throw new Error(`La subida excedió el tiempo máximo (${String(Math.round(uploadDeadlineMs / 1000))} s para ${String(tarSizeBytes)} bytes); reintente con menos imágenes o una conexión más rápida. / Upload exceeded the maximum time (${String(Math.round(uploadDeadlineMs / 1000))} s for ${String(tarSizeBytes)} bytes); retry with fewer images or a faster connection.`);
174
+ }
175
+ // Same cadence as the single-file path (every 16 chunks or 5 s, mirrors
176
+ // EnriCode): the tar loop previously only had the 5 s timer, so fast
177
+ // links could stream 256 MiB unchecked between checks.
178
+ if (shouldRecheckIdentity(chunksSinceIdentityCheck, Date.now(), lastIdentityCheckAt)) {
179
+ for (const input of inputs) {
180
+ const current = await stat(input.localPath);
181
+ const expected = stagedIdentities.get(input.localPath);
182
+ if (typeof expected === "string" && describeFileIdentity(current) !== expected) {
183
+ try {
184
+ await client.deleteUploadSession(session.upload_id, AbortSignal.timeout(15_000));
185
+ }
186
+ catch {
187
+ // Best-effort: the identity error always wins.
188
+ }
189
+ throw new Error(`El archivo cambió mientras se subía (${input.localPath}); reintente la llamada con archivos estables. / File changed while uploading (${input.localPath}); retry the call with stable files.`);
190
+ }
191
+ }
192
+ chunksSinceIdentityCheck = 0;
193
+ lastIdentityCheckAt = Date.now();
194
+ }
195
+ let madeProgress = false;
196
+ // Breaking out of this loop on offset resync is safe: TarStream
197
+ // releases its file handle in a generator finally block.
198
+ for await (const chunk of tar.iterateChunks(offset, chunkSize)) {
199
+ if (chunk.length === 0) {
200
+ continue;
201
+ }
202
+ const expectedOffset = offset;
203
+ const nextOffset = await this.uploader.uploadChunkWithRetry(client, session.upload_id, expectedOffset, chunk, resolveChunkTimeoutMs(chunk.length, timeoutMs), signal);
204
+ // A forward jump skips bytes that were never sent (a hole in the
205
+ // tar): fail fast instead of resyncing past them.
206
+ assertNoForwardGap(nextOffset, expectedOffset, chunk.length);
207
+ offset = nextOffset;
208
+ madeProgress = true;
209
+ chunksSinceIdentityCheck += 1;
210
+ progress.report(offset);
211
+ // Offset resync: restart generation from the server-provided offset.
212
+ if (offset !== expectedOffset + chunk.length) {
213
+ if (offset === expectedOffset) {
214
+ consecutiveNoAdvance += 1;
215
+ if (consecutiveNoAdvance >= MAX_CONSECUTIVE_NO_ADVANCE) {
216
+ try {
217
+ await client.deleteUploadSession(session.upload_id, AbortSignal.timeout(15_000));
218
+ }
219
+ catch {
220
+ // Best-effort: the stuck-offset error always wins.
221
+ }
222
+ throw new Error(`El servidor rechazó el fragmento sin avanzar el offset (protocolo de subida inconsistente); reintente la llamada. / The server rejected the chunk without advancing the offset (inconsistent upload protocol); retry the call.`);
223
+ }
224
+ }
225
+ else {
226
+ consecutiveNoAdvance = 0;
227
+ }
228
+ break;
229
+ }
230
+ consecutiveNoAdvance = 0;
231
+ if (offset >= tarSizeBytes) {
232
+ break;
233
+ }
234
+ }
235
+ if (!madeProgress) {
236
+ throw new Error("Subida estancada: no hubo progreso al enviar los fragmentos del tar. / Stalled upload: no progress sending the tar chunks.");
237
+ }
238
+ }
239
+ if (offset !== tarSizeBytes) {
240
+ throw new Error(`Subida incompleta: se enviaron ${offset} de ${tarSizeBytes} bytes. / Incomplete upload: sent ${offset} of ${tarSizeBytes} bytes.`);
241
+ }
242
+ return session.upload_id;
243
+ }
244
+ }
245
+ //# sourceMappingURL=AnalyzeMediaTarPackager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalyzeMediaTarPackager.js","sourceRoot":"","sources":["../../src/tools/AnalyzeMediaTarPackager.ts"],"names":[],"mappings":"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"}