@ttt-productions/media-processing-core 0.8.15 → 0.8.17
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.
- package/dist/audio/audio-processor.d.ts +2 -2
- package/dist/audio/audio-processor.d.ts.map +1 -1
- package/dist/audio/audio-processor.js +62 -48
- package/dist/audio/audio-processor.js.map +1 -1
- package/dist/audio/probe.d.ts +1 -1
- package/dist/audio/probe.d.ts.map +1 -1
- package/dist/audio/probe.js +6 -3
- package/dist/audio/probe.js.map +1 -1
- package/dist/duration/media-duration.d.ts +2 -2
- package/dist/duration/media-duration.d.ts.map +1 -1
- package/dist/duration/media-duration.js +23 -21
- package/dist/duration/media-duration.js.map +1 -1
- package/dist/image/formats.d.ts +2 -2
- package/dist/image/formats.js +25 -25
- package/dist/image/formats.js.map +1 -1
- package/dist/image/image-processor.d.ts +2 -2
- package/dist/image/image-processor.d.ts.map +1 -1
- package/dist/image/image-processor.js +47 -37
- package/dist/image/image-processor.js.map +1 -1
- package/dist/image/resize.d.ts +2 -2
- package/dist/image/resize.d.ts.map +1 -1
- package/dist/image/resize.js +13 -13
- package/dist/image/resize.js.map +1 -1
- package/dist/index.d.ts +19 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -16
- package/dist/index.js.map +1 -1
- package/dist/inspection/inspect-media.d.ts +13 -13
- package/dist/inspection/inspect-media.d.ts.map +1 -1
- package/dist/inspection/inspect-media.js +196 -140
- package/dist/inspection/inspect-media.js.map +1 -1
- package/dist/io/fs.d.ts +1 -1
- package/dist/io/fs.js +4 -4
- package/dist/io/fs.js.map +1 -1
- package/dist/io/local-input.d.ts +1 -1
- package/dist/io/local-input.d.ts.map +1 -1
- package/dist/io/local-input.js +15 -15
- package/dist/io/local-input.js.map +1 -1
- package/dist/io/types.d.ts.map +1 -1
- package/dist/io/types.js.map +1 -1
- package/dist/moderation/merge.d.ts +1 -1
- package/dist/moderation/merge.d.ts.map +1 -1
- package/dist/moderation/merge.js +1 -1
- package/dist/moderation/merge.js.map +1 -1
- package/dist/moderation/types.d.ts +3 -3
- package/dist/moderation/types.js.map +1 -1
- package/dist/process-media.d.ts +2 -3
- package/dist/process-media.d.ts.map +1 -1
- package/dist/process-media.js +9 -9
- package/dist/process-media.js.map +1 -1
- package/dist/processing/errors.d.ts.map +1 -1
- package/dist/processing/errors.js +1 -1
- package/dist/processing/errors.js.map +1 -1
- package/dist/processing/result.d.ts +2 -2
- package/dist/processing/result.js +1 -1
- package/dist/processing/result.js.map +1 -1
- package/dist/run-pipeline.d.ts +5 -5
- package/dist/run-pipeline.d.ts.map +1 -1
- package/dist/run-pipeline.js +70 -54
- package/dist/run-pipeline.js.map +1 -1
- package/dist/server/download-token.d.ts +14 -0
- package/dist/server/download-token.d.ts.map +1 -0
- package/dist/server/download-token.js +19 -0
- package/dist/server/download-token.js.map +1 -0
- package/dist/server/firebase-media-io.d.ts +2 -2
- package/dist/server/firebase-media-io.js +1 -1
- package/dist/server/firebase-media-io.js.map +1 -1
- package/dist/server/gcs-errors.js +2 -2
- package/dist/server/gcs-errors.js.map +1 -1
- package/dist/server/index.d.ts +7 -5
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +7 -5
- package/dist/server/index.js.map +1 -1
- package/dist/server/pending-media.d.ts +2 -2
- package/dist/server/pending-media.d.ts.map +1 -1
- package/dist/server/pending-media.js +12 -6
- package/dist/server/pending-media.js.map +1 -1
- package/dist/server/r2-retry.d.ts +4 -4
- package/dist/server/r2-retry.d.ts.map +1 -1
- package/dist/server/r2-retry.js +48 -47
- package/dist/server/r2-retry.js.map +1 -1
- package/dist/server/staged-object.d.ts +2 -2
- package/dist/server/staged-object.d.ts.map +1 -1
- package/dist/server/staged-object.js +4 -4
- package/dist/server/staged-object.js.map +1 -1
- package/dist/server/storage-ops.d.ts +3 -5
- package/dist/server/storage-ops.d.ts.map +1 -1
- package/dist/server/storage-ops.js +101 -97
- package/dist/server/storage-ops.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/log.d.ts.map +1 -1
- package/dist/utils/log.js +3 -3
- package/dist/utils/log.js.map +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +1 -4
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/safe-path.js +8 -8
- package/dist/utils/safe-path.js.map +1 -1
- package/dist/validation/validate-duration.d.ts.map +1 -1
- package/dist/validation/validate-duration.js.map +1 -1
- package/dist/validation/validate-mime.d.ts.map +1 -1
- package/dist/validation/validate-mime.js.map +1 -1
- package/dist/validation/validate-size.d.ts.map +1 -1
- package/dist/validation/validate-size.js.map +1 -1
- package/dist/video/ffmpeg.d.ts +1 -1
- package/dist/video/ffmpeg.d.ts.map +1 -1
- package/dist/video/ffmpeg.js +51 -43
- package/dist/video/ffmpeg.js.map +1 -1
- package/dist/video/probe.d.ts +1 -1
- package/dist/video/probe.d.ts.map +1 -1
- package/dist/video/probe.js +10 -7
- package/dist/video/probe.js.map +1 -1
- package/dist/video/video-processor.d.ts +2 -2
- package/dist/video/video-processor.d.ts.map +1 -1
- package/dist/video/video-processor.js +123 -81
- package/dist/video/video-processor.js.map +1 -1
- package/dist/workspace/temp.js +4 -4
- package/dist/workspace/temp.js.map +1 -1
- package/package.json +2 -2
- package/dist/audio/index.d.ts +0 -3
- package/dist/audio/index.d.ts.map +0 -1
- package/dist/audio/index.js +0 -3
- package/dist/audio/index.js.map +0 -1
- package/dist/image/index.d.ts +0 -4
- package/dist/image/index.d.ts.map +0 -1
- package/dist/image/index.js +0 -4
- package/dist/image/index.js.map +0 -1
- package/dist/video/index.d.ts +0 -4
- package/dist/video/index.d.ts.map +0 -1
- package/dist/video/index.js +0 -4
- package/dist/video/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect-media.js","sourceRoot":"","sources":["../../src/inspection/inspect-media.ts"],"names":[],"mappings":"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","sourcesContent":["// =============================================================================\n// Canonical media content inspection\n// =============================================================================\n//\n// The ONE server-side classification authority. Consumes a LOCAL file (the\n// pipeline's generation-pinned temp download), establishes what the bytes\n// actually contain, and returns the bounded `MediaInspectionResult` contract\n// from @ttt-productions/media-schemas. Everything downstream — origin/kind\n// validation, processing-spec selection, the persisted asset kind, and the\n// safety (PhotoDNA) routing — derives from this one result. Client MIME,\n// filename, extension, container brand, and payload-byte heuristics are never\n// consulted.\n//\n// Design:\n// - family selection by a bounded 64 KiB SIGNATURE read (header only —\n// semantic elements are NEVER searched for in arbitrary payload: payload\n// bytes can mimic container elements, so a flat scan misclassifies WebM\n// audio as video);\n// - shared A/V containers (EBML/ISO-BMFF/Ogg/AVI) classified by a hardened\n// `ffprobe` stream table (libavformat's structural parsers), with timeout,\n// kill-on-abort, output cap, and strict schema validation;\n// - image-family proof by DECODER (sharp) — a signature or `ftyp` brand is a\n// candidate, not proof, and image-family ISO-BMFF (AVIF/HEIC) is resolved\n// BEFORE the ordinary \"any timed video stream wins\" rule (a valid AVIF\n// probes as a one-frame AV1 `video` stream);\n// - FAIL-CLOSED: anything unproven is `indeterminate` with the\n// `strict-video-fallback` safety plan — never audio, never publishable.\n\nimport { open } from \"node:fs/promises\";\nimport { z } from \"zod\";\nimport {\n MediaInspectionResultSchema,\n type MediaInspectionResult,\n type MediaInspectionStreams,\n type NormalizedCodecId,\n type MediaFormatId,\n} from \"@ttt-productions/media-schemas\";\nimport { DEFAULT_PROBE_TIMEOUT_MS, runCmd } from \"../video/ffmpeg.js\";\nimport { measureDurationSec, type MeasureDurationFn } from \"../duration/media-duration.js\";\n\n/** Bump on any classification-rule change (rides every decision event). */\nexport const INSPECTOR_VERSION = \"mpc-inspect-2\";\n\nconst SIGNATURE_READ_BYTES = 64 * 1024;\nconst PROBE_SIZE_BYTES = 4 * 1024 * 1024; // -probesize: metadata, not playback\nconst ANALYZE_DURATION_US = 10 * 1000 * 1000;\n\n// ---- ffprobe JSON boundary (strict; anything else is malformed) ----\n\nconst ProbeStreamSchema = z\n .object({\n codec_type: z.string().max(32).optional(),\n codec_name: z.string().max(64).optional(),\n disposition: z\n .object({ attached_pic: z.number().int().min(0).max(1).optional() })\n .loose()\n .optional(),\n })\n .loose();\n\nconst ProbeJsonSchema = z\n .object({\n format: z.object({ format_name: z.string().max(200).optional() }).loose().optional(),\n streams: z.array(ProbeStreamSchema).max(256).optional(),\n })\n .loose();\n\n// ---- codec normalization (bounded — raw strings never escape) ----\n\nconst CODEC_MAP: Record<string, NormalizedCodecId> = {\n h264: \"h264\",\n hevc: \"hevc\",\n vp8: \"vp8\",\n vp9: \"vp9\",\n av1: \"av1\",\n theora: \"theora\",\n mpeg4: \"mpeg4\",\n mjpeg: \"mjpeg\",\n aac: \"aac\",\n alac: \"alac\",\n opus: \"opus\",\n vorbis: \"vorbis\",\n mp3: \"mp3\",\n flac: \"flac\",\n};\n\nfunction normalizeCodec(name: string | undefined): NormalizedCodecId {\n if (!name) return \"other\";\n const n = name.toLowerCase();\n if (CODEC_MAP[n]) return CODEC_MAP[n];\n if (n.startsWith(\"pcm_\")) return \"pcm\";\n if (n.startsWith(\"amr\")) return \"amr\";\n return \"other\";\n}\n\n// ---- signature families ----\n\ntype SignatureFamily =\n | { family: \"image\"; formatId: MediaFormatId; container: string }\n | { family: \"svg\" }\n | { family: \"ebml\" }\n | { family: \"isobmff\"; brand: string }\n | { family: \"ogg\" }\n | { family: \"avi\" }\n | { family: \"wav\" }\n | { family: \"mp3\" }\n | { family: \"flac\" }\n | { family: \"unknown\" };\n\n/** ISO-BMFF brands that declare an IMAGE-item file (HEIF family). Resolved via\n * decoder proof BEFORE the timed-video rule — see the AVIF note above. */\nconst ISOBMFF_IMAGE_BRANDS = new Set([\"avif\", \"avis\", \"heic\", \"heix\", \"heim\", \"heis\", \"hevc\", \"hevx\", \"mif1\", \"msf1\"]);\n\nfunction ascii(b: Uint8Array, off: number, s: string): boolean {\n if (off + s.length > b.length) return false;\n for (let i = 0; i < s.length; i++) if (b[off + i] !== s.charCodeAt(i)) return false;\n return true;\n}\n\nexport function detectSignatureFamily(b: Uint8Array): SignatureFamily {\n if (b.length < 12) return { family: \"unknown\" };\n // images (single-format signatures)\n if (b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff) return { family: \"image\", formatId: \"jpeg\", container: \"jpeg\" };\n if (b[0] === 0x89 && ascii(b, 1, \"PNG\")) return { family: \"image\", formatId: \"png\", container: \"png\" };\n if (ascii(b, 0, \"GIF8\")) return { family: \"image\", formatId: \"gif\", container: \"gif\" };\n if (ascii(b, 0, \"RIFF\") && ascii(b, 8, \"WEBP\")) return { family: \"image\", formatId: \"webp\", container: \"webp\" };\n if (b[0] === 0x42 && b[1] === 0x4d) return { family: \"image\", formatId: \"bmp\", container: \"bmp\" };\n if ((b[0] === 0x49 && b[1] === 0x49 && b[2] === 0x2a) || (b[0] === 0x4d && b[1] === 0x4d && b[3] === 0x2a)) {\n return { family: \"image\", formatId: \"tiff\", container: \"tiff\" };\n }\n // SVG: XML text — scan a short prefix for '<svg' (bounded; case-insensitive).\n {\n const prefix = Buffer.from(b.slice(0, Math.min(b.length, 4096)))\n .toString(\"latin1\")\n .toLowerCase();\n if (prefix.includes(\"<svg\") && (prefix.trimStart().startsWith(\"<?xml\") || prefix.trimStart().startsWith(\"<svg\") || prefix.includes(\"<!doctype svg\"))) {\n return { family: \"svg\" };\n }\n }\n // containers\n if (b[0] === 0x1a && b[1] === 0x45 && b[2] === 0xdf && b[3] === 0xa3) return { family: \"ebml\" };\n if (ascii(b, 4, \"ftyp\")) {\n const brand = String.fromCharCode(b[8], b[9], b[10], b[11]).trim().toLowerCase();\n return { family: \"isobmff\", brand };\n }\n if (ascii(b, 0, \"OggS\")) return { family: \"ogg\" };\n if (ascii(b, 0, \"RIFF\") && ascii(b, 8, \"AVI \")) return { family: \"avi\" };\n if (ascii(b, 0, \"RIFF\") && ascii(b, 8, \"WAVE\")) return { family: \"wav\" };\n if (ascii(b, 0, \"ID3\")) return { family: \"mp3\" };\n if (b[0] === 0xff && (b[1] & 0xe0) === 0xe0) return { family: \"mp3\" };\n if (ascii(b, 0, \"fLaC\")) return { family: \"flac\" };\n return { family: \"unknown\" };\n}\n\n// ---- dependency seams (tests inject; production uses the real tools) ----\n\nexport interface InspectMediaDeps {\n /** Probe the local file; default shells to the hardened `ffprobe`. */\n probe?: (localPath: string, opts: { timeoutMs: number; signal?: AbortSignal }) => Promise<\n | { ok: true; json: unknown }\n | { ok: false; reason: \"timeout\" | \"truncated\" | \"failed\" | \"bad_json\" }\n >;\n /** Decode-prove an image; default uses sharp metadata. Returns frame count\n * (pages) on success, null on decode failure. */\n decodeImage?: (localPath: string) => Promise<{ frames: number } | null>;\n /** Measure the file's length; default reads its packet timestamps\n * (`measureDurationSec`). */\n measureDuration?: MeasureDurationFn;\n /** Injected ffprobe version (default: cached `ffprobe -version` first line). */\n ffprobeVersion?: string;\n}\n\nlet cachedFfprobeVersion: string | null | undefined;\n\nasync function getFfprobeVersion(): Promise<string | undefined> {\n if (cachedFfprobeVersion !== undefined) return cachedFfprobeVersion ?? undefined;\n try {\n const r = await runCmd(\"ffprobe\", [\"-version\"], { timeoutMs: 5_000 });\n const first = (r.stdout || r.stderr).split(/\\r?\\n/)[0]?.trim() ?? \"\";\n cachedFfprobeVersion = first ? first.slice(0, 120) : null;\n } catch {\n cachedFfprobeVersion = null;\n }\n return cachedFfprobeVersion ?? undefined;\n}\n\nasync function defaultProbe(\n localPath: string,\n opts: { timeoutMs: number; signal?: AbortSignal },\n): Promise<{ ok: true; json: unknown } | { ok: false; reason: \"timeout\" | \"truncated\" | \"failed\" | \"bad_json\" }> {\n let r;\n try {\n r = await runCmd(\n \"ffprobe\",\n [\n \"-v\",\n \"error\",\n \"-print_format\",\n \"json\",\n \"-show_format\",\n \"-show_streams\",\n \"-probesize\",\n String(PROBE_SIZE_BYTES),\n \"-analyzeduration\",\n String(ANALYZE_DURATION_US),\n localPath,\n ],\n { timeoutMs: opts.timeoutMs, signal: opts.signal },\n );\n } catch {\n return { ok: false, reason: \"failed\" }; // spawn failure (ffprobe missing) — fail closed\n }\n if (r.timedOut) return { ok: false, reason: \"timeout\" };\n if (r.truncated) return { ok: false, reason: \"truncated\" };\n if (r.code !== 0) return { ok: false, reason: \"failed\" };\n try {\n return { ok: true, json: JSON.parse(r.stdout || \"{}\") };\n } catch {\n return { ok: false, reason: \"bad_json\" };\n }\n}\n\nasync function defaultDecodeImage(localPath: string): Promise<{ frames: number } | null> {\n try {\n const sharp = (await import(\"sharp\")).default;\n const meta = await sharp(localPath, { limitInputPixels: 268402689 /* sharp default ~16k x 16k */ }).metadata();\n if (!meta.width || !meta.height) return null;\n return { frames: Math.max(1, meta.pages ?? 1) };\n } catch {\n return null;\n }\n}\n\n// ---- result builders ----\n\nfunction baseResult(\n partial: Omit<MediaInspectionResult, \"inspectorVersion\" | \"streams\" | \"codecs\"> &\n Partial<Pick<MediaInspectionResult, \"streams\" | \"codecs\">>,\n ffprobeVersion: string | undefined,\n): MediaInspectionResult {\n const result: MediaInspectionResult = {\n inspectorVersion: INSPECTOR_VERSION,\n ...(ffprobeVersion ? { ffprobeVersion } : {}),\n streams: partial.streams ?? { audio: 0, timedVideo: 0, attachedPictures: 0, imageFrames: 0, auxiliary: 0 },\n codecs: partial.codecs ?? { audio: [], video: [] },\n status: partial.status,\n container: partial.container,\n safetyPlan: partial.safetyPlan,\n reasonCode: partial.reasonCode,\n ...(partial.canonicalKind ? { canonicalKind: partial.canonicalKind } : {}),\n ...(partial.formatId ? { formatId: partial.formatId } : {}),\n ...(partial.durationSec !== undefined ? { durationSec: partial.durationSec } : {}),\n };\n return MediaInspectionResultSchema.parse(result);\n}\n\nfunction indeterminate(\n container: string,\n reasonCode: string,\n ffprobeVersion: string | undefined,\n formatId?: MediaFormatId,\n): MediaInspectionResult {\n return baseResult(\n {\n status: \"indeterminate\",\n container,\n safetyPlan: \"strict-video-fallback\",\n reasonCode,\n ...(formatId ? { formatId } : {}),\n },\n ffprobeVersion,\n );\n}\n\n// ---- the inspector ----\n\nexport interface InspectMediaArgs {\n localPath: string;\n timeoutMs?: number;\n signal?: AbortSignal;\n deps?: InspectMediaDeps;\n}\n\nexport async function inspectMedia(args: InspectMediaArgs): Promise<MediaInspectionResult> {\n const timeoutMs = args.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;\n const probe = args.deps?.probe ?? defaultProbe;\n const decodeImage = args.deps?.decodeImage ?? defaultDecodeImage;\n const ffprobeVersion = args.deps?.ffprobeVersion ?? (await getFfprobeVersion());\n\n // 1) bounded signature read (header only)\n let head: Uint8Array;\n try {\n const fh = await open(args.localPath, \"r\");\n try {\n const buf = Buffer.alloc(SIGNATURE_READ_BYTES);\n const { bytesRead } = await fh.read(buf, 0, SIGNATURE_READ_BYTES, 0);\n head = buf.subarray(0, bytesRead);\n } finally {\n await fh.close();\n }\n } catch {\n return indeterminate(\"unknown\", \"read_failed\", ffprobeVersion);\n }\n\n const sig = detectSignatureFamily(head);\n\n // 2) family routing\n switch (sig.family) {\n case \"unknown\":\n return indeterminate(\"unknown\", \"unrecognized_signature\", ffprobeVersion);\n\n case \"svg\":\n // Scriptable XML \"image\" — structurally recognized, deliberately NOT a\n // processable format: it can carry script and no sanitize/rasterize step\n // exists. Never classified by decoder capability alone.\n return baseResult(\n {\n status: \"unsupported\",\n container: \"svg\",\n formatId: \"svg\",\n safetyPlan: \"strict-video-fallback\",\n reasonCode: \"unsupported_format:svg\",\n },\n ffprobeVersion,\n );\n\n case \"image\": {\n // Single-format image signature: decoder proof required — a signature is\n // a candidate, not a classification.\n const decoded = await decodeImage(args.localPath);\n if (!decoded) return baseResult(\n { status: \"malformed\", container: sig.container, formatId: sig.formatId, safetyPlan: \"strict-video-fallback\", reasonCode: \"image_decode_failed\" },\n ffprobeVersion,\n );\n const frames = decoded.frames;\n return baseResult(\n {\n status: \"definitive\",\n canonicalKind: \"image\",\n container: sig.container,\n formatId: sig.formatId,\n streams: { audio: 0, timedVideo: 0, attachedPictures: 0, imageFrames: frames, auxiliary: 0 },\n safetyPlan: frames > 1 ? \"animated-image-frames\" : \"still-image\",\n reasonCode: \"ok\",\n },\n ffprobeVersion,\n );\n }\n\n case \"isobmff\":\n if (ISOBMFF_IMAGE_BRANDS.has(sig.brand)) {\n // IMAGE-FAMILY ISO-BMFF resolves BEFORE the timed-video rule: a valid\n // AVIF probes as a one-frame AV1 `video` stream. Proof = image brand +\n // successful bounded decode + no ordinary timed A/V presentation.\n const probed = await probe(args.localPath, { timeoutMs, signal: args.signal });\n const parsed = probed.ok ? ProbeJsonSchema.safeParse(probed.json) : null;\n const streams = parsed?.success ? parsed.data.streams ?? [] : null;\n const hasAudio = streams ? streams.some((s) => s.codec_type === \"audio\") : true; // unknown ⇒ assume worst\n const formatId: MediaFormatId | undefined = sig.brand.startsWith(\"avi\") ? \"avif\" : \"heic\";\n const decoded = await decodeImage(args.localPath);\n if (!decoded || hasAudio) {\n if (formatId === \"heic\" && !decoded && !hasAudio) {\n // Recognized HEIC-family that the runtime cannot decode: explicit\n // unsupported-image (launch policy) — NEVER relabeled video.\n return baseResult(\n { status: \"unsupported\", container: \"heif\", formatId, safetyPlan: \"strict-video-fallback\", reasonCode: \"unsupported_format:heic\" },\n ffprobeVersion,\n );\n }\n // Undecodable/ambiguous image-brand file, or one carrying audio (a\n // real timed presentation wearing an image brand): fail toward the\n // stricter visual path.\n return indeterminate(\"heif\", decoded ? \"image_brand_with_audio\" : \"image_decode_failed\", ffprobeVersion, formatId);\n }\n const frames = decoded.frames;\n return baseResult(\n {\n status: \"definitive\",\n canonicalKind: \"image\",\n container: \"heif\",\n formatId,\n streams: { audio: 0, timedVideo: 0, attachedPictures: 0, imageFrames: frames, auxiliary: 0 },\n safetyPlan: frames > 1 ? \"animated-image-frames\" : \"still-image\",\n reasonCode: \"ok\",\n },\n ffprobeVersion,\n );\n }\n return classifyAvContainer(args, \"isobmff\", \"isobmff\", probe, timeoutMs, ffprobeVersion);\n\n case \"ebml\":\n return classifyAvContainer(args, \"webm\", \"webm\", probe, timeoutMs, ffprobeVersion);\n case \"ogg\":\n return classifyAvContainer(args, \"ogg\", \"ogg\", probe, timeoutMs, ffprobeVersion);\n case \"avi\":\n // Real container ffprobe parses; no registry entry (no origin enables it\n // today) — the stream truth still classifies it, policy rejects by format.\n return classifyAvContainer(args, \"avi\", undefined, probe, timeoutMs, ffprobeVersion);\n case \"wav\":\n return classifyAvContainer(args, \"wav\", \"wav\", probe, timeoutMs, ffprobeVersion);\n case \"mp3\":\n return classifyAvContainer(args, \"mp3\", \"mp3\", probe, timeoutMs, ffprobeVersion);\n case \"flac\":\n return classifyAvContainer(args, \"flac\", \"flac\", probe, timeoutMs, ffprobeVersion);\n }\n}\n\nasync function classifyAvContainer(\n args: InspectMediaArgs,\n container: string,\n formatId: MediaFormatId | undefined,\n probe: NonNullable<InspectMediaDeps[\"probe\"]>,\n timeoutMs: number,\n ffprobeVersion: string | undefined,\n): Promise<MediaInspectionResult> {\n const probed = await probe(args.localPath, { timeoutMs, signal: args.signal });\n if (!probed.ok) {\n return indeterminate(container, `probe_${probed.reason}`, ffprobeVersion, formatId);\n }\n const parsed = ProbeJsonSchema.safeParse(probed.json);\n if (!parsed.success) return indeterminate(container, \"probe_schema_invalid\", ffprobeVersion, formatId);\n\n const rawStreams = parsed.data.streams ?? [];\n if (rawStreams.length === 0) return indeterminate(container, \"no_streams\", ffprobeVersion, formatId);\n\n const counts: MediaInspectionStreams = { audio: 0, timedVideo: 0, attachedPictures: 0, imageFrames: 0, auxiliary: 0 };\n const audioCodecs = new Set<NormalizedCodecId>();\n const videoCodecs = new Set<NormalizedCodecId>();\n let sawUnknownType = false;\n\n for (const s of rawStreams) {\n const type = s.codec_type ?? \"\";\n if (type === \"audio\") {\n counts.audio++;\n audioCodecs.add(normalizeCodec(s.codec_name));\n } else if (type === \"video\") {\n // An attached picture (cover art) is NOT a timed presentation — but the\n // disposition flag is untrusted container data, so it is COUNTED and the\n // safety plan forces every such picture through the image hash path\n // before the audio guard may return clean.\n if (s.disposition?.attached_pic === 1) {\n counts.attachedPictures++;\n } else {\n counts.timedVideo++;\n videoCodecs.add(normalizeCodec(s.codec_name));\n }\n } else if (type === \"subtitle\" || type === \"data\" || type === \"attachment\") {\n counts.auxiliary++;\n } else {\n counts.auxiliary++;\n sawUnknownType = true;\n }\n }\n\n const codecs = { audio: [...audioCodecs], video: [...videoCodecs] };\n const measure = args.deps?.measureDuration ?? measureDurationSec;\n const durationSec = await measure(args.localPath, { signal: args.signal });\n const duration = durationSec !== undefined ? { durationSec } : {};\n\n // classification table (fail-closed)\n if (counts.timedVideo > 0) {\n return baseResult(\n {\n status: \"definitive\",\n canonicalKind: \"video\",\n container,\n ...(formatId ? { formatId } : {}),\n streams: counts,\n codecs,\n ...duration,\n safetyPlan: \"video-frames\",\n reasonCode: \"ok\",\n },\n ffprobeVersion,\n );\n }\n if (counts.audio > 0 && !sawUnknownType) {\n return baseResult(\n {\n status: \"definitive\",\n canonicalKind: \"audio\",\n container,\n ...(formatId ? { formatId } : {}),\n streams: counts,\n codecs,\n ...duration,\n safetyPlan: counts.attachedPictures > 0 ? \"audio-plus-artwork\" : \"audio-only\",\n reasonCode: \"ok\",\n },\n ffprobeVersion,\n );\n }\n // auxiliary-only, unknown stream types alongside audio, or nothing usable:\n // never audio — the strict visual fallback owns it.\n return baseResult(\n {\n status: \"indeterminate\",\n container,\n ...(formatId ? { formatId } : {}),\n streams: counts,\n codecs,\n ...duration,\n safetyPlan: \"strict-video-fallback\",\n reasonCode: sawUnknownType ? \"unknown_stream_type\" : \"auxiliary_only\",\n },\n ffprobeVersion,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"inspect-media.js","sourceRoot":"","sources":["../../src/inspection/inspect-media.ts"],"names":[],"mappings":"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","sourcesContent":["// =============================================================================\n// Canonical media content inspection\n// =============================================================================\n//\n// The ONE server-side classification authority. Consumes a LOCAL file (the\n// pipeline's generation-pinned temp download), establishes what the bytes\n// actually contain, and returns the bounded `MediaInspectionResult` contract\n// from @ttt-productions/media-schemas. Everything downstream — origin/kind\n// validation, processing-spec selection, the persisted asset kind, and the\n// safety (PhotoDNA) routing — derives from this one result. Client MIME,\n// filename, extension, container brand, and payload-byte heuristics are never\n// consulted.\n//\n// Design:\n// - family selection by a bounded 64 KiB SIGNATURE read (header only —\n// semantic elements are NEVER searched for in arbitrary payload: payload\n// bytes can mimic container elements, so a flat scan misclassifies WebM\n// audio as video);\n// - shared A/V containers (EBML/ISO-BMFF/Ogg/AVI) classified by a hardened\n// `ffprobe` stream table (libavformat's structural parsers), with timeout,\n// kill-on-abort, output cap, and strict schema validation;\n// - image-family proof by DECODER (sharp) — a signature or `ftyp` brand is a\n// candidate, not proof, and image-family ISO-BMFF (AVIF/HEIC) is resolved\n// BEFORE the ordinary \"any timed video stream wins\" rule (a valid AVIF\n// probes as a one-frame AV1 `video` stream);\n// - FAIL-CLOSED: anything unproven is `indeterminate` with the\n// `strict-video-fallback` safety plan — never audio, never publishable.\n\nimport { open } from 'node:fs/promises';\nimport { z } from 'zod';\nimport {\n MediaInspectionResultSchema,\n type MediaInspectionResult,\n type MediaInspectionStreams,\n type NormalizedCodecId,\n type MediaFormatId,\n} from '@ttt-productions/media-schemas';\nimport { DEFAULT_PROBE_TIMEOUT_MS, runCmd } from '../video/ffmpeg.js';\nimport { measureDurationSec, type MeasureDurationFn } from '../duration/media-duration.js';\n\n/** Bump on any classification-rule change (rides every decision event). */\nexport const INSPECTOR_VERSION = 'mpc-inspect-2';\n\nconst SIGNATURE_READ_BYTES = 64 * 1024;\nconst PROBE_SIZE_BYTES = 4 * 1024 * 1024; // -probesize: metadata, not playback\nconst ANALYZE_DURATION_US = 10 * 1000 * 1000;\n\n// ---- ffprobe JSON boundary (strict; anything else is malformed) ----\n\nconst ProbeStreamSchema = z\n .object({\n codec_type: z.string().max(32).optional(),\n codec_name: z.string().max(64).optional(),\n disposition: z\n .object({ attached_pic: z.number().int().min(0).max(1).optional() })\n .loose()\n .optional(),\n })\n .loose();\n\nconst ProbeJsonSchema = z\n .object({\n format: z\n .object({ format_name: z.string().max(200).optional() })\n .loose()\n .optional(),\n streams: z.array(ProbeStreamSchema).max(256).optional(),\n })\n .loose();\n\n// ---- codec normalization (bounded — raw strings never escape) ----\n\nconst CODEC_MAP: Record<string, NormalizedCodecId> = {\n h264: 'h264',\n hevc: 'hevc',\n vp8: 'vp8',\n vp9: 'vp9',\n av1: 'av1',\n theora: 'theora',\n mpeg4: 'mpeg4',\n mjpeg: 'mjpeg',\n aac: 'aac',\n alac: 'alac',\n opus: 'opus',\n vorbis: 'vorbis',\n mp3: 'mp3',\n flac: 'flac',\n};\n\nfunction normalizeCodec(name: string | undefined): NormalizedCodecId {\n if (!name) return 'other';\n const n = name.toLowerCase();\n if (CODEC_MAP[n]) return CODEC_MAP[n];\n if (n.startsWith('pcm_')) return 'pcm';\n if (n.startsWith('amr')) return 'amr';\n return 'other';\n}\n\n// ---- signature families ----\n\ntype SignatureFamily =\n | { family: 'image'; formatId: MediaFormatId; container: string }\n | { family: 'svg' }\n | { family: 'ebml' }\n | { family: 'isobmff'; brand: string }\n | { family: 'ogg' }\n | { family: 'avi' }\n | { family: 'wav' }\n | { family: 'mp3' }\n | { family: 'flac' }\n | { family: 'unknown' };\n\n/** ISO-BMFF brands that declare an IMAGE-item file (HEIF family). Resolved via\n * decoder proof BEFORE the timed-video rule — see the AVIF note above. */\nconst ISOBMFF_IMAGE_BRANDS = new Set([\n 'avif',\n 'avis',\n 'heic',\n 'heix',\n 'heim',\n 'heis',\n 'hevc',\n 'hevx',\n 'mif1',\n 'msf1',\n]);\n\nfunction ascii(b: Uint8Array, off: number, s: string): boolean {\n if (off + s.length > b.length) return false;\n for (let i = 0; i < s.length; i++) if (b[off + i] !== s.charCodeAt(i)) return false;\n return true;\n}\n\nexport function detectSignatureFamily(b: Uint8Array): SignatureFamily {\n if (b.length < 12) return { family: 'unknown' };\n // images (single-format signatures)\n if (b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff)\n return { family: 'image', formatId: 'jpeg', container: 'jpeg' };\n if (b[0] === 0x89 && ascii(b, 1, 'PNG'))\n return { family: 'image', formatId: 'png', container: 'png' };\n if (ascii(b, 0, 'GIF8')) return { family: 'image', formatId: 'gif', container: 'gif' };\n if (ascii(b, 0, 'RIFF') && ascii(b, 8, 'WEBP'))\n return { family: 'image', formatId: 'webp', container: 'webp' };\n if (b[0] === 0x42 && b[1] === 0x4d) return { family: 'image', formatId: 'bmp', container: 'bmp' };\n if (\n (b[0] === 0x49 && b[1] === 0x49 && b[2] === 0x2a) ||\n (b[0] === 0x4d && b[1] === 0x4d && b[3] === 0x2a)\n ) {\n return { family: 'image', formatId: 'tiff', container: 'tiff' };\n }\n // SVG: XML text — scan a short prefix for '<svg' (bounded; case-insensitive).\n {\n const prefix = Buffer.from(b.slice(0, Math.min(b.length, 4096)))\n .toString('latin1')\n .toLowerCase();\n if (\n prefix.includes('<svg') &&\n (prefix.trimStart().startsWith('<?xml') ||\n prefix.trimStart().startsWith('<svg') ||\n prefix.includes('<!doctype svg'))\n ) {\n return { family: 'svg' };\n }\n }\n // containers\n if (b[0] === 0x1a && b[1] === 0x45 && b[2] === 0xdf && b[3] === 0xa3) return { family: 'ebml' };\n if (ascii(b, 4, 'ftyp')) {\n const brand = String.fromCharCode(b[8], b[9], b[10], b[11]).trim().toLowerCase();\n return { family: 'isobmff', brand };\n }\n if (ascii(b, 0, 'OggS')) return { family: 'ogg' };\n if (ascii(b, 0, 'RIFF') && ascii(b, 8, 'AVI ')) return { family: 'avi' };\n if (ascii(b, 0, 'RIFF') && ascii(b, 8, 'WAVE')) return { family: 'wav' };\n if (ascii(b, 0, 'ID3')) return { family: 'mp3' };\n if (b[0] === 0xff && (b[1] & 0xe0) === 0xe0) return { family: 'mp3' };\n if (ascii(b, 0, 'fLaC')) return { family: 'flac' };\n return { family: 'unknown' };\n}\n\n// ---- dependency seams (tests inject; production uses the real tools) ----\n\nexport interface InspectMediaDeps {\n /** Probe the local file; default shells to the hardened `ffprobe`. */\n probe?: (\n localPath: string,\n opts: { timeoutMs: number; signal?: AbortSignal },\n ) => Promise<\n | { ok: true; json: unknown }\n | { ok: false; reason: 'timeout' | 'truncated' | 'failed' | 'bad_json' }\n >;\n /** Decode-prove an image; default uses sharp metadata. Returns frame count\n * (pages) on success, null on decode failure. */\n decodeImage?: (localPath: string) => Promise<{ frames: number } | null>;\n /** Measure the file's length; default reads its packet timestamps\n * (`measureDurationSec`). */\n measureDuration?: MeasureDurationFn;\n /** Injected ffprobe version (default: cached `ffprobe -version` first line). */\n ffprobeVersion?: string;\n}\n\nlet cachedFfprobeVersion: string | null | undefined;\n\nasync function getFfprobeVersion(): Promise<string | undefined> {\n if (cachedFfprobeVersion !== undefined) return cachedFfprobeVersion ?? undefined;\n try {\n const r = await runCmd('ffprobe', ['-version'], { timeoutMs: 5_000 });\n const first = (r.stdout || r.stderr).split(/\\r?\\n/)[0]?.trim() ?? '';\n cachedFfprobeVersion = first ? first.slice(0, 120) : null;\n } catch {\n cachedFfprobeVersion = null;\n }\n return cachedFfprobeVersion ?? undefined;\n}\n\nasync function defaultProbe(\n localPath: string,\n opts: { timeoutMs: number; signal?: AbortSignal },\n): Promise<\n | { ok: true; json: unknown }\n | { ok: false; reason: 'timeout' | 'truncated' | 'failed' | 'bad_json' }\n> {\n let r;\n try {\n r = await runCmd(\n 'ffprobe',\n [\n '-v',\n 'error',\n '-print_format',\n 'json',\n '-show_format',\n '-show_streams',\n '-probesize',\n String(PROBE_SIZE_BYTES),\n '-analyzeduration',\n String(ANALYZE_DURATION_US),\n localPath,\n ],\n { timeoutMs: opts.timeoutMs, signal: opts.signal },\n );\n } catch {\n return { ok: false, reason: 'failed' }; // spawn failure (ffprobe missing) — fail closed\n }\n if (r.timedOut) return { ok: false, reason: 'timeout' };\n if (r.truncated) return { ok: false, reason: 'truncated' };\n if (r.code !== 0) return { ok: false, reason: 'failed' };\n try {\n return { ok: true, json: JSON.parse(r.stdout || '{}') };\n } catch {\n return { ok: false, reason: 'bad_json' };\n }\n}\n\nasync function defaultDecodeImage(localPath: string): Promise<{ frames: number } | null> {\n try {\n const sharp = (await import('sharp')).default;\n const meta = await sharp(localPath, {\n limitInputPixels: 268402689 /* sharp default ~16k x 16k */,\n }).metadata();\n if (!meta.width || !meta.height) return null;\n return { frames: Math.max(1, meta.pages ?? 1) };\n } catch {\n return null;\n }\n}\n\n// ---- result builders ----\n\nfunction baseResult(\n partial: Omit<MediaInspectionResult, 'inspectorVersion' | 'streams' | 'codecs'> &\n Partial<Pick<MediaInspectionResult, 'streams' | 'codecs'>>,\n ffprobeVersion: string | undefined,\n): MediaInspectionResult {\n const result: MediaInspectionResult = {\n inspectorVersion: INSPECTOR_VERSION,\n ...(ffprobeVersion ? { ffprobeVersion } : {}),\n streams: partial.streams ?? {\n audio: 0,\n timedVideo: 0,\n attachedPictures: 0,\n imageFrames: 0,\n auxiliary: 0,\n },\n codecs: partial.codecs ?? { audio: [], video: [] },\n status: partial.status,\n container: partial.container,\n safetyPlan: partial.safetyPlan,\n reasonCode: partial.reasonCode,\n ...(partial.canonicalKind ? { canonicalKind: partial.canonicalKind } : {}),\n ...(partial.formatId ? { formatId: partial.formatId } : {}),\n ...(partial.durationSec !== undefined ? { durationSec: partial.durationSec } : {}),\n };\n return MediaInspectionResultSchema.parse(result);\n}\n\nfunction indeterminate(\n container: string,\n reasonCode: string,\n ffprobeVersion: string | undefined,\n formatId?: MediaFormatId,\n): MediaInspectionResult {\n return baseResult(\n {\n status: 'indeterminate',\n container,\n safetyPlan: 'strict-video-fallback',\n reasonCode,\n ...(formatId ? { formatId } : {}),\n },\n ffprobeVersion,\n );\n}\n\n// ---- the inspector ----\n\nexport interface InspectMediaArgs {\n localPath: string;\n timeoutMs?: number;\n signal?: AbortSignal;\n deps?: InspectMediaDeps;\n}\n\nexport async function inspectMedia(args: InspectMediaArgs): Promise<MediaInspectionResult> {\n const timeoutMs = args.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;\n const probe = args.deps?.probe ?? defaultProbe;\n const decodeImage = args.deps?.decodeImage ?? defaultDecodeImage;\n const ffprobeVersion = args.deps?.ffprobeVersion ?? (await getFfprobeVersion());\n\n // 1) bounded signature read (header only)\n let head: Uint8Array;\n try {\n const fh = await open(args.localPath, 'r');\n try {\n const buf = Buffer.alloc(SIGNATURE_READ_BYTES);\n const { bytesRead } = await fh.read(buf, 0, SIGNATURE_READ_BYTES, 0);\n head = buf.subarray(0, bytesRead);\n } finally {\n await fh.close();\n }\n } catch {\n return indeterminate('unknown', 'read_failed', ffprobeVersion);\n }\n\n const sig = detectSignatureFamily(head);\n\n // 2) family routing\n switch (sig.family) {\n case 'unknown':\n return indeterminate('unknown', 'unrecognized_signature', ffprobeVersion);\n\n case 'svg':\n // Scriptable XML \"image\" — structurally recognized, deliberately NOT a\n // processable format: it can carry script and no sanitize/rasterize step\n // exists. Never classified by decoder capability alone.\n return baseResult(\n {\n status: 'unsupported',\n container: 'svg',\n formatId: 'svg',\n safetyPlan: 'strict-video-fallback',\n reasonCode: 'unsupported_format:svg',\n },\n ffprobeVersion,\n );\n\n case 'image': {\n // Single-format image signature: decoder proof required — a signature is\n // a candidate, not a classification.\n const decoded = await decodeImage(args.localPath);\n if (!decoded)\n return baseResult(\n {\n status: 'malformed',\n container: sig.container,\n formatId: sig.formatId,\n safetyPlan: 'strict-video-fallback',\n reasonCode: 'image_decode_failed',\n },\n ffprobeVersion,\n );\n const frames = decoded.frames;\n return baseResult(\n {\n status: 'definitive',\n canonicalKind: 'image',\n container: sig.container,\n formatId: sig.formatId,\n streams: {\n audio: 0,\n timedVideo: 0,\n attachedPictures: 0,\n imageFrames: frames,\n auxiliary: 0,\n },\n safetyPlan: frames > 1 ? 'animated-image-frames' : 'still-image',\n reasonCode: 'ok',\n },\n ffprobeVersion,\n );\n }\n\n case 'isobmff':\n if (ISOBMFF_IMAGE_BRANDS.has(sig.brand)) {\n // IMAGE-FAMILY ISO-BMFF resolves BEFORE the timed-video rule: a valid\n // AVIF probes as a one-frame AV1 `video` stream. Proof = image brand +\n // successful bounded decode + no ordinary timed A/V presentation.\n const probed = await probe(args.localPath, { timeoutMs, signal: args.signal });\n const parsed = probed.ok ? ProbeJsonSchema.safeParse(probed.json) : null;\n const streams = parsed?.success ? (parsed.data.streams ?? []) : null;\n const hasAudio = streams ? streams.some((s) => s.codec_type === 'audio') : true; // unknown ⇒ assume worst\n const formatId: MediaFormatId | undefined = sig.brand.startsWith('avi') ? 'avif' : 'heic';\n const decoded = await decodeImage(args.localPath);\n if (!decoded || hasAudio) {\n if (formatId === 'heic' && !decoded && !hasAudio) {\n // Recognized HEIC-family that the runtime cannot decode: explicit\n // unsupported-image (launch policy) — NEVER relabeled video.\n return baseResult(\n {\n status: 'unsupported',\n container: 'heif',\n formatId,\n safetyPlan: 'strict-video-fallback',\n reasonCode: 'unsupported_format:heic',\n },\n ffprobeVersion,\n );\n }\n // Undecodable/ambiguous image-brand file, or one carrying audio (a\n // real timed presentation wearing an image brand): fail toward the\n // stricter visual path.\n return indeterminate(\n 'heif',\n decoded ? 'image_brand_with_audio' : 'image_decode_failed',\n ffprobeVersion,\n formatId,\n );\n }\n const frames = decoded.frames;\n return baseResult(\n {\n status: 'definitive',\n canonicalKind: 'image',\n container: 'heif',\n formatId,\n streams: {\n audio: 0,\n timedVideo: 0,\n attachedPictures: 0,\n imageFrames: frames,\n auxiliary: 0,\n },\n safetyPlan: frames > 1 ? 'animated-image-frames' : 'still-image',\n reasonCode: 'ok',\n },\n ffprobeVersion,\n );\n }\n return classifyAvContainer(args, 'isobmff', 'isobmff', probe, timeoutMs, ffprobeVersion);\n\n case 'ebml':\n return classifyAvContainer(args, 'webm', 'webm', probe, timeoutMs, ffprobeVersion);\n case 'ogg':\n return classifyAvContainer(args, 'ogg', 'ogg', probe, timeoutMs, ffprobeVersion);\n case 'avi':\n // Real container ffprobe parses; no registry entry (no origin enables it\n // today) — the stream truth still classifies it, policy rejects by format.\n return classifyAvContainer(args, 'avi', undefined, probe, timeoutMs, ffprobeVersion);\n case 'wav':\n return classifyAvContainer(args, 'wav', 'wav', probe, timeoutMs, ffprobeVersion);\n case 'mp3':\n return classifyAvContainer(args, 'mp3', 'mp3', probe, timeoutMs, ffprobeVersion);\n case 'flac':\n return classifyAvContainer(args, 'flac', 'flac', probe, timeoutMs, ffprobeVersion);\n }\n}\n\nasync function classifyAvContainer(\n args: InspectMediaArgs,\n container: string,\n formatId: MediaFormatId | undefined,\n probe: NonNullable<InspectMediaDeps['probe']>,\n timeoutMs: number,\n ffprobeVersion: string | undefined,\n): Promise<MediaInspectionResult> {\n const probed = await probe(args.localPath, { timeoutMs, signal: args.signal });\n if (!probed.ok) {\n return indeterminate(container, `probe_${probed.reason}`, ffprobeVersion, formatId);\n }\n const parsed = ProbeJsonSchema.safeParse(probed.json);\n if (!parsed.success)\n return indeterminate(container, 'probe_schema_invalid', ffprobeVersion, formatId);\n\n const rawStreams = parsed.data.streams ?? [];\n if (rawStreams.length === 0)\n return indeterminate(container, 'no_streams', ffprobeVersion, formatId);\n\n const counts: MediaInspectionStreams = {\n audio: 0,\n timedVideo: 0,\n attachedPictures: 0,\n imageFrames: 0,\n auxiliary: 0,\n };\n const audioCodecs = new Set<NormalizedCodecId>();\n const videoCodecs = new Set<NormalizedCodecId>();\n let sawUnknownType = false;\n\n for (const s of rawStreams) {\n const type = s.codec_type ?? '';\n if (type === 'audio') {\n counts.audio++;\n audioCodecs.add(normalizeCodec(s.codec_name));\n } else if (type === 'video') {\n // An attached picture (cover art) is NOT a timed presentation — but the\n // disposition flag is untrusted container data, so it is COUNTED and the\n // safety plan forces every such picture through the image hash path\n // before the audio guard may return clean.\n if (s.disposition?.attached_pic === 1) {\n counts.attachedPictures++;\n } else {\n counts.timedVideo++;\n videoCodecs.add(normalizeCodec(s.codec_name));\n }\n } else if (type === 'subtitle' || type === 'data' || type === 'attachment') {\n counts.auxiliary++;\n } else {\n counts.auxiliary++;\n sawUnknownType = true;\n }\n }\n\n const codecs = { audio: [...audioCodecs], video: [...videoCodecs] };\n const measure = args.deps?.measureDuration ?? measureDurationSec;\n const durationSec = await measure(args.localPath, { signal: args.signal });\n const duration = durationSec !== undefined ? { durationSec } : {};\n\n // classification table (fail-closed)\n if (counts.timedVideo > 0) {\n return baseResult(\n {\n status: 'definitive',\n canonicalKind: 'video',\n container,\n ...(formatId ? { formatId } : {}),\n streams: counts,\n codecs,\n ...duration,\n safetyPlan: 'video-frames',\n reasonCode: 'ok',\n },\n ffprobeVersion,\n );\n }\n if (counts.audio > 0 && !sawUnknownType) {\n return baseResult(\n {\n status: 'definitive',\n canonicalKind: 'audio',\n container,\n ...(formatId ? { formatId } : {}),\n streams: counts,\n codecs,\n ...duration,\n safetyPlan: counts.attachedPictures > 0 ? 'audio-plus-artwork' : 'audio-only',\n reasonCode: 'ok',\n },\n ffprobeVersion,\n );\n }\n // auxiliary-only, unknown stream types alongside audio, or nothing usable:\n // never audio — the strict visual fallback owns it.\n return baseResult(\n {\n status: 'indeterminate',\n container,\n ...(formatId ? { formatId } : {}),\n streams: counts,\n codecs,\n ...duration,\n safetyPlan: 'strict-video-fallback',\n reasonCode: sawUnknownType ? 'unknown_stream_type' : 'auxiliary_only',\n },\n ffprobeVersion,\n );\n}\n"]}
|
package/dist/io/fs.d.ts
CHANGED
package/dist/io/fs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { copyFile, mkdir } from
|
|
2
|
-
import path from
|
|
3
|
-
import { sanitizeKey } from
|
|
1
|
+
import { copyFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { sanitizeKey } from '../utils/safe-path.js';
|
|
4
4
|
export function createFsIO(args) {
|
|
5
5
|
return {
|
|
6
6
|
input: {
|
|
@@ -19,7 +19,7 @@ export function createFsIO(args) {
|
|
|
19
19
|
const resolvedDir = path.resolve(args.outputDir);
|
|
20
20
|
const resolvedOut = path.resolve(out);
|
|
21
21
|
if (!resolvedOut.startsWith(resolvedDir + path.sep) && resolvedOut !== resolvedDir) {
|
|
22
|
-
throw new Error(
|
|
22
|
+
throw new Error('Unsafe output path');
|
|
23
23
|
}
|
|
24
24
|
await copyFile(localPath, out);
|
|
25
25
|
return { path: out, url: `file://${out}` };
|
package/dist/io/fs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/io/fs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,UAAU,UAAU,CAAC,IAI1B;IACC,OAAO;QACL,KAAK,EAAE;YACL,IAAI,EAAE,IAAI,CAAC,SAAS;YACpB,KAAK,CAAC,UAAU,CAAC,SAAS;gBACxB,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YAC5C,CAAC;SACF;QACD,MAAM,EAAE;YACN,KAAK,CAAC,aAAa,CAAC,SAAS,EAAE,GAAG;gBAChC,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACpC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;gBACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC;gBAE1D,4CAA4C;gBAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACjD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACtC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;oBACnF,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;gBACxC,CAAC;gBACD,MAAM,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;gBAC/B,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,GAAG,EAAE,EAAE,CAAC;YAC7C,CAAC;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { MediaIO } from
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/io/fs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,UAAU,UAAU,CAAC,IAI1B;IACC,OAAO;QACL,KAAK,EAAE;YACL,IAAI,EAAE,IAAI,CAAC,SAAS;YACpB,KAAK,CAAC,UAAU,CAAC,SAAS;gBACxB,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YAC5C,CAAC;SACF;QACD,MAAM,EAAE;YACN,KAAK,CAAC,aAAa,CAAC,SAAS,EAAE,GAAG;gBAChC,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACpC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;gBACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC;gBAE1D,4CAA4C;gBAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACjD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACtC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;oBACnF,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;gBACxC,CAAC;gBACD,MAAM,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;gBAC/B,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,GAAG,EAAE,EAAE,CAAC;YAC7C,CAAC;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { MediaIO } from './types.js';\nimport { copyFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport { sanitizeKey } from '../utils/safe-path.js';\n\nexport function createFsIO(args: {\n inputPath: string;\n inputMime?: string;\n outputDir: string;\n}): MediaIO {\n return {\n input: {\n mime: args.inputMime,\n async readToFile(localPath) {\n await copyFile(args.inputPath, localPath);\n },\n },\n output: {\n async writeFromFile(localPath, key) {\n await mkdir(args.outputDir, { recursive: true });\n const ext = path.extname(localPath);\n const safeKey = sanitizeKey(key);\n const out = path.join(args.outputDir, `${safeKey}${ext}`);\n\n // Ensure final path stays within outputDir.\n const resolvedDir = path.resolve(args.outputDir);\n const resolvedOut = path.resolve(out);\n if (!resolvedOut.startsWith(resolvedDir + path.sep) && resolvedOut !== resolvedDir) {\n throw new Error('Unsafe output path');\n }\n await copyFile(localPath, out);\n return { path: out, url: `file://${out}` };\n },\n },\n };\n}\n"]}
|
package/dist/io/local-input.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-input.d.ts","sourceRoot":"","sources":["../../src/io/local-input.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,6EAA6E;AAC7E,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,QAAQ,EAAE,MAAM;CAK7B;AAED,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC;4EACwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"local-input.d.ts","sourceRoot":"","sources":["../../src/io/local-input.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,6EAA6E;AAC7E,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,QAAQ,EAAE,MAAM;CAK7B;AAED,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC;4EACwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,aAAa,CAAC,CA+BxB;AAED,6FAA6F;AAC7F,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMvE;AAED,gGAAgG;AAChG,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAE3C;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,MAA0B,GACnC,OAAO,CAAC,UAAU,CAAC,CASrB"}
|
package/dist/io/local-input.js
CHANGED
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
// hard byte cap, hashes stream from disk, and signature checks read only a
|
|
5
5
|
// bounded header. These primitives are generic (no storage/vendor deps) — the
|
|
6
6
|
// caller supplies the Readable and owns generation pinning.
|
|
7
|
-
import { createHash } from
|
|
8
|
-
import { createReadStream, createWriteStream } from
|
|
9
|
-
import { mkdtemp, open, rm } from
|
|
10
|
-
import os from
|
|
11
|
-
import path from
|
|
12
|
-
import { pipeline } from
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
9
|
+
import { mkdtemp, open, rm } from 'node:fs/promises';
|
|
10
|
+
import os from 'node:os';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { pipeline } from 'node:stream/promises';
|
|
13
13
|
/** Thrown by {@link streamToTempFile} when the source exceeds `maxBytes`. */
|
|
14
14
|
export class ByteLimitExceededError extends Error {
|
|
15
15
|
maxBytes;
|
|
16
16
|
constructor(maxBytes) {
|
|
17
17
|
super(`source exceeded the ${maxBytes}-byte limit`);
|
|
18
|
-
this.name =
|
|
18
|
+
this.name = 'ByteLimitExceededError';
|
|
19
19
|
this.maxBytes = maxBytes;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -26,21 +26,21 @@ export class ByteLimitExceededError extends Error {
|
|
|
26
26
|
* removed before the error propagates.
|
|
27
27
|
*/
|
|
28
28
|
export async function streamToTempFile(source, options) {
|
|
29
|
-
const { maxBytes, prefix =
|
|
29
|
+
const { maxBytes, prefix = 'media-input-' } = options;
|
|
30
30
|
if (!Number.isFinite(maxBytes) || maxBytes <= 0) {
|
|
31
|
-
throw new Error(
|
|
31
|
+
throw new Error('streamToTempFile requires a positive finite maxBytes');
|
|
32
32
|
}
|
|
33
33
|
const dir = await mkdtemp(path.join(os.tmpdir(), prefix));
|
|
34
|
-
const localPath = path.join(dir,
|
|
34
|
+
const localPath = path.join(dir, 'input');
|
|
35
35
|
const cleanup = async () => {
|
|
36
36
|
await rm(dir, { recursive: true, force: true }).catch(() => { });
|
|
37
37
|
};
|
|
38
38
|
let bytesWritten = 0;
|
|
39
39
|
try {
|
|
40
|
-
const sink = createWriteStream(localPath, { flags:
|
|
40
|
+
const sink = createWriteStream(localPath, { flags: 'wx' });
|
|
41
41
|
await pipeline(source, async function* (chunks) {
|
|
42
42
|
for await (const chunk of chunks) {
|
|
43
|
-
const buf = typeof chunk ===
|
|
43
|
+
const buf = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
44
44
|
bytesWritten += buf.byteLength;
|
|
45
45
|
if (bytesWritten > maxBytes)
|
|
46
46
|
throw new ByteLimitExceededError(maxBytes);
|
|
@@ -56,12 +56,12 @@ export async function streamToTempFile(source, options) {
|
|
|
56
56
|
}
|
|
57
57
|
/** Streams a file through SHA-256 (constant memory) and returns the lowercase hex digest. */
|
|
58
58
|
export async function hashFileSha256(localPath) {
|
|
59
|
-
const hash = createHash(
|
|
59
|
+
const hash = createHash('sha256');
|
|
60
60
|
await pipeline(createReadStream(localPath), async (chunks) => {
|
|
61
61
|
for await (const chunk of chunks)
|
|
62
62
|
hash.update(chunk);
|
|
63
63
|
});
|
|
64
|
-
return hash.digest(
|
|
64
|
+
return hash.digest('hex');
|
|
65
65
|
}
|
|
66
66
|
/** Default header window for signature-family checks (matches the inspector's sniff window). */
|
|
67
67
|
export const FILE_HEADER_BYTES = 64 * 1024;
|
|
@@ -71,7 +71,7 @@ export const FILE_HEADER_BYTES = 64 * 1024;
|
|
|
71
71
|
* the whole source.
|
|
72
72
|
*/
|
|
73
73
|
export async function readFileHeader(localPath, maxBytes = FILE_HEADER_BYTES) {
|
|
74
|
-
const handle = await open(localPath,
|
|
74
|
+
const handle = await open(localPath, 'r');
|
|
75
75
|
try {
|
|
76
76
|
const buf = Buffer.alloc(maxBytes);
|
|
77
77
|
const { bytesRead } = await handle.read(buf, 0, maxBytes, 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-input.js","sourceRoot":"","sources":["../../src/io/local-input.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,iFAAiF;AACjF,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,4DAA4D;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhD,6EAA6E;AAC7E,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IACtC,QAAQ,CAAS;IAC1B,YAAY,QAAgB;QAC1B,KAAK,CAAC,uBAAuB,QAAQ,aAAa,CAAC,CAAC;QACpD,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAmBD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAgB,EAChB,OAAgC;IAEhC,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,GAAG,OAAO,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;QACzB,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC;IAEF,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,iBAAiB,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"local-input.js","sourceRoot":"","sources":["../../src/io/local-input.ts"],"names":[],"mappings":"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","sourcesContent":["// Bounded-memory local-input primitives (canonical-upload-content-classification,\n// bounded-memory unit). Safety scanning and hashing must never hold a full media\n// source in JS memory: sources stream to a generation-pinned temp file with a\n// hard byte cap, hashes stream from disk, and signature checks read only a\n// bounded header. These primitives are generic (no storage/vendor deps) — the\n// caller supplies the Readable and owns generation pinning.\n\nimport { createHash } from 'node:crypto';\nimport { createReadStream, createWriteStream } from 'node:fs';\nimport { mkdtemp, open, rm } from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { pipeline } from 'node:stream/promises';\nimport type { Readable } from 'node:stream';\n\n/** Thrown by {@link streamToTempFile} when the source exceeds `maxBytes`. */\nexport class ByteLimitExceededError extends Error {\n readonly maxBytes: number;\n constructor(maxBytes: number) {\n super(`source exceeded the ${maxBytes}-byte limit`);\n this.name = 'ByteLimitExceededError';\n this.maxBytes = maxBytes;\n }\n}\n\nexport interface TempFileInput {\n /** Absolute path of the fully-written temp file. */\n localPath: string;\n /** Total bytes written (always <= maxBytes). */\n bytesWritten: number;\n /** Removes the temp file and its private directory. Idempotent; never throws. */\n cleanup: () => Promise<void>;\n}\n\nexport interface StreamToTempFileOptions {\n /** HARD cap: the stream is destroyed and the temp file removed the moment the\n * cap is crossed, so an oversized source never fully lands on disk. */\n maxBytes: number;\n /** Temp-dir prefix (default \"media-input-\"). */\n prefix?: string;\n}\n\n/**\n * Streams a Readable into a private temp file with a hard byte cap and\n * constant memory. On success the caller MUST invoke `cleanup()` in a\n * `finally`. On any failure (cap exceeded, stream error) the temp file is\n * removed before the error propagates.\n */\nexport async function streamToTempFile(\n source: Readable,\n options: StreamToTempFileOptions,\n): Promise<TempFileInput> {\n const { maxBytes, prefix = 'media-input-' } = options;\n if (!Number.isFinite(maxBytes) || maxBytes <= 0) {\n throw new Error('streamToTempFile requires a positive finite maxBytes');\n }\n const dir = await mkdtemp(path.join(os.tmpdir(), prefix));\n const localPath = path.join(dir, 'input');\n const cleanup = async () => {\n await rm(dir, { recursive: true, force: true }).catch(() => {});\n };\n\n let bytesWritten = 0;\n try {\n const sink = createWriteStream(localPath, { flags: 'wx' });\n await pipeline(\n source,\n async function* (chunks: AsyncIterable<Buffer | string>) {\n for await (const chunk of chunks) {\n const buf = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;\n bytesWritten += buf.byteLength;\n if (bytesWritten > maxBytes) throw new ByteLimitExceededError(maxBytes);\n yield buf;\n }\n },\n sink,\n );\n } catch (err) {\n await cleanup();\n throw err;\n }\n return { localPath, bytesWritten, cleanup };\n}\n\n/** Streams a file through SHA-256 (constant memory) and returns the lowercase hex digest. */\nexport async function hashFileSha256(localPath: string): Promise<string> {\n const hash = createHash('sha256');\n await pipeline(createReadStream(localPath), async (chunks: AsyncIterable<Buffer>) => {\n for await (const chunk of chunks) hash.update(chunk);\n });\n return hash.digest('hex');\n}\n\n/** Default header window for signature-family checks (matches the inspector's sniff window). */\nexport const FILE_HEADER_BYTES = 64 * 1024;\n\n/**\n * Reads at most `maxBytes` (default 64 KiB) from the start of a file — the\n * bounded input for {@link detectSignatureFamily}-style checks without loading\n * the whole source.\n */\nexport async function readFileHeader(\n localPath: string,\n maxBytes: number = FILE_HEADER_BYTES,\n): Promise<Uint8Array> {\n const handle = await open(localPath, 'r');\n try {\n const buf = Buffer.alloc(maxBytes);\n const { bytesRead } = await handle.read(buf, 0, maxBytes, 0);\n return buf.subarray(0, bytesRead);\n } finally {\n await handle.close();\n }\n}\n"]}
|
package/dist/io/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/io/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/io/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,aAAa,CACX,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QACT,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,iBAAiB,CAAC;CAC3B"}
|
package/dist/io/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/io/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface MediaInputSource {\n
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/io/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface MediaInputSource {\n /** Copy source media into localPath */\n readToFile(localPath: string): Promise<void>;\n\n /** Optional mime hint */\n mime?: string;\n}\n\nexport interface MediaOutputTarget {\n /** Persist a processed file from localPath */\n writeFromFile(\n localPath: string,\n outputKey: string,\n ): Promise<{\n url?: string;\n path?: string;\n }>;\n}\n\nexport interface MediaIO {\n input: MediaInputSource;\n output: MediaOutputTarget;\n}\n"]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { MediaModerationResult } from
|
|
1
|
+
import type { MediaModerationResult } from '@ttt-productions/media-schemas';
|
|
2
2
|
export declare function mergeModeration(input?: MediaModerationResult | null, output?: MediaModerationResult | null): MediaModerationResult | undefined;
|
|
3
3
|
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../src/moderation/merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5E,wBAAgB,eAAe,CAC7B,KAAK,CAAC,EAAE,qBAAqB,GAAG,IAAI,EACpC,MAAM,CAAC,EAAE,qBAAqB,GAAG,IAAI,GACpC,qBAAqB,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../src/moderation/merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5E,wBAAgB,eAAe,CAC7B,KAAK,CAAC,EAAE,qBAAqB,GAAG,IAAI,EACpC,MAAM,CAAC,EAAE,qBAAqB,GAAG,IAAI,GACpC,qBAAqB,GAAG,SAAS,CAuBnC"}
|
package/dist/moderation/merge.js
CHANGED
|
@@ -8,7 +8,7 @@ export function mergeModeration(input, output) {
|
|
|
8
8
|
if (!b)
|
|
9
9
|
return a ?? undefined;
|
|
10
10
|
// worst status wins: rejected > flagged > error > passed
|
|
11
|
-
const rank = (s) => s ===
|
|
11
|
+
const rank = (s) => (s === 'rejected' ? 4 : s === 'flagged' ? 3 : s === 'error' ? 2 : 1);
|
|
12
12
|
const status = rank(a.status) >= rank(b.status) ? a.status : b.status;
|
|
13
13
|
const reasons = Array.from(new Set([...(a.reasons ?? []), ...(b.reasons ?? [])]));
|
|
14
14
|
const findings = [...(a.findings ?? []), ...(b.findings ?? [])];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/moderation/merge.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,eAAe,CAC7B,KAAoC,EACpC,MAAqC;IAErC,MAAM,CAAC,GAAG,KAAK,IAAI,SAAS,CAAC;IAC7B,MAAM,CAAC,GAAG,MAAM,IAAI,SAAS,CAAC;IAE9B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/B,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,IAAI,SAAS,CAAC;IAC9B,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,IAAI,SAAS,CAAC;IAE9B,yDAAyD;IACzD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/moderation/merge.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,eAAe,CAC7B,KAAoC,EACpC,MAAqC;IAErC,MAAM,CAAC,GAAG,KAAK,IAAI,SAAS,CAAC;IAC7B,MAAM,CAAC,GAAG,MAAM,IAAI,SAAS,CAAC;IAE9B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/B,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,IAAI,SAAS,CAAC;IAC9B,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,IAAI,SAAS,CAAC;IAE9B,yDAAyD;IACzD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjG,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAEtE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IAEhE,OAAO;QACL,MAAM;QACN,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ;QAClC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QAC7C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;QAChD,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU;KACzC,CAAC;AACJ,CAAC","sourcesContent":["import type { MediaModerationResult } from '@ttt-productions/media-schemas';\n\nexport function mergeModeration(\n input?: MediaModerationResult | null,\n output?: MediaModerationResult | null,\n): MediaModerationResult | undefined {\n const a = input ?? undefined;\n const b = output ?? undefined;\n\n if (!a && !b) return undefined;\n if (!a) return b ?? undefined;\n if (!b) return a ?? undefined;\n\n // worst status wins: rejected > flagged > error > passed\n const rank = (s: string) => (s === 'rejected' ? 4 : s === 'flagged' ? 3 : s === 'error' ? 2 : 1);\n\n const status = rank(a.status) >= rank(b.status) ? a.status : b.status;\n\n const reasons = Array.from(new Set([...(a.reasons ?? []), ...(b.reasons ?? [])]));\n const findings = [...(a.findings ?? []), ...(b.findings ?? [])];\n\n return {\n status,\n provider: b.provider ?? a.provider,\n reasons: reasons.length ? reasons : undefined,\n findings: findings.length ? findings : undefined,\n reviewedAt: b.reviewedAt ?? a.reviewedAt,\n };\n}\n"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { MediaModerationResult, MediaProcessingSpec } from
|
|
1
|
+
import type { MediaModerationResult, MediaProcessingSpec } from '@ttt-productions/media-schemas';
|
|
2
2
|
export interface ModerationInput {
|
|
3
3
|
spec: MediaProcessingSpec;
|
|
4
|
-
kind:
|
|
4
|
+
kind: 'image' | 'video' | 'audio' | 'generic';
|
|
5
5
|
localPath: string;
|
|
6
6
|
mime?: string;
|
|
7
7
|
}
|
|
8
8
|
export interface ModerationOutput {
|
|
9
9
|
spec: MediaProcessingSpec;
|
|
10
|
-
kind:
|
|
10
|
+
kind: 'image' | 'video' | 'audio' | 'generic';
|
|
11
11
|
outputs: Array<{
|
|
12
12
|
key: string;
|
|
13
13
|
localPath: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/moderation/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { MediaModerationResult, MediaProcessingSpec } from
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/moderation/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { MediaModerationResult, MediaProcessingSpec } from '@ttt-productions/media-schemas';\n\nexport interface ModerationInput {\n spec: MediaProcessingSpec;\n kind: 'image' | 'video' | 'audio' | 'generic';\n localPath: string;\n mime?: string;\n}\n\nexport interface ModerationOutput {\n spec: MediaProcessingSpec;\n kind: 'image' | 'video' | 'audio' | 'generic';\n outputs: Array<{\n key: string;\n localPath: string;\n mime?: string;\n }>;\n}\n\nexport interface ModerationAdapter {\n provider: string;\n\n /** Run on the ORIGINAL uploaded file before processing. */\n moderateInput?: (input: ModerationInput) => Promise<MediaModerationResult | null | undefined>;\n\n /** Run on PROCESSED outputs after processing. */\n moderateOutput?: (output: ModerationOutput) => Promise<MediaModerationResult | null | undefined>;\n}\n"]}
|
package/dist/process-media.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { MediaProcessingResult, MediaProcessingSpec } from
|
|
2
|
-
import type { MediaProcessors, ProcessMediaContext, ProcessMediaOptions } from
|
|
3
|
-
export type { MediaPipelineProgress, MediaProcessors, ProcessMediaContext, ProcessMediaOptions } from "./types.js";
|
|
1
|
+
import type { MediaProcessingResult, MediaProcessingSpec } from '@ttt-productions/media-schemas';
|
|
2
|
+
import type { MediaProcessors, ProcessMediaContext, ProcessMediaOptions } from './types.js';
|
|
4
3
|
export declare const defaultMediaProcessors: MediaProcessors;
|
|
5
4
|
export declare function processMedia(spec: MediaProcessingSpec, ctx: ProcessMediaContext, opts?: ProcessMediaOptions, processors?: MediaProcessors): Promise<MediaProcessingResult>;
|
|
6
5
|
//# sourceMappingURL=process-media.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-media.d.ts","sourceRoot":"","sources":["../src/process-media.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAIjG,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE5F,
|
|
1
|
+
{"version":3,"file":"process-media.d.ts","sourceRoot":"","sources":["../src/process-media.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAIjG,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE5F,eAAO,MAAM,sBAAsB,EAAE,eAIpC,CAAC;AAEF,wBAAsB,YAAY,CAChC,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,mBAAmB,EACxB,IAAI,CAAC,EAAE,mBAAmB,EAC1B,UAAU,GAAE,eAAwC,GACnD,OAAO,CAAC,qBAAqB,CAAC,CAmBhC"}
|
package/dist/process-media.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { processImage } from
|
|
2
|
-
import { processVideo } from
|
|
3
|
-
import { processAudio } from
|
|
1
|
+
import { processImage } from './image/image-processor.js';
|
|
2
|
+
import { processVideo } from './video/video-processor.js';
|
|
3
|
+
import { processAudio } from './audio/audio-processor.js';
|
|
4
4
|
export const defaultMediaProcessors = {
|
|
5
5
|
image: processImage,
|
|
6
6
|
video: processVideo,
|
|
@@ -8,18 +8,18 @@ export const defaultMediaProcessors = {
|
|
|
8
8
|
};
|
|
9
9
|
export async function processMedia(spec, ctx, opts, processors = defaultMediaProcessors) {
|
|
10
10
|
switch (spec.kind) {
|
|
11
|
-
case
|
|
11
|
+
case 'image':
|
|
12
12
|
return processors.image(spec, ctx, opts);
|
|
13
|
-
case
|
|
13
|
+
case 'video':
|
|
14
14
|
return processors.video(spec, ctx, opts);
|
|
15
|
-
case
|
|
15
|
+
case 'audio':
|
|
16
16
|
return processors.audio(spec, ctx, opts);
|
|
17
|
-
case
|
|
17
|
+
case 'generic':
|
|
18
18
|
default:
|
|
19
19
|
return {
|
|
20
20
|
ok: false,
|
|
21
|
-
mediaType:
|
|
22
|
-
error: { code:
|
|
21
|
+
mediaType: 'other',
|
|
22
|
+
error: { code: 'processing_failed', message: 'Generic processing not implemented yet.' },
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-media.js","sourceRoot":"","sources":["../src/process-media.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"process-media.js","sourceRoot":"","sources":["../src/process-media.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,MAAM,CAAC,MAAM,sBAAsB,GAAoB;IACrD,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,YAAY;CACpB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAyB,EACzB,GAAwB,EACxB,IAA0B,EAC1B,aAA8B,sBAAsB;IAEpD,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,OAAO;YACV,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAE3C,KAAK,OAAO;YACV,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAE3C,KAAK,OAAO;YACV,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAE3C,KAAK,SAAS,CAAC;QACf;YACE,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,SAAS,EAAE,OAAO;gBAClB,KAAK,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,yCAAyC,EAAE;aACzF,CAAC;IACN,CAAC;AACH,CAAC","sourcesContent":["import type { MediaProcessingResult, MediaProcessingSpec } from '@ttt-productions/media-schemas';\nimport { processImage } from './image/image-processor.js';\nimport { processVideo } from './video/video-processor.js';\nimport { processAudio } from './audio/audio-processor.js';\nimport type { MediaProcessors, ProcessMediaContext, ProcessMediaOptions } from './types.js';\n\nexport const defaultMediaProcessors: MediaProcessors = {\n image: processImage,\n video: processVideo,\n audio: processAudio,\n};\n\nexport async function processMedia(\n spec: MediaProcessingSpec,\n ctx: ProcessMediaContext,\n opts?: ProcessMediaOptions,\n processors: MediaProcessors = defaultMediaProcessors,\n): Promise<MediaProcessingResult> {\n switch (spec.kind) {\n case 'image':\n return processors.image(spec, ctx, opts);\n\n case 'video':\n return processors.video(spec, ctx, opts);\n\n case 'audio':\n return processors.audio(spec, ctx, opts);\n\n case 'generic':\n default:\n return {\n ok: false,\n mediaType: 'other',\n error: { code: 'processing_failed', message: 'Generic processing not implemented yet.' },\n };\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/processing/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/processing/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;EAM/F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/processing/errors.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe,
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/processing/errors.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,OAAe,EAAE,OAAiC;IAC9F,OAAO;QACL,IAAI;QACJ,OAAO;QACP,OAAO;KACR,CAAC;AACJ,CAAC","sourcesContent":["export function processingError(code: string, message: string, details?: Record<string, unknown>) {\n return {\n code,\n message,\n details,\n };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { MediaProcessingError, MediaProcessingResult } from
|
|
1
|
+
import type { MediaProcessingError, MediaProcessingResult } from '@ttt-productions/media-schemas';
|
|
2
2
|
export declare function success(result: Omit<Extract<MediaProcessingResult, {
|
|
3
3
|
ok: true;
|
|
4
|
-
}>,
|
|
4
|
+
}>, 'ok'>): Extract<MediaProcessingResult, {
|
|
5
5
|
ok: true;
|
|
6
6
|
}>;
|
|
7
7
|
export declare function failure(error: MediaProcessingError): Extract<MediaProcessingResult, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/processing/result.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,OAAO,CACrB,MAAgE;IAEhE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,KAA2B;IAE3B,OAAO;QACL,EAAE,EAAE,KAAK;QACT,SAAS,EAAE,OAAO;QAClB,KAAK;KACN,CAAC;AACJ,CAAC","sourcesContent":["import type { MediaProcessingError, MediaProcessingResult } from
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/processing/result.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,OAAO,CACrB,MAAgE;IAEhE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,KAA2B;IAE3B,OAAO;QACL,EAAE,EAAE,KAAK;QACT,SAAS,EAAE,OAAO;QAClB,KAAK;KACN,CAAC;AACJ,CAAC","sourcesContent":["import type { MediaProcessingError, MediaProcessingResult } from '@ttt-productions/media-schemas';\n\nexport function success(\n result: Omit<Extract<MediaProcessingResult, { ok: true }>, 'ok'>,\n): Extract<MediaProcessingResult, { ok: true }> {\n return { ok: true, ...result };\n}\n\nexport function failure(\n error: MediaProcessingError,\n): Extract<MediaProcessingResult, { ok: false }> {\n return {\n ok: false,\n mediaType: 'other',\n error,\n };\n}\n"]}
|
package/dist/run-pipeline.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type { MediaProcessingResult, MediaProcessingSpec, MediaInspectionResult, MediaProcessingError } from
|
|
2
|
-
import { type InspectMediaDeps } from
|
|
3
|
-
import type { MediaIO } from
|
|
4
|
-
import type { ModerationAdapter } from
|
|
1
|
+
import type { MediaProcessingResult, MediaProcessingSpec, MediaInspectionResult, MediaProcessingError } from '@ttt-productions/media-schemas';
|
|
2
|
+
import { type InspectMediaDeps } from './inspection/inspect-media.js';
|
|
3
|
+
import type { MediaIO } from './io/types.js';
|
|
4
|
+
import type { ModerationAdapter } from './moderation/types.js';
|
|
5
5
|
export interface RunPipelineArgs {
|
|
6
6
|
spec: MediaProcessingSpec;
|
|
7
7
|
io: MediaIO;
|
|
8
8
|
outputBaseName?: string;
|
|
9
9
|
moderation?: ModerationAdapter;
|
|
10
10
|
signal?: AbortSignal;
|
|
11
|
-
onProgress?: (p: import(
|
|
11
|
+
onProgress?: (p: import('./types.js').MediaPipelineProgress) => void;
|
|
12
12
|
/**
|
|
13
13
|
* CANONICAL INSPECTION SEAM (canonical-upload-content-classification).
|
|
14
14
|
* When present, the pipeline runs `inspectMedia` on the just-downloaded temp
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-pipeline.d.ts","sourceRoot":"","sources":["../src/run-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"run-pipeline.d.ts","sourceRoot":"","sources":["../src/run-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EAEnB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AAIxC,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACpF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAK/D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,YAAY,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACrE;;;;;;;;;;;;;;;OAeG;IACH,sBAAsB,CAAC,EAAE,CACvB,UAAU,EAAE,qBAAqB,KAE/B,OAAO,CAAC;QAAE,IAAI,EAAE,mBAAmB,CAAA;KAAE,GAAG;QAAE,MAAM,EAAE,oBAAoB,CAAA;KAAE,CAAC,GACzE,CAAC;QAAE,IAAI,EAAE,mBAAmB,CAAA;KAAE,GAAG;QAAE,MAAM,EAAE,oBAAoB,CAAA;KAAE,CAAC,CAAC;IACvE,yCAAyC;IACzC,cAAc,CAAC,EAAE,gBAAgB,CAAC;CACnC;AAmBD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA4Q5F"}
|