urma-mcp 0.1.0-rc.1
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/LICENSE +201 -0
- package/README.md +389 -0
- package/assets/urma-banner.png +0 -0
- package/assets/urma-logo.png +0 -0
- package/dist/src/acquisition/frame-panel.d.ts +22 -0
- package/dist/src/acquisition/frame-panel.js +110 -0
- package/dist/src/acquisition/frame-panel.js.map +1 -0
- package/dist/src/acquisition/frames.d.ts +37 -0
- package/dist/src/acquisition/frames.js +463 -0
- package/dist/src/acquisition/frames.js.map +1 -0
- package/dist/src/acquisition/media.d.ts +59 -0
- package/dist/src/acquisition/media.js +946 -0
- package/dist/src/acquisition/media.js.map +1 -0
- package/dist/src/acquisition/overview.d.ts +31 -0
- package/dist/src/acquisition/overview.js +335 -0
- package/dist/src/acquisition/overview.js.map +1 -0
- package/dist/src/acquisition/panel.d.ts +16 -0
- package/dist/src/acquisition/panel.js +125 -0
- package/dist/src/acquisition/panel.js.map +1 -0
- package/dist/src/acquisition/records.d.ts +24 -0
- package/dist/src/acquisition/records.js +127 -0
- package/dist/src/acquisition/records.js.map +1 -0
- package/dist/src/acquisition/remote-budget.d.ts +4 -0
- package/dist/src/acquisition/remote-budget.js +121 -0
- package/dist/src/acquisition/remote-budget.js.map +1 -0
- package/dist/src/acquisition/singleflight.d.ts +10 -0
- package/dist/src/acquisition/singleflight.js +75 -0
- package/dist/src/acquisition/singleflight.js.map +1 -0
- package/dist/src/acquisition/storyboard.d.ts +36 -0
- package/dist/src/acquisition/storyboard.js +324 -0
- package/dist/src/acquisition/storyboard.js.map +1 -0
- package/dist/src/acquisition/transcript.d.ts +25 -0
- package/dist/src/acquisition/transcript.js +367 -0
- package/dist/src/acquisition/transcript.js.map +1 -0
- package/dist/src/acquisition/transport-policy.d.ts +7 -0
- package/dist/src/acquisition/transport-policy.js +22 -0
- package/dist/src/acquisition/transport-policy.js.map +1 -0
- package/dist/src/acquisition/video-timing.d.ts +24 -0
- package/dist/src/acquisition/video-timing.js +249 -0
- package/dist/src/acquisition/video-timing.js.map +1 -0
- package/dist/src/app.d.ts +49 -0
- package/dist/src/app.js +31 -0
- package/dist/src/app.js.map +1 -0
- package/dist/src/cli/doctor.d.ts +24 -0
- package/dist/src/cli/doctor.js +368 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/main.d.ts +2 -0
- package/dist/src/cli/main.js +79 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/config.d.ts +36 -0
- package/dist/src/config.js +110 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/core/coverage.d.ts +20 -0
- package/dist/src/core/coverage.js +89 -0
- package/dist/src/core/coverage.js.map +1 -0
- package/dist/src/core/diagnostics.d.ts +58 -0
- package/dist/src/core/diagnostics.js +451 -0
- package/dist/src/core/diagnostics.js.map +1 -0
- package/dist/src/core/errors.d.ts +13 -0
- package/dist/src/core/errors.js +57 -0
- package/dist/src/core/errors.js.map +1 -0
- package/dist/src/core/frame-schedule.d.ts +16 -0
- package/dist/src/core/frame-schedule.js +52 -0
- package/dist/src/core/frame-schedule.js.map +1 -0
- package/dist/src/core/ids.d.ts +48 -0
- package/dist/src/core/ids.js +122 -0
- package/dist/src/core/ids.js.map +1 -0
- package/dist/src/core/model.d.ts +216 -0
- package/dist/src/core/model.js +2 -0
- package/dist/src/core/model.js.map +1 -0
- package/dist/src/core/request-key.d.ts +1 -0
- package/dist/src/core/request-key.js +8 -0
- package/dist/src/core/request-key.js.map +1 -0
- package/dist/src/core/search-limits.d.ts +11 -0
- package/dist/src/core/search-limits.js +13 -0
- package/dist/src/core/search-limits.js.map +1 -0
- package/dist/src/distribution/active.d.ts +20 -0
- package/dist/src/distribution/active.js +169 -0
- package/dist/src/distribution/active.js.map +1 -0
- package/dist/src/distribution/archive.d.ts +8 -0
- package/dist/src/distribution/archive.js +368 -0
- package/dist/src/distribution/archive.js.map +1 -0
- package/dist/src/distribution/download.d.ts +8 -0
- package/dist/src/distribution/download.js +93 -0
- package/dist/src/distribution/download.js.map +1 -0
- package/dist/src/distribution/host-registration.d.ts +7 -0
- package/dist/src/distribution/host-registration.js +64 -0
- package/dist/src/distribution/host-registration.js.map +1 -0
- package/dist/src/distribution/installer.d.ts +38 -0
- package/dist/src/distribution/installer.js +445 -0
- package/dist/src/distribution/installer.js.map +1 -0
- package/dist/src/distribution/integrity.d.ts +8 -0
- package/dist/src/distribution/integrity.js +131 -0
- package/dist/src/distribution/integrity.js.map +1 -0
- package/dist/src/distribution/lock.d.ts +14 -0
- package/dist/src/distribution/lock.js +136 -0
- package/dist/src/distribution/lock.js.map +1 -0
- package/dist/src/distribution/manifest.d.ts +46 -0
- package/dist/src/distribution/manifest.js +202 -0
- package/dist/src/distribution/manifest.js.map +1 -0
- package/dist/src/distribution/paths.d.ts +30 -0
- package/dist/src/distribution/paths.js +154 -0
- package/dist/src/distribution/paths.js.map +1 -0
- package/dist/src/distribution/platform.d.ts +15 -0
- package/dist/src/distribution/platform.js +76 -0
- package/dist/src/distribution/platform.js.map +1 -0
- package/dist/src/distribution/qualification.d.ts +26 -0
- package/dist/src/distribution/qualification.js +265 -0
- package/dist/src/distribution/qualification.js.map +1 -0
- package/dist/src/distribution/receipt.d.ts +52 -0
- package/dist/src/distribution/receipt.js +142 -0
- package/dist/src/distribution/receipt.js.map +1 -0
- package/dist/src/distribution/runtime.d.ts +8 -0
- package/dist/src/distribution/runtime.js +173 -0
- package/dist/src/distribution/runtime.js.map +1 -0
- package/dist/src/evidence/service.d.ts +959 -0
- package/dist/src/evidence/service.js +1455 -0
- package/dist/src/evidence/service.js.map +1 -0
- package/dist/src/evidence/state.d.ts +52 -0
- package/dist/src/evidence/state.js +362 -0
- package/dist/src/evidence/state.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcp/logo.d.ts +5 -0
- package/dist/src/mcp/logo.js +11 -0
- package/dist/src/mcp/logo.js.map +1 -0
- package/dist/src/mcp/projection.d.ts +4 -0
- package/dist/src/mcp/projection.js +144 -0
- package/dist/src/mcp/projection.js.map +1 -0
- package/dist/src/mcp/schemas.d.ts +1744 -0
- package/dist/src/mcp/schemas.js +662 -0
- package/dist/src/mcp/schemas.js.map +1 -0
- package/dist/src/mcp/server.d.ts +6 -0
- package/dist/src/mcp/server.js +470 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/stdio.d.ts +1 -0
- package/dist/src/mcp/stdio.js +36 -0
- package/dist/src/mcp/stdio.js.map +1 -0
- package/dist/src/remote/egress.d.ts +42 -0
- package/dist/src/remote/egress.js +611 -0
- package/dist/src/remote/egress.js.map +1 -0
- package/dist/src/remote/formats.d.ts +5 -0
- package/dist/src/remote/formats.js +30 -0
- package/dist/src/remote/formats.js.map +1 -0
- package/dist/src/remote/lease.d.ts +15 -0
- package/dist/src/remote/lease.js +2 -0
- package/dist/src/remote/lease.js.map +1 -0
- package/dist/src/remote/normalize.d.ts +14 -0
- package/dist/src/remote/normalize.js +243 -0
- package/dist/src/remote/normalize.js.map +1 -0
- package/dist/src/remote/policy.d.ts +13 -0
- package/dist/src/remote/policy.js +107 -0
- package/dist/src/remote/policy.js.map +1 -0
- package/dist/src/remote/worker.d.ts +14 -0
- package/dist/src/remote/worker.js +40 -0
- package/dist/src/remote/worker.js.map +1 -0
- package/dist/src/sources/candidates.d.ts +18 -0
- package/dist/src/sources/candidates.js +23 -0
- package/dist/src/sources/candidates.js.map +1 -0
- package/dist/src/sources/caption-tracks.d.ts +12 -0
- package/dist/src/sources/caption-tracks.js +75 -0
- package/dist/src/sources/caption-tracks.js.map +1 -0
- package/dist/src/sources/local.d.ts +42 -0
- package/dist/src/sources/local.js +203 -0
- package/dist/src/sources/local.js.map +1 -0
- package/dist/src/sources/metadata.d.ts +15 -0
- package/dist/src/sources/metadata.js +513 -0
- package/dist/src/sources/metadata.js.map +1 -0
- package/dist/src/sources/resolver.d.ts +22 -0
- package/dist/src/sources/resolver.js +363 -0
- package/dist/src/sources/resolver.js.map +1 -0
- package/dist/src/sources/timeline.d.ts +23 -0
- package/dist/src/sources/timeline.js +145 -0
- package/dist/src/sources/timeline.js.map +1 -0
- package/dist/src/sources/types.d.ts +67 -0
- package/dist/src/sources/types.js +2 -0
- package/dist/src/sources/types.js.map +1 -0
- package/dist/src/sources/youtube.d.ts +10 -0
- package/dist/src/sources/youtube.js +59 -0
- package/dist/src/sources/youtube.js.map +1 -0
- package/dist/src/store/blob-store.d.ts +20 -0
- package/dist/src/store/blob-store.js +156 -0
- package/dist/src/store/blob-store.js.map +1 -0
- package/dist/src/store/schema.d.ts +4 -0
- package/dist/src/store/schema.js +169 -0
- package/dist/src/store/schema.js.map +1 -0
- package/dist/src/store/sqlite-store.d.ts +47 -0
- package/dist/src/store/sqlite-store.js +545 -0
- package/dist/src/store/sqlite-store.js.map +1 -0
- package/dist/src/store/store.d.ts +138 -0
- package/dist/src/store/store.js +2 -0
- package/dist/src/store/store.js.map +1 -0
- package/dist/src/subprocess/ffmpeg.d.ts +18 -0
- package/dist/src/subprocess/ffmpeg.js +117 -0
- package/dist/src/subprocess/ffmpeg.js.map +1 -0
- package/dist/src/subprocess/ffprobe.d.ts +11 -0
- package/dist/src/subprocess/ffprobe.js +62 -0
- package/dist/src/subprocess/ffprobe.js.map +1 -0
- package/dist/src/subprocess/redaction.d.ts +3 -0
- package/dist/src/subprocess/redaction.js +31 -0
- package/dist/src/subprocess/redaction.js.map +1 -0
- package/dist/src/subprocess/remote-media.d.ts +3 -0
- package/dist/src/subprocess/remote-media.js +27 -0
- package/dist/src/subprocess/remote-media.js.map +1 -0
- package/dist/src/subprocess/runner.d.ts +23 -0
- package/dist/src/subprocess/runner.js +197 -0
- package/dist/src/subprocess/runner.js.map +1 -0
- package/dist/src/subprocess/versions.d.ts +8 -0
- package/dist/src/subprocess/versions.js +46 -0
- package/dist/src/subprocess/versions.js.map +1 -0
- package/dist/src/subprocess/ytdlp.d.ts +39 -0
- package/dist/src/subprocess/ytdlp.js +326 -0
- package/dist/src/subprocess/ytdlp.js.map +1 -0
- package/dist/src/version.d.ts +8 -0
- package/dist/src/version.js +44 -0
- package/dist/src/version.js.map +1 -0
- package/docs/ARCHITECTURE.md +273 -0
- package/docs/CONTRIBUTING.md +101 -0
- package/docs/EVIDENCE_MODEL.md +292 -0
- package/docs/PRODUCT_SCOPE.md +115 -0
- package/docs/SECURITY.md +182 -0
- package/docs/assets/architecture.png +0 -0
- package/docs/assets/contribution.png +0 -0
- package/docs/assets/evidence-model.png +0 -0
- package/docs/assets/product-scope.png +0 -0
- package/docs/assets/security.png +0 -0
- package/launcher-v1.mjs +430 -0
- package/package.json +45 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { ArtifactId, InvestigationRef, RemoteIdentity, SourceRef } from "../core/ids.js";
|
|
2
|
+
import type { AcquisitionMethod, ArtifactKind, ArtifactRole, SourceKind, TranscriptKind } from "../core/model.js";
|
|
3
|
+
export type StoredSource = Readonly<{
|
|
4
|
+
sourceRef: SourceRef;
|
|
5
|
+
kind: SourceKind;
|
|
6
|
+
identity: RemoteIdentity | Readonly<{
|
|
7
|
+
basis: "local";
|
|
8
|
+
pathDigest: string;
|
|
9
|
+
}>;
|
|
10
|
+
latestRevision: string;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
}>;
|
|
13
|
+
export type StoredSourceSnapshot = Readonly<{
|
|
14
|
+
sourceRef: SourceRef;
|
|
15
|
+
revision: string;
|
|
16
|
+
observedAt: string;
|
|
17
|
+
durationMs: number;
|
|
18
|
+
descriptor: Readonly<Record<string, unknown>>;
|
|
19
|
+
}>;
|
|
20
|
+
export type StoredSourceLocator = Readonly<{
|
|
21
|
+
sourceRef: SourceRef;
|
|
22
|
+
locatorDigest: string;
|
|
23
|
+
privateReopenLocator: string;
|
|
24
|
+
observedAt: string;
|
|
25
|
+
}>;
|
|
26
|
+
export type StoredInvestigation = Readonly<{
|
|
27
|
+
investigationRef: InvestigationRef;
|
|
28
|
+
sourceRef: SourceRef;
|
|
29
|
+
sourceRevision: string;
|
|
30
|
+
durationMs: number;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
}>;
|
|
34
|
+
export type StoredTrack = Readonly<{
|
|
35
|
+
id: string;
|
|
36
|
+
sourceRef: SourceRef;
|
|
37
|
+
sourceRevision: string;
|
|
38
|
+
language: string;
|
|
39
|
+
kind: TranscriptKind;
|
|
40
|
+
providerTrackId: string | null;
|
|
41
|
+
acquiredAt: string;
|
|
42
|
+
metadata: Readonly<Record<string, unknown>>;
|
|
43
|
+
}>;
|
|
44
|
+
export type StoredSegment = Readonly<{
|
|
45
|
+
id: number;
|
|
46
|
+
trackId: string;
|
|
47
|
+
startMs: number;
|
|
48
|
+
endMs: number;
|
|
49
|
+
text: string;
|
|
50
|
+
ordinal: number;
|
|
51
|
+
}>;
|
|
52
|
+
export type StoredArtifact = Readonly<{
|
|
53
|
+
artifactId: ArtifactId;
|
|
54
|
+
sourceRef: SourceRef;
|
|
55
|
+
sourceRevision: string;
|
|
56
|
+
kind: ArtifactKind;
|
|
57
|
+
role: ArtifactRole;
|
|
58
|
+
mimeType: string;
|
|
59
|
+
sha256: string;
|
|
60
|
+
byteSize: number;
|
|
61
|
+
blobPath: string;
|
|
62
|
+
startMs: number | null;
|
|
63
|
+
endMs: number | null;
|
|
64
|
+
params: Readonly<Record<string, unknown>>;
|
|
65
|
+
producer: Readonly<Record<string, unknown>>;
|
|
66
|
+
createdAt: string;
|
|
67
|
+
}>;
|
|
68
|
+
export type StoredAcquisition = Readonly<{
|
|
69
|
+
id: string;
|
|
70
|
+
sourceRef: SourceRef;
|
|
71
|
+
sourceRevision: string;
|
|
72
|
+
investigationRef: InvestigationRef | null;
|
|
73
|
+
operation: string;
|
|
74
|
+
requestKey: string;
|
|
75
|
+
method: AcquisitionMethod;
|
|
76
|
+
status: "running" | "succeeded" | "failed" | "cancelled";
|
|
77
|
+
startedAt: string;
|
|
78
|
+
completedAt: string | null;
|
|
79
|
+
wallMs: number | null;
|
|
80
|
+
networkBytes: number | null;
|
|
81
|
+
networkAccountingComplete: boolean;
|
|
82
|
+
errorCode: string | null;
|
|
83
|
+
metadata: Readonly<Record<string, unknown>>;
|
|
84
|
+
}>;
|
|
85
|
+
export type StoredPresentation = Readonly<{
|
|
86
|
+
id: string;
|
|
87
|
+
investigationRef: InvestigationRef;
|
|
88
|
+
artifactId: ArtifactId | null;
|
|
89
|
+
modality: "transcript" | "visual" | "audio";
|
|
90
|
+
evidenceKind: "transcript_search" | "transcript_range" | "point" | "sparse" | "ordered_points" | "audio";
|
|
91
|
+
startMs: number | null;
|
|
92
|
+
endMs: number | null;
|
|
93
|
+
pointsMs: readonly number[] | null;
|
|
94
|
+
metadata: Readonly<Record<string, unknown>>;
|
|
95
|
+
presentedAt: string;
|
|
96
|
+
}>;
|
|
97
|
+
export interface UrmaStore {
|
|
98
|
+
readonly ftsEnabled: boolean;
|
|
99
|
+
close(): void;
|
|
100
|
+
putSourceSnapshot(input: Readonly<{
|
|
101
|
+
source: Omit<StoredSource, "createdAt">;
|
|
102
|
+
snapshot: StoredSourceSnapshot;
|
|
103
|
+
locators: readonly StoredSourceLocator[];
|
|
104
|
+
}>): StoredSourceSnapshot;
|
|
105
|
+
getSource(sourceRef: SourceRef): StoredSource | null;
|
|
106
|
+
getSnapshot(sourceRef: SourceRef, revision: string): StoredSourceSnapshot | null;
|
|
107
|
+
getLatestSnapshot(sourceRef: SourceRef): StoredSourceSnapshot | null;
|
|
108
|
+
getLocator(sourceRef: SourceRef, locatorDigest: string): StoredSourceLocator | null;
|
|
109
|
+
listSourceLocators(sourceRef: SourceRef): StoredSourceLocator[];
|
|
110
|
+
findSourcesByLocatorDigest(locatorDigest: string): StoredSource[];
|
|
111
|
+
createInvestigation(investigation: StoredInvestigation): void;
|
|
112
|
+
getInvestigation(investigationRef: InvestigationRef): StoredInvestigation | null;
|
|
113
|
+
putTranscript(track: StoredTrack, segments: readonly Omit<StoredSegment, "id">[]): void;
|
|
114
|
+
listTranscriptTracks(sourceRef: SourceRef, revision: string): StoredTrack[];
|
|
115
|
+
listTranscriptSegments(trackId: string, startMs?: number, endMs?: number): StoredSegment[];
|
|
116
|
+
searchTranscriptSegments(trackId: string, query: string, limit: number): StoredSegment[];
|
|
117
|
+
putArtifact(artifact: StoredArtifact, request?: Readonly<{
|
|
118
|
+
requestKey: string;
|
|
119
|
+
operation: string;
|
|
120
|
+
}>, parents?: readonly ArtifactId[]): void;
|
|
121
|
+
getArtifact(artifactId: ArtifactId): StoredArtifact | null;
|
|
122
|
+
getArtifactByRequest(requestKey: string): StoredArtifact | null;
|
|
123
|
+
listArtifacts(sourceRef: SourceRef, revision: string): StoredArtifact[];
|
|
124
|
+
beginAcquisition(acquisition: StoredAcquisition): void;
|
|
125
|
+
finishAcquisition(id: string, result: Pick<StoredAcquisition, "status" | "completedAt" | "wallMs" | "networkBytes" | "networkAccountingComplete" | "errorCode" | "metadata">): void;
|
|
126
|
+
listAcquisitions(investigationRef: InvestigationRef): StoredAcquisition[];
|
|
127
|
+
addPresentation(presentation: StoredPresentation): void;
|
|
128
|
+
listPresentations(investigationRef: InvestigationRef): StoredPresentation[];
|
|
129
|
+
isArtifactPresented(investigationRef: InvestigationRef, artifactId: ArtifactId): boolean;
|
|
130
|
+
listPresentedArtifactIds(investigationRef: InvestigationRef): ArtifactId[];
|
|
131
|
+
cacheStats(): {
|
|
132
|
+
sources: number;
|
|
133
|
+
investigations: number;
|
|
134
|
+
artifacts: number;
|
|
135
|
+
artifactBytes: number;
|
|
136
|
+
acquisitions: number;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/store/store.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { UrmaConfig } from "../config.js";
|
|
2
|
+
import type { RemoteOperationContext } from "../remote/worker.js";
|
|
3
|
+
import { type ProcessResult, type RunOptions } from "./runner.js";
|
|
4
|
+
export declare class Ffmpeg {
|
|
5
|
+
readonly config: UrmaConfig;
|
|
6
|
+
readonly remoteContext: RemoteOperationContext | null;
|
|
7
|
+
readonly runner: (executable: string, args: readonly string[], options?: RunOptions) => Promise<ProcessResult>;
|
|
8
|
+
constructor(config: UrmaConfig, remoteContext?: RemoteOperationContext | null, runner?: (executable: string, args: readonly string[], options?: RunOptions) => Promise<ProcessResult>);
|
|
9
|
+
version(signal?: AbortSignal): Promise<string>;
|
|
10
|
+
extractJpeg(media: string, atMs: number, output: string, signal?: AbortSignal): Promise<void>;
|
|
11
|
+
cropJpeg(image: string, crop: {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
}, output: string, signal?: AbortSignal): Promise<void>;
|
|
17
|
+
validateJpeg(file: string): Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { readFile, rm, stat } from "node:fs/promises";
|
|
2
|
+
import { UrmaError } from "../core/errors.js";
|
|
3
|
+
import { runChecked } from "./runner.js";
|
|
4
|
+
import { remoteMediaInputArgs } from "./remote-media.js";
|
|
5
|
+
import { verifyRuntimeTool } from "../distribution/integrity.js";
|
|
6
|
+
export class Ffmpeg {
|
|
7
|
+
config;
|
|
8
|
+
remoteContext;
|
|
9
|
+
runner;
|
|
10
|
+
constructor(config, remoteContext = null, runner = runChecked) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.remoteContext = remoteContext;
|
|
13
|
+
this.runner = runner;
|
|
14
|
+
}
|
|
15
|
+
async version(signal) {
|
|
16
|
+
await verifyRuntimeTool(this.config, "ffmpeg");
|
|
17
|
+
const result = await this.runner(this.config.ffmpeg, ["-version"], {
|
|
18
|
+
timeoutMs: 10_000,
|
|
19
|
+
maxStdoutBytes: 256 * 1024,
|
|
20
|
+
maxStderrBytes: 256 * 1024,
|
|
21
|
+
signal,
|
|
22
|
+
debug: this.config.debug,
|
|
23
|
+
label: "ffmpeg",
|
|
24
|
+
diagnosticRole: "binary-version",
|
|
25
|
+
});
|
|
26
|
+
return result.stdout.toString("utf8").split(/\r?\n/, 1)[0] ?? "unknown";
|
|
27
|
+
}
|
|
28
|
+
async extractJpeg(media, atMs, output, signal) {
|
|
29
|
+
await verifyRuntimeTool(this.config, "ffmpeg");
|
|
30
|
+
await rm(output, { force: true });
|
|
31
|
+
const remoteArgs = await remoteMediaInputArgs(media, this.remoteContext);
|
|
32
|
+
await this.runner(this.config.ffmpeg, [
|
|
33
|
+
...remoteArgs,
|
|
34
|
+
"-v",
|
|
35
|
+
"error",
|
|
36
|
+
"-ss",
|
|
37
|
+
(atMs / 1000).toFixed(3),
|
|
38
|
+
"-i",
|
|
39
|
+
media,
|
|
40
|
+
"-frames:v",
|
|
41
|
+
"1",
|
|
42
|
+
"-pix_fmt",
|
|
43
|
+
"yuvj420p",
|
|
44
|
+
"-q:v",
|
|
45
|
+
"2",
|
|
46
|
+
"-y",
|
|
47
|
+
output,
|
|
48
|
+
], {
|
|
49
|
+
timeoutMs: this.config.limits.mediaTimeoutMs,
|
|
50
|
+
maxStdoutBytes: 512 * 1024,
|
|
51
|
+
maxStderrBytes: this.config.limits.subprocessStderrBytes,
|
|
52
|
+
signal,
|
|
53
|
+
debug: this.config.debug,
|
|
54
|
+
label: "ffmpeg",
|
|
55
|
+
diagnosticRole: "ffmpeg-exact-frame",
|
|
56
|
+
});
|
|
57
|
+
try {
|
|
58
|
+
const info = await stat(output);
|
|
59
|
+
if (!info.isFile() || info.size < 1)
|
|
60
|
+
throw new Error("empty output");
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error instanceof UrmaError)
|
|
64
|
+
throw error;
|
|
65
|
+
throw new UrmaError("FRAME_EXTRACTION_FAILED", "ffmpeg completed without producing a JPEG frame; verify that the requested timestamp is present in the media", { retryable: true, cause: error });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async cropJpeg(image, crop, output, signal) {
|
|
69
|
+
await verifyRuntimeTool(this.config, "ffmpeg");
|
|
70
|
+
const remoteArgs = await remoteMediaInputArgs(image, this.remoteContext);
|
|
71
|
+
await this.runner(this.config.ffmpeg, [
|
|
72
|
+
...remoteArgs,
|
|
73
|
+
"-v",
|
|
74
|
+
"error",
|
|
75
|
+
"-i",
|
|
76
|
+
image,
|
|
77
|
+
"-vf",
|
|
78
|
+
`crop=${crop.width}:${crop.height}:${crop.x}:${crop.y}`,
|
|
79
|
+
"-frames:v",
|
|
80
|
+
"1",
|
|
81
|
+
"-pix_fmt",
|
|
82
|
+
"yuvj420p",
|
|
83
|
+
"-q:v",
|
|
84
|
+
"2",
|
|
85
|
+
"-y",
|
|
86
|
+
output,
|
|
87
|
+
], {
|
|
88
|
+
timeoutMs: this.config.limits.mediaTimeoutMs,
|
|
89
|
+
maxStdoutBytes: 512 * 1024,
|
|
90
|
+
maxStderrBytes: this.config.limits.subprocessStderrBytes,
|
|
91
|
+
signal,
|
|
92
|
+
debug: this.config.debug,
|
|
93
|
+
label: "ffmpeg",
|
|
94
|
+
diagnosticRole: "ffmpeg-panel",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async validateJpeg(file) {
|
|
98
|
+
let bytes;
|
|
99
|
+
try {
|
|
100
|
+
bytes = await readFile(file);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
104
|
+
throw new UrmaError("FRAME_EXTRACTION_FAILED", "Expected JPEG output was not produced by ffmpeg; verify that the requested timestamp is present in the media", { retryable: true, cause: error });
|
|
105
|
+
}
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
if (bytes.length < 4 ||
|
|
109
|
+
bytes[0] !== 0xff ||
|
|
110
|
+
bytes[1] !== 0xd8 ||
|
|
111
|
+
bytes.at(-2) !== 0xff ||
|
|
112
|
+
bytes.at(-1) !== 0xd9) {
|
|
113
|
+
throw new UrmaError("MEDIA_INVALID", `Extracted JPEG failed marker validation; retry acquisition from source media`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=ffmpeg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../../../src/subprocess/ffmpeg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAuC,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,MAAM,OAAO,MAAM;IAEN,MAAM;IACN,aAAa;IACb,MAAM;IAHjB,YACW,MAAkB,EAClB,aAAa,GAAkC,IAAI,EACnD,MAAM,GAIe,UAAU;sBAN/B,MAAM;6BACN,aAAa;sBACb,MAAM;IAKd,CAAC;IACJ,KAAK,CAAC,OAAO,CAAC,MAAoB;QAChC,MAAM,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE;YACjE,SAAS,EAAE,MAAM;YACjB,cAAc,EAAE,GAAG,GAAG,IAAI;YAC1B,cAAc,EAAE,GAAG,GAAG,IAAI;YAC1B,MAAM;YACN,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,KAAK,EAAE,QAAQ;YACf,cAAc,EAAE,gBAAgB;SACjC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAC1E,CAAC;IACD,KAAK,CAAC,WAAW,CACf,KAAa,EACb,IAAY,EACZ,MAAc,EACd,MAAoB;QAEpB,MAAM,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAClC,MAAM,UAAU,GAAG,MAAM,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACzE,MAAM,IAAI,CAAC,MAAM,CACf,IAAI,CAAC,MAAM,CAAC,MAAM,EAClB;YACE,GAAG,UAAU;YACb,IAAI;YACJ,OAAO;YACP,KAAK;YACL,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;YACxB,IAAI;YACJ,KAAK;YACL,WAAW;YACX,GAAG;YACH,UAAU;YACV,UAAU;YACV,MAAM;YACN,GAAG;YACH,IAAI;YACJ,MAAM;SACP,EACD;YACE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc;YAC5C,cAAc,EAAE,GAAG,GAAG,IAAI;YAC1B,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB;YACxD,MAAM;YACN,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,KAAK,EAAE,QAAQ;YACf,cAAc,EAAE,oBAAoB;SACrC,CACF,CAAC;QACF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,SAAS;gBAAE,MAAM,KAAK,CAAC;YAC5C,MAAM,IAAI,SAAS,CACjB,yBAAyB,EACzB,8GAA8G,EAC9G,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAClC,CAAC;QACJ,CAAC;IACH,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,KAAa,EACb,IAA6D,EAC7D,MAAc,EACd,MAAoB;QAEpB,MAAM,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,MAAM,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACzE,MAAM,IAAI,CAAC,MAAM,CACf,IAAI,CAAC,MAAM,CAAC,MAAM,EAClB;YACE,GAAG,UAAU;YACb,IAAI;YACJ,OAAO;YACP,IAAI;YACJ,KAAK;YACL,KAAK;YACL,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE;YACvD,WAAW;YACX,GAAG;YACH,UAAU;YACV,UAAU;YACV,MAAM;YACN,GAAG;YACH,IAAI;YACJ,MAAM;SACP,EACD;YACE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc;YAC5C,cAAc,EAAE,GAAG,GAAG,IAAI;YAC1B,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB;YACxD,MAAM;YACN,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,KAAK,EAAE,QAAQ;YACf,cAAc,EAAE,cAAc;SAC/B,CACF,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,YAAY,CAAC,IAAY;QAC7B,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IACE,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EACpE,CAAC;gBACD,MAAM,IAAI,SAAS,CACjB,yBAAyB,EACzB,8GAA8G,EAC9G,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAClC,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IACE,KAAK,CAAC,MAAM,GAAG,CAAC;YAChB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;YACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;YACjB,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;YACrB,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EACrB,CAAC;YACD,MAAM,IAAI,SAAS,CACjB,eAAe,EACf,8EAA8E,CAC/E,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { UrmaConfig } from "../config.js";
|
|
2
|
+
import type { RemoteOperationContext } from "../remote/worker.js";
|
|
3
|
+
import { type ProcessResult, type RunOptions } from "./runner.js";
|
|
4
|
+
export declare class Ffprobe {
|
|
5
|
+
readonly config: UrmaConfig;
|
|
6
|
+
readonly remoteContext: RemoteOperationContext | null;
|
|
7
|
+
readonly runner: (executable: string, args: readonly string[], options?: RunOptions) => Promise<ProcessResult>;
|
|
8
|
+
constructor(config: UrmaConfig, remoteContext?: RemoteOperationContext | null, runner?: (executable: string, args: readonly string[], options?: RunOptions) => Promise<ProcessResult>);
|
|
9
|
+
version(signal?: AbortSignal): Promise<string>;
|
|
10
|
+
inspect(media: string, signal?: AbortSignal): Promise<Record<string, unknown>>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { UrmaError } from "../core/errors.js";
|
|
2
|
+
import { runChecked } from "./runner.js";
|
|
3
|
+
import { remoteMediaInputArgs } from "./remote-media.js";
|
|
4
|
+
import { verifyRuntimeTool } from "../distribution/integrity.js";
|
|
5
|
+
export class Ffprobe {
|
|
6
|
+
config;
|
|
7
|
+
remoteContext;
|
|
8
|
+
runner;
|
|
9
|
+
constructor(config, remoteContext = null, runner = runChecked) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.remoteContext = remoteContext;
|
|
12
|
+
this.runner = runner;
|
|
13
|
+
}
|
|
14
|
+
async version(signal) {
|
|
15
|
+
await verifyRuntimeTool(this.config, "ffprobe");
|
|
16
|
+
const result = await this.runner(this.config.ffprobe, ["-version"], {
|
|
17
|
+
timeoutMs: 10_000,
|
|
18
|
+
maxStdoutBytes: 256 * 1024,
|
|
19
|
+
maxStderrBytes: 256 * 1024,
|
|
20
|
+
signal,
|
|
21
|
+
debug: this.config.debug,
|
|
22
|
+
label: "ffprobe",
|
|
23
|
+
diagnosticRole: "binary-version",
|
|
24
|
+
});
|
|
25
|
+
return result.stdout.toString("utf8").split(/\r?\n/, 1)[0] ?? "unknown";
|
|
26
|
+
}
|
|
27
|
+
async inspect(media, signal) {
|
|
28
|
+
await verifyRuntimeTool(this.config, "ffprobe");
|
|
29
|
+
const remoteArgs = await remoteMediaInputArgs(media, this.remoteContext);
|
|
30
|
+
const result = await this.runner(this.config.ffprobe, [
|
|
31
|
+
...remoteArgs,
|
|
32
|
+
"-v",
|
|
33
|
+
"error",
|
|
34
|
+
"-show_format",
|
|
35
|
+
"-show_streams",
|
|
36
|
+
"-of",
|
|
37
|
+
"json",
|
|
38
|
+
media,
|
|
39
|
+
], {
|
|
40
|
+
timeoutMs: this.config.limits.metadataTimeoutMs,
|
|
41
|
+
maxStdoutBytes: this.config.limits.subprocessStdoutBytes,
|
|
42
|
+
maxStderrBytes: this.config.limits.subprocessStderrBytes,
|
|
43
|
+
signal,
|
|
44
|
+
debug: this.config.debug,
|
|
45
|
+
label: "ffprobe",
|
|
46
|
+
diagnosticRole: "ffprobe-media-probe",
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(result.stdout.toString("utf8"));
|
|
50
|
+
if (typeof parsed !== "object" ||
|
|
51
|
+
parsed === null ||
|
|
52
|
+
Array.isArray(parsed)) {
|
|
53
|
+
throw new Error("not an object");
|
|
54
|
+
}
|
|
55
|
+
return parsed;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
throw new UrmaError("MEDIA_INVALID", `ffprobe returned invalid JSON for the requested media; verify the source is a supported video`, { cause: error });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=ffprobe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffprobe.js","sourceRoot":"","sources":["../../../src/subprocess/ffprobe.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAuC,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,MAAM,OAAO,OAAO;IAEP,MAAM;IACN,aAAa;IACb,MAAM;IAHjB,YACW,MAAkB,EAClB,aAAa,GAAkC,IAAI,EACnD,MAAM,GAIe,UAAU;sBAN/B,MAAM;6BACN,aAAa;sBACb,MAAM;IAKd,CAAC;IACJ,KAAK,CAAC,OAAO,CAAC,MAAoB;QAChC,MAAM,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE;YAClE,SAAS,EAAE,MAAM;YACjB,cAAc,EAAE,GAAG,GAAG,IAAI;YAC1B,cAAc,EAAE,GAAG,GAAG,IAAI;YAC1B,MAAM;YACN,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,KAAK,EAAE,SAAS;YAChB,cAAc,EAAE,gBAAgB;SACjC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAC1E,CAAC;IACD,KAAK,CAAC,OAAO,CACX,KAAa,EACb,MAAoB;QAEpB,MAAM,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,MAAM,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACzE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAC9B,IAAI,CAAC,MAAM,CAAC,OAAO,EACnB;YACE,GAAG,UAAU;YACb,IAAI;YACJ,OAAO;YACP,cAAc;YACd,eAAe;YACf,KAAK;YACL,MAAM;YACN,KAAK;SACN,EACD;YACE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,iBAAiB;YAC/C,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB;YACxD,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB;YACxD,MAAM;YACN,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,KAAK,EAAE,SAAS;YAChB,cAAc,EAAE,qBAAqB;SACtC,CACF,CAAC;QACF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAY,CAAC;YACrE,IACE,OAAO,MAAM,KAAK,QAAQ;gBAC1B,MAAM,KAAK,IAAI;gBACf,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EACrB,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;YACnC,CAAC;YACD,OAAO,MAAiC,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,SAAS,CACjB,eAAe,EACf,+FAA+F,EAC/F,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const URL_PATTERN = /https?:\/\/[^\s"'<>]+/gi;
|
|
2
|
+
const SIGNED_QUERY_FRAGMENT_PATTERN = /(^|[\s"'(])\?(?=[^\s"'<>]*(?:sig(?:nature)?|token|expire|expires|hdnts|auth|authorization|x-amz-[^=]+|x-goog-[^=]+)=)[^\s"'<>]*/giu;
|
|
3
|
+
export function redactText(value) {
|
|
4
|
+
return value.replace(URL_PATTERN, (raw) => {
|
|
5
|
+
try {
|
|
6
|
+
const parsed = new URL(raw);
|
|
7
|
+
if ([
|
|
8
|
+
"youtube.com",
|
|
9
|
+
"www.youtube.com",
|
|
10
|
+
"m.youtube.com",
|
|
11
|
+
"youtu.be",
|
|
12
|
+
].includes(parsed.hostname.toLowerCase())) {
|
|
13
|
+
return `${parsed.protocol}//${parsed.host}${parsed.pathname}[query-redacted]`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
/* replace malformed URL-shaped diagnostics wholesale */
|
|
18
|
+
}
|
|
19
|
+
return "[remote-url-redacted]";
|
|
20
|
+
}).replace(SIGNED_QUERY_FRAGMENT_PATTERN, "$1[query-redacted]");
|
|
21
|
+
}
|
|
22
|
+
export function redactModelText(value) {
|
|
23
|
+
return redactText(value)
|
|
24
|
+
.replace(/[A-Za-z]:(?:\\{1,2}|\/)[^\s"'<>]*/g, "[local-path-redacted]")
|
|
25
|
+
.replace(/(^|[\s"'(])\/(?:[^\s"'<>]+\/)*[^\s"'<>]*/g, (_match, prefix) => `${prefix}[local-path-redacted]`)
|
|
26
|
+
.replace(/(?:\\\\|\/\/)[^\s"'<>]*/g, "[local-path-redacted]");
|
|
27
|
+
}
|
|
28
|
+
export function redactArgs(args) {
|
|
29
|
+
return args.map((argument) => redactText(argument));
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=redaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.js","sourceRoot":"","sources":["../../../src/subprocess/redaction.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,yBAAyB,CAAC;AAC9C,MAAM,6BAA6B,GAAG,oIAAoI,CAAC;AAE3K,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IACE;gBACE,aAAa;gBACb,iBAAiB;gBACjB,eAAe;gBACf,UAAU;aACX,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,EACzC,CAAC;gBACD,OAAO,GAAG,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,kBAAkB,CAAC;YAChF,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wDAAwD;QAC1D,CAAC;QACD,OAAO,uBAAuB,CAAC;IACjC,CAAC,CAAC,CAAC,OAAO,CAAC,6BAA6B,EAAE,oBAAoB,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,UAAU,CAAC,KAAK,CAAC;SACrB,OAAO,CAAC,oCAAoC,EAAE,uBAAuB,CAAC;SACtE,OAAO,CACN,2CAA2C,EAC3C,CAAC,MAAc,EAAE,MAAc,EAAE,EAAE,CAAC,GAAG,MAAM,uBAAuB,CACrE;SACA,OAAO,CAAC,0BAA0B,EAAE,uBAAuB,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type RemoteOperationContext } from "../remote/worker.js";
|
|
2
|
+
export declare function mediaInputKind(value: string): "local" | "remote";
|
|
3
|
+
export declare function remoteMediaInputArgs(value: string, context: RemoteOperationContext | null | undefined): Promise<string[]>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { assertRemoteTargetAllowed } from "../remote/egress.js";
|
|
2
|
+
import { ensureRemoteProxy } from "../remote/worker.js";
|
|
3
|
+
import { UrmaError } from "../core/errors.js";
|
|
4
|
+
function isWindowsDrivePath(value) {
|
|
5
|
+
return /^[A-Za-z]:[\\/]/u.test(value);
|
|
6
|
+
}
|
|
7
|
+
export function mediaInputKind(value) {
|
|
8
|
+
if (/^https?:\/\//iu.test(value))
|
|
9
|
+
return "remote";
|
|
10
|
+
if (!isWindowsDrivePath(value) && /^[A-Za-z][A-Za-z0-9+.-]*:/u.test(value)) {
|
|
11
|
+
throw new UrmaError("UNSUPPORTED_SOURCE", "Media subprocesses accept local paths or HTTP(S) through Urma's Safe Proxy; the supplied protocol is unsupported");
|
|
12
|
+
}
|
|
13
|
+
return "local";
|
|
14
|
+
}
|
|
15
|
+
export async function remoteMediaInputArgs(value, context) {
|
|
16
|
+
if (mediaInputKind(value) !== "remote")
|
|
17
|
+
return [];
|
|
18
|
+
assertRemoteTargetAllowed({ url: value, purpose: "input" });
|
|
19
|
+
const proxyUrl = await ensureRemoteProxy(context);
|
|
20
|
+
return [
|
|
21
|
+
"-protocol_whitelist",
|
|
22
|
+
"http,https,tcp,tls,httpproxy",
|
|
23
|
+
"-http_proxy",
|
|
24
|
+
proxyUrl,
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=remote-media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-media.js","sourceRoot":"","sources":["../../../src/subprocess/remote-media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAA+B,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAClD,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,SAAS,CACjB,oBAAoB,EACpB,kHAAkH,CACnH,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAa,EACb,OAAkD;IAElD,IAAI,cAAc,CAAC,KAAK,CAAC,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAClD,yBAAyB,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAClD,OAAO;QACL,qBAAqB;QACrB,8BAA8B;QAC9B,aAAa;QACb,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ProcessResult = Readonly<{
|
|
2
|
+
executable: string;
|
|
3
|
+
args: readonly string[];
|
|
4
|
+
code: number;
|
|
5
|
+
stdout: Buffer;
|
|
6
|
+
stderr: Buffer;
|
|
7
|
+
wallMs: number;
|
|
8
|
+
}>;
|
|
9
|
+
export type RunOptions = Readonly<{
|
|
10
|
+
cwd?: string | undefined;
|
|
11
|
+
env?: NodeJS.ProcessEnv | undefined;
|
|
12
|
+
timeoutMs?: number | undefined;
|
|
13
|
+
maxStdoutBytes?: number | undefined;
|
|
14
|
+
maxStderrBytes?: number | undefined;
|
|
15
|
+
signal?: AbortSignal | undefined;
|
|
16
|
+
debug?: boolean | undefined;
|
|
17
|
+
label?: string | undefined;
|
|
18
|
+
diagnosticRole?: string | undefined;
|
|
19
|
+
}>;
|
|
20
|
+
/** Keep credentials, proxy settings, hooks, browser paths, and host state out of child processes */
|
|
21
|
+
export declare function allowlistedEnvironment(input?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
22
|
+
export declare function runProcess(executable: string, args: readonly string[], options?: RunOptions): Promise<ProcessResult>;
|
|
23
|
+
export declare function runChecked(executable: string, args: readonly string[], options?: RunOptions): Promise<ProcessResult>;
|