@bedolla/enrivision 0.1.5 → 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,214 @@
1
+ /**
2
+ * ANALYZE MEDIA EXTRACTION SANITIZER
3
+ *
4
+ * Strips routing-only internals from the EnriProxy extraction payload before
5
+ * it reaches the model. Only upload identifiers, provider-routing identities,
6
+ * and secret-bearing keys are removed: coverage metadata that EnriProxy
7
+ * intentionally returns (`detected_media_type`, `analysis_mode_*`,
8
+ * `multipass`, `models`, `strategy`, `warnings`, `frame_count`, `timeline`)
9
+ * is preserved so the model can report honest coverage (missing frames).
10
+ *
11
+ * Key matching is separator-insensitive (`-`, `_`, `.` stripped): hyphenated
12
+ * spellings such as `api-key` or `access-token` match like `api_key`.
13
+ *
14
+ * @module tools/AnalyzeMediaExtractionSanitizer
15
+ */
16
+ /**
17
+ * Internal-only extraction keys stripped at any depth (case-insensitive,
18
+ * separator-insensitive: matched against the separator-stripped form).
19
+ *
20
+ * @remarks
21
+ * Covers upload identifiers, provider-routing identities, secret-bearing
22
+ * token variants (`api_key`, `secret`, `refresh_token`, `access_token`,
23
+ * `auth_token`, `id_token`, bare `token`), and bare bearer material (`jwt`,
24
+ * `jwk` plus suffixed variants). Coverage and accounting keys such as
25
+ * `multipass`, `detected_media_type`, `analysis_mode_*`, `models`,
26
+ * `strategy`, `warnings`, `frame_count`, `timeline`, and the OpenAI usage
27
+ * block (`prompt_tokens`, `completion_tokens`, `total_tokens`, …) are
28
+ * explicitly preserved (see {@link PRESERVED_KEYS} and the accounting set).
29
+ */
30
+ const STRIPPED_KEY_PATTERN = /^(uploadids?.*|provider.*|apikeys?.*|secrets?.*|refreshtokens?.*|accesstokens?.*|authtokens?.*|idtokens?.*|jwts?.*|jwks?.*|tokens?)$/iu;
31
+ /**
32
+ * Internal routing identifiers that never reach the model.
33
+ *
34
+ * @remarks
35
+ * The anchored pattern above requires a literal `id` after `upload_`, so
36
+ * `upload_url` would survive it; session/trace ids are plausible server
37
+ * internals too. Listed explicitly (case-insensitive) instead.
38
+ */
39
+ const INTERNAL_KEYS = new Set([
40
+ "sessionid",
41
+ "clienttraceid",
42
+ "traceid",
43
+ "uploadurl",
44
+ "requestid",
45
+ ]);
46
+ /**
47
+ * Secret-material suffixes stripped at any depth (case-insensitive).
48
+ *
49
+ * @remarks
50
+ * The anchored pattern misses prefixed secrets (`client_secret`,
51
+ * `my_api_key`) and bearer/authorization material, all of which would
52
+ * otherwise reach the model. Matched as a suffix so `monkey`-style false
53
+ * positives cannot strip legitimate metadata.
54
+ */
55
+ const SECRET_SUFFIX_PATTERN = /(password|passwd|bearer|authorization|authentication|nonce|signature)$/iu;
56
+ /**
57
+ * Coverage/accounting keys that must survive sanitization even though an
58
+ * older broader pattern used to strip them.
59
+ */
60
+ const PRESERVED_KEYS = new Set([
61
+ "multipass",
62
+ "detected_media_type",
63
+ "analysis_mode",
64
+ "analysis_mode_requested",
65
+ "analysis_mode_used",
66
+ "models",
67
+ "model",
68
+ "strategy",
69
+ "warnings",
70
+ "frame_count",
71
+ "timeline",
72
+ ]);
73
+ /**
74
+ * Legitimate accounting/metadata keys that must survive sanitization even
75
+ * though they contain the substring `token`.
76
+ *
77
+ * @remarks
78
+ * Covers the standard OpenAI-compatible usage block (`prompt_tokens`,
79
+ * `completion_tokens`, `total_tokens`, `input_tokens`, `output_tokens`) plus
80
+ * reasoning/cache variants. Compared in separator-stripped form (see
81
+ * {@link normalizeSanitizerKey}) so hyphenated spellings (`prompt-tokens`)
82
+ * and vendor-prefixed variants (`response_input_tokens`) survive too.
83
+ */
84
+ const ACCOUNTING_KEYS = new Set([
85
+ "tokenusage",
86
+ "tokensused",
87
+ "tokencount",
88
+ "prompttokens",
89
+ "completiontokens",
90
+ "totaltokens",
91
+ "inputtokens",
92
+ "outputtokens",
93
+ "reasoningtokens",
94
+ "cachetokens",
95
+ ]);
96
+ /**
97
+ * Normalizes one extraction key for separator-insensitive matching.
98
+ *
99
+ * @remarks
100
+ * Strips `-`, `_`, and `.` after lowercasing so hyphenated secrets
101
+ * (`api-key`, `access-token`, `provider-id`, `client-secret`, `upload-ids`)
102
+ * match the same anchored and suffix rules as their underscored spellings.
103
+ *
104
+ * @param key - Raw extraction key.
105
+ * @returns Lowercased key without `-`, `_`, or `.` characters.
106
+ */
107
+ function normalizeSanitizerKey(key) {
108
+ return key.toLowerCase().replace(/[-_.]/gu, "");
109
+ }
110
+ /**
111
+ * Reports whether one separator-stripped key is legitimate usage accounting.
112
+ *
113
+ * @remarks
114
+ * Exact match covers the standard OpenAI-compatible usage block; the
115
+ * ends-with rule additionally preserves vendor-prefixed variants (for
116
+ * example `response_input_tokens` → `responseinputtokens`). Preservation is
117
+ * the fail-open direction here only because every accounting token is a
118
+ * known usage-counter suffix, never a secret shape.
119
+ *
120
+ * @param normalizedKey - Separator-stripped lowercased key (see {@link normalizeSanitizerKey}).
121
+ * @returns True when the key is accounting and must survive sanitization.
122
+ */
123
+ function isAccountingKey(normalizedKey) {
124
+ if (ACCOUNTING_KEYS.has(normalizedKey)) {
125
+ return true;
126
+ }
127
+ for (const token of ACCOUNTING_KEYS) {
128
+ if (normalizedKey.length > token.length && normalizedKey.endsWith(token)) {
129
+ return true;
130
+ }
131
+ }
132
+ return false;
133
+ }
134
+ /**
135
+ * Object keys that must never be assigned (prototype pollution guard).
136
+ */
137
+ const UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
138
+ /**
139
+ * Sanitizes EnriProxy extraction payloads for model consumption.
140
+ */
141
+ export class AnalyzeMediaExtractionSanitizer {
142
+ /**
143
+ * Removes internal identifiers from the extraction payload.
144
+ *
145
+ * @param extraction - Raw extraction object returned by EnriProxy.
146
+ * @returns Sanitized plain extraction object.
147
+ */
148
+ sanitize(extraction) {
149
+ const stripped = this.stripInternalFields(extraction);
150
+ if (stripped && typeof stripped === "object" && !Array.isArray(stripped)) {
151
+ return stripped;
152
+ }
153
+ return {};
154
+ }
155
+ /**
156
+ * Recursively strips internal fields from an unknown value.
157
+ *
158
+ * @param value - Unknown value to sanitize.
159
+ * @returns Sanitized value.
160
+ */
161
+ stripInternalFields(value) {
162
+ if (Array.isArray(value)) {
163
+ return value.map((item) => this.stripInternalFields(item));
164
+ }
165
+ if (!value || typeof value !== "object") {
166
+ return value;
167
+ }
168
+ const record = value;
169
+ const next = {};
170
+ for (const [key, child] of Object.entries(record)) {
171
+ if (UNSAFE_KEYS.has(key)) {
172
+ continue;
173
+ }
174
+ const lowered = key.toLowerCase();
175
+ if (PRESERVED_KEYS.has(lowered)) {
176
+ next[key] = this.stripInternalFields(child);
177
+ continue;
178
+ }
179
+ // Separator-insensitive matching (F10): hyphens, underscores, and dots
180
+ // are stripped before every rule below, so `api-key`, `access-token`,
181
+ // `provider-id`, `client-secret`, and `upload-ids` match exactly like
182
+ // their underscored spellings. Accounting is checked first so usage
183
+ // counters (including hyphenated and vendor-prefixed variants) survive
184
+ // the `token` suffix sweep.
185
+ const normalized = normalizeSanitizerKey(key);
186
+ if (isAccountingKey(normalized)) {
187
+ next[key] = this.stripInternalFields(child);
188
+ continue;
189
+ }
190
+ if (STRIPPED_KEY_PATTERN.test(normalized)) {
191
+ continue;
192
+ }
193
+ if (INTERNAL_KEYS.has(normalized)) {
194
+ continue;
195
+ }
196
+ // Substring/suffix secret sweep. Catches prefixed secrets the anchored
197
+ // pattern misses (`client_secret`, `my_token`) plus bare `jwt`/`jwk`
198
+ // bearer material and request-signing leftovers (`nonce`, `signature`).
199
+ if (normalized.includes("secret") ||
200
+ normalized.includes("apikey") ||
201
+ normalized.includes("privatekey") ||
202
+ normalized.includes("credential") ||
203
+ normalized.includes("password") ||
204
+ normalized.includes("passwd") ||
205
+ /tokens?$/u.test(normalized) ||
206
+ SECRET_SUFFIX_PATTERN.test(normalized)) {
207
+ continue;
208
+ }
209
+ next[key] = this.stripInternalFields(child);
210
+ }
211
+ return next;
212
+ }
213
+ }
214
+ //# sourceMappingURL=AnalyzeMediaExtractionSanitizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalyzeMediaExtractionSanitizer.js","sourceRoot":"","sources":["../../src/tools/AnalyzeMediaExtractionSanitizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,250 @@
1
+ /**
2
+ * ANALYZE MEDIA INPUT RESOLVER
3
+ *
4
+ * Turns validated `path`/`paths` arguments into local files ready for
5
+ * upload: URL inputs are materialized through bounded streaming downloads,
6
+ * every input is readability-checked, and its effective upload content type
7
+ * is resolved.
8
+ *
9
+ * Content-type rule: the server-reported content type is authoritative and
10
+ * always wins over the extension-derived guess, so `image/webp` served from
11
+ * `/a.png` can never degrade to `image/png`; the generic
12
+ * `application/octet-stream` never wins.
13
+ *
14
+ * @module tools/AnalyzeMediaInputResolver
15
+ */
16
+ import { MediaUrlFetcher, type MediaUrlFetchResult } from "../shared/mediaUrlFetcher.js";
17
+ import { type AnalyzeMediaToolParams } from "./AnalyzeMediaContract.js";
18
+ /**
19
+ * One media input resolved to a local file ready for upload.
20
+ */
21
+ export interface ResolvedMediaInput {
22
+ /**
23
+ * Local filesystem path (already materialized for URL inputs).
24
+ */
25
+ readonly localPath: string;
26
+ /**
27
+ * Upload file name.
28
+ */
29
+ readonly filename: string;
30
+ /**
31
+ * File size in bytes.
32
+ */
33
+ readonly sizeBytes: number;
34
+ /**
35
+ * Effective MIME type for the upload session.
36
+ */
37
+ readonly contentType: string;
38
+ /**
39
+ * Server-reported content type for downloaded URLs.
40
+ */
41
+ readonly urlContentType?: string;
42
+ /**
43
+ * True when the download file extension was synthesized from the server
44
+ * content type.
45
+ */
46
+ readonly extensionSynthesized: boolean;
47
+ /**
48
+ * File identity staged at resolve time (`ino:size:mtime:birthtime:nlink`).
49
+ *
50
+ * @remarks
51
+ * The uploader compares it against the `fstat` identity of the opened
52
+ * handle so a same-size replacement between resolve and upload fails
53
+ * loudly instead of shipping the wrong bytes.
54
+ */
55
+ readonly stagedIdentity?: string;
56
+ }
57
+ /**
58
+ * Resolved inputs plus the owned URL downloads awaiting cleanup.
59
+ */
60
+ export interface ResolvedMediaInputs {
61
+ /**
62
+ * Upload-ready inputs in request order.
63
+ */
64
+ readonly inputs: readonly ResolvedMediaInput[];
65
+ /**
66
+ * Owned URL downloads; the caller must clean each one up.
67
+ */
68
+ readonly materialized: readonly MediaUrlFetchResult[];
69
+ /**
70
+ * Single remote URL for server-side `source_url` ingest, set only when a
71
+ * lone http(s) input exceeds the 64 MiB client download cap. The fetcher
72
+ * SSRF guards already passed, so the server can ingest it directly
73
+ * without a client download + re-upload round trip.
74
+ */
75
+ readonly remoteUrl?: string;
76
+ }
77
+ /**
78
+ * Resolves validated media arguments into upload-ready local files.
79
+ */
80
+ export declare class AnalyzeMediaInputResolver {
81
+ /**
82
+ * Do-not-follow flag for strict-mode opens (`0` where advisory).
83
+ *
84
+ * @remarks
85
+ * `O_NOFOLLOW` is honored on POSIX; on Windows it is advisory at best,
86
+ * so the `dev:ino` handle-identity comparison stays the real gate there.
87
+ */
88
+ private static readonly NO_FOLLOW_FLAG;
89
+ /**
90
+ * Bounded http(s) media fetcher used for URL inputs.
91
+ */
92
+ private readonly urlFetcher;
93
+ /**
94
+ * Creates a new {@link AnalyzeMediaInputResolver}.
95
+ *
96
+ * @param urlFetcher - URL fetcher used to materialize http(s) inputs.
97
+ */
98
+ constructor(urlFetcher: MediaUrlFetcher);
99
+ /**
100
+ * Resolves validated params into local upload-ready inputs.
101
+ *
102
+ * @remarks
103
+ * When `paths` carries at least one entry it wins over `path` (documented
104
+ * in the tool schema).
105
+ *
106
+ * @param params - Validated tool parameters.
107
+ * @param signal - Optional cancellation signal forwarded to URL downloads.
108
+ * @returns Resolved inputs plus owned downloads awaiting cleanup.
109
+ * @throws Error with an Spanish-first bilingual message when no input was provided, a download fails, or a file is unreadable.
110
+ */
111
+ resolve(params: AnalyzeMediaToolParams, signal?: AbortSignal): Promise<ResolvedMediaInputs>;
112
+ /**
113
+ * Fails fast when resolved bytes already exceed the upload ceiling.
114
+ *
115
+ * @remarks
116
+ * Multi-entry sets travel as one tar archive (headers, padding, manifest,
117
+ * end marker), so the fail-fast estimates the tar framing overhead (see
118
+ * {@link estimateMediaSetTarBytes}) instead of the raw byte sum: a set
119
+ * summing to 3.99 GiB raw would otherwise materialize ~100 temp downloads
120
+ * only for the packager to reject it once framing pushes it over 4 GiB.
121
+ * Over-estimating is correct for a fail-fast.
122
+ *
123
+ * @param resolvedBytes - Running total of resolved input bytes.
124
+ * @param entryCount - Resolved entries so far (including the latest).
125
+ * @param isImageSet - Whether the call resolves a multi-entry set.
126
+ * @throws Error with an Spanish-first bilingual message when the set already exceeds 4 GiB.
127
+ */
128
+ private throwOnUploadCeilingExceeded;
129
+ /**
130
+ * Resolves one local file into an upload-ready input.
131
+ *
132
+ * @param localPath - Absolute local file path.
133
+ * @returns Upload-ready input.
134
+ * @throws Error with an Spanish-first bilingual message when the file is missing or unreadable.
135
+ */
136
+ private resolveLocalFile;
137
+ /**
138
+ * Rejects a non-image entry of a multi-entry set right after it materializes.
139
+ *
140
+ * @remarks
141
+ * The tar packager repeats this check authoritatively before packing; the
142
+ * early check here only stops the resolver from downloading the rest of
143
+ * the set after the first failure. Single inputs keep any allowed type.
144
+ *
145
+ * @param localPath - Materialized local path (for error messages).
146
+ * @param contentType - Effective content type of the entry.
147
+ * @param isImageSet - Whether the call resolves a multi-entry set.
148
+ * @throws Error with an Spanish-first bilingual message when a set entry is not an image.
149
+ */
150
+ private throwOnNonImageSetEntry;
151
+ /**
152
+ * Resolves one downloaded URL file into an upload-ready input.
153
+ *
154
+ * @param fetched - Owned download result.
155
+ * @returns Upload-ready input preferring the server content type when the extension was synthesized.
156
+ * @throws Error with an Spanish-first bilingual message when the downloaded file is unreadable.
157
+ */
158
+ private resolveDownloadedFile;
159
+ /**
160
+ * Resolves the upload content type for one media input.
161
+ *
162
+ * @remarks
163
+ * The server-reported content type is authoritative: whenever it differs
164
+ * from the extension-derived guess it wins (a synthesized download
165
+ * extension is only a filesystem hint, and a mismatched authored
166
+ * extension such as `/a.png` serving `image/webp` must never shadow the
167
+ * real type). The generic `application/octet-stream` never wins.
168
+ *
169
+ * @param localPath - Local file path (already materialized for URLs).
170
+ * @param urlContentType - Server-reported content type for downloaded URLs.
171
+ * @returns Effective MIME type.
172
+ */
173
+ private resolveEffectiveContentType;
174
+ /**
175
+ * Detects a MIME type using the file extension.
176
+ *
177
+ * @param filePath - File path.
178
+ * @returns MIME type string.
179
+ */
180
+ private detectMimeType;
181
+ /**
182
+ * Validates that a path exists and is a readable file.
183
+ *
184
+ * @remarks
185
+ * `path` follows symlinks by design (the MCP host trusts the model with
186
+ * host-file access, like the documented DNS-rebinding residual in
187
+ * `mediaUrlFetcher.ts`). Operators that need strict mode set
188
+ * `ENRIVISION_DENY_SYMLINKS=1` to reject symlinked inputs with a Spanish
189
+ * error instead.
190
+ *
191
+ * @param filePath - Local filesystem path.
192
+ * @returns File size in bytes.
193
+ * @throws Error with an Spanish-first bilingual message when the file is missing, not readable, a rejected symlink, or exceeds 4 GiB.
194
+ */
195
+ private assertReadableFile;
196
+ /**
197
+ * Validates one file without ever trusting a path re-stat.
198
+ *
199
+ * @remarks
200
+ * `lstat` + `stat` + `open` on the same path races: a symlink swapped in
201
+ * between the check and the open defeats `ENRIVISION_DENY_SYMLINKS`.
202
+ * Opening with `O_NOFOLLOW` (POSIX) makes a swapped-in symlink fail with
203
+ * `ELOOP` instead, and the size/kind verdicts come from `fstat` on the
204
+ * opened handle — never from a second path lookup. The `dev:ino`
205
+ * comparison additionally rejects a real file swapped between `lstat`
206
+ * and `open` on platforms where `O_NOFOLLOW` is advisory.
207
+ *
208
+ * @param filePath - Local filesystem path.
209
+ * @returns File size in bytes plus the staged `fstat` identity.
210
+ * @throws Error with an Spanish-first bilingual message when the file is missing, a symlink, swapped mid-check, or exceeds 4 GiB.
211
+ */
212
+ private assertReadableFileWithoutSymlinks;
213
+ /**
214
+ * Applies the shared size/kind verdicts to one stat result.
215
+ *
216
+ * @param filePath - Local filesystem path (for error messages).
217
+ * @param size - File size in bytes.
218
+ * @param isFile - Whether the stat target is a regular file.
219
+ * @returns File size in bytes.
220
+ * @throws Error with an Spanish-first bilingual message when the target is not a file, is empty, or exceeds 4 GiB.
221
+ */
222
+ private checkFileStat;
223
+ /**
224
+ * Maps filesystem lookup failures to the stable not-found error.
225
+ *
226
+ * @param filePath - Local filesystem path (for error messages).
227
+ * @param error - Raw filesystem error.
228
+ * @throws Error with an Spanish-first bilingual message when the file is missing; rethrows unreadable-file errors otherwise.
229
+ */
230
+ private throwOnMissingFile;
231
+ }
232
+ /**
233
+ * Estimates the tar archive size for a multi-image set before packing.
234
+ *
235
+ * @remarks
236
+ * Fail-fast estimator (over-estimates on purpose): raw bytes plus one 512 B
237
+ * header per file, the manifest entry (512 B header plus content padded to
238
+ * 512 B), worst-case content padding (511 B per file), and the 1024 B end
239
+ * marker. The manifest term budgets 256 B of envelope plus 512 B per entry
240
+ * (worst case: 255 B basenames plus content type plus JSON overhead), so
241
+ * long filenames never under-estimate. Used by the resolver so a set that
242
+ * only fits raw never pays ~100 temp downloads before the packager rejects
243
+ * it.
244
+ *
245
+ * @param rawBytes - Summed input bytes.
246
+ * @param fileCount - Number of files in the set.
247
+ * @returns Estimated tar size in bytes.
248
+ */
249
+ export declare function estimateMediaSetTarBytes(rawBytes: number, fileCount: number): number;
250
+ //# sourceMappingURL=AnalyzeMediaInputResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalyzeMediaInputResolver.d.ts","sourceRoot":"","sources":["../../src/tools/AnalyzeMediaInputResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,OAAO,EAAE,eAAe,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEzF,OAAO,EAAwB,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAa9F;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAEvC;;;;;;;OAOG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAE/C;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAEtD;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,yBAAyB;IACpC;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CACoB;IAE1D;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAE7C;;;;OAIG;gBACgB,UAAU,EAAE,eAAe;IAI9C;;;;;;;;;;;OAWG;IACU,OAAO,CAClB,MAAM,EAAE,sBAAsB,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC;IAyE/B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,4BAA4B;IAapC;;;;;;OAMG;YACW,gBAAgB;IAqB9B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,uBAAuB;IAQ/B;;;;;;OAMG;YACW,qBAAqB;IAwBnC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,2BAA2B;IASnC;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;;;;;;;;;;OAaG;YACW,kBAAkB;IA4BhC;;;;;;;;;;;;;;;OAeG;YACW,iCAAiC;IAmC/C;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAerB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;CAS3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAWpF"}