@minicor/mcp-server 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -2
- package/dist/__tests__/recording-frames.test.js +42 -1
- package/dist/__tests__/recording-frames.test.js.map +1 -1
- package/dist/__tests__/seeer-client.test.d.ts +2 -0
- package/dist/__tests__/seeer-client.test.d.ts.map +1 -0
- package/dist/__tests__/seeer-client.test.js +57 -0
- package/dist/__tests__/seeer-client.test.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/lib.js +1 -1
- package/dist/recording-frames.d.ts +82 -9
- package/dist/recording-frames.d.ts.map +1 -1
- package/dist/recording-frames.js +254 -32
- package/dist/recording-frames.js.map +1 -1
- package/dist/seeer-client.d.ts +173 -0
- package/dist/seeer-client.d.ts.map +1 -0
- package/dist/seeer-client.js +181 -0
- package/dist/seeer-client.js.map +1 -0
- package/dist/server-surface.d.ts.map +1 -1
- package/dist/server-surface.js +2 -0
- package/dist/server-surface.js.map +1 -1
- package/dist/tools/core.d.ts.map +1 -1
- package/dist/tools/core.js +189 -22
- package/dist/tools/core.js.map +1 -1
- package/dist/tools/recording-common.d.ts +11 -0
- package/dist/tools/recording-common.d.ts.map +1 -0
- package/dist/tools/recording-common.js +15 -0
- package/dist/tools/recording-common.js.map +1 -0
- package/dist/tools/recording.d.ts +3 -0
- package/dist/tools/recording.d.ts.map +1 -0
- package/dist/tools/recording.js +237 -0
- package/dist/tools/recording.js.map +1 -0
- package/dist/tools/workflow-ops.d.ts.map +1 -1
- package/dist/tools/workflow-ops.js +79 -5
- package/dist/tools/workflow-ops.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -270,7 +270,7 @@ After all steps pass individually:
|
|
|
270
270
|
|
|
271
271
|
Then close the loop at the job level:
|
|
272
272
|
|
|
273
|
-
- Point the job's workflow step at the finished `workflowId` (`update_job variant=draft`). If the workflow was edited in Dev Mode, `dev_mode_publish` first - jobs execute published workflows, not
|
|
273
|
+
- Point the job's workflow step at the finished `workflowId` (`update_job variant=draft`). If the workflow was edited in Dev Mode, `dev_mode_publish` first - jobs execute published workflows, not drafts.
|
|
274
274
|
- `run_tests variant=draft` - the test cases from Phase 3 are the pass/fail verdict for the build
|
|
275
275
|
- On a red case, `resolve_job_state` / `inspect_job_execution` locate the failing step; replay just that slice with `run_job` (`fromStepId` + `seedExecutionId`) or drop back into the workflow, fix, re-run
|
|
276
276
|
- When the suite is green, `publish_job` puts it live at `/m/:slug/:path`
|
|
@@ -345,7 +345,7 @@ You work **backwards from the job's test cases**. The job's test suite is the ma
|
|
|
345
345
|
seedExecutionId=<failed execution> (seeds ctx so mid-graph starts
|
|
346
346
|
resolve earlier steps' values).
|
|
347
347
|
5b. Workflow-level (microscope) - the failing step's workflowId -> dev_mode_load,
|
|
348
|
-
fix/run the
|
|
348
|
+
fix/run the draft's flow steps (dev_mode_run needs vmId),
|
|
349
349
|
dev_mode_publish - jobs execute PUBLISHED workflows.
|
|
350
350
|
6. PUBLISH - when run_tests variant=draft is green, publish_job promotes the draft;
|
|
351
351
|
runtime traffic at /m/:slug serves it immediately.
|
|
@@ -686,6 +686,19 @@ Jobs/middleware base resolution (precedence: **proxy > direct > default**):
|
|
|
686
686
|
| `MIDDLEWARE_SERVICE_URL_US` | Direct middleware-service base for US (overrides the generic one) | unset |
|
|
687
687
|
| `MIDDLEWARE_SERVICE_URL_CA` | Direct middleware-service base for CA (overrides the generic one) | unset |
|
|
688
688
|
| `EXPERIMENTAL_USE_CODE_MODE` | Expose the experimental single `codemode` tool surface | unset (standard tools) |
|
|
689
|
+
| `SEEER_SERVICE_PROXY_BASE` | Override the frontend origin fronting the video-tool proxy (auth = user bearer, like the agents/stitchy proxies) | derived from API base |
|
|
690
|
+
| `SEEER_SERVICE_PROXY_PREFIX` | video-tool proxy path prefix | `/api/video-tool` |
|
|
691
|
+
| `SEEER_SERVICE_URL` | Direct video-tool service URL (bypasses the frontend proxy) | unset |
|
|
692
|
+
| `SEEER_SERVICE_TOKEN` | App token for direct mode (sent as X-API-Key) | unset |
|
|
693
|
+
| `SEEER_SERVICE_ID_TOKEN` | Static Google identity token for IAM-gated Cloud Run (local testing) | unset |
|
|
694
|
+
| `SEEER_SERVICE_USE_GCP_IDENTITY` | Set to 1 to mint identity tokens from the GCP metadata server | unset |
|
|
695
|
+
|
|
696
|
+
The video-tool (seeer) service needs **no configuration** against the standard
|
|
697
|
+
Laminar backends: the frontend proxy origin is derived from the region's API
|
|
698
|
+
base (`api.laminar.run` → `app.laminar.run`, `ca.api.laminar.run` →
|
|
699
|
+
`ca.app.laminar.run`). The env vars above only override this for dev/local
|
|
700
|
+
setups (a localhost backend has no derivable frontend, so set
|
|
701
|
+
`SEEER_SERVICE_PROXY_BASE` or `SEEER_SERVICE_URL` there).
|
|
689
702
|
|
|
690
703
|
When none are set, Jobs calls the region's public middleware-service Cloud Run directly. To route through the frontend (once it deploys an `/api/middleware/[...path]` proxy), set `MIDDLEWARE_SERVICE_PROXY_BASE` (or the per-region variants).
|
|
691
704
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { computeSampleTimestamps, buildScaleFilter, runCommand, } from "../recording-frames.js";
|
|
2
|
+
import { computeSampleTimestamps, computeRangeTimestamps, buildScaleFilter, buildCropFilter, cacheKeyForUrl, runCommand, } from "../recording-frames.js";
|
|
3
3
|
describe("computeSampleTimestamps", () => {
|
|
4
4
|
it("returns evenly-spaced, centered timestamps within the duration", () => {
|
|
5
5
|
expect(computeSampleTimestamps(10, 4)).toEqual([1.25, 3.75, 6.25, 8.75]);
|
|
@@ -22,6 +22,47 @@ describe("computeSampleTimestamps", () => {
|
|
|
22
22
|
expect(computeSampleTimestamps(Number.NaN, 4)).toEqual([]);
|
|
23
23
|
});
|
|
24
24
|
});
|
|
25
|
+
describe("computeRangeTimestamps", () => {
|
|
26
|
+
it("samples the window at the requested fps, inclusive of both ends", () => {
|
|
27
|
+
expect(computeRangeTimestamps(10, 14, 1, 16)).toEqual([10, 11, 12, 13, 14]);
|
|
28
|
+
});
|
|
29
|
+
it("falls back to even spacing when fps would exceed maxFrames", () => {
|
|
30
|
+
const ts = computeRangeTimestamps(0, 30, 2, 4);
|
|
31
|
+
expect(ts).toHaveLength(4);
|
|
32
|
+
expect(ts[0]).toBe(0);
|
|
33
|
+
expect(ts[3]).toBe(30);
|
|
34
|
+
});
|
|
35
|
+
it("returns a single frame for a zero-ish span with n=1", () => {
|
|
36
|
+
expect(computeRangeTimestamps(5, 5.4, 1, 16)).toEqual([5]);
|
|
37
|
+
});
|
|
38
|
+
it("returns empty for invalid input", () => {
|
|
39
|
+
expect(computeRangeTimestamps(10, 5, 1, 16)).toEqual([]);
|
|
40
|
+
expect(computeRangeTimestamps(0, 10, 0, 16)).toEqual([]);
|
|
41
|
+
expect(computeRangeTimestamps(0, 10, 1, 0)).toEqual([]);
|
|
42
|
+
expect(computeRangeTimestamps(Number.NaN, 10, 1, 16)).toEqual([]);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("buildCropFilter", () => {
|
|
46
|
+
it("builds a crop for the region with padding", () => {
|
|
47
|
+
expect(buildCropFilter({ x: 100, y: 50, width: 200, height: 100, pad: 10 })).toBe("crop=220:120:90:40");
|
|
48
|
+
});
|
|
49
|
+
it("clamps to video bounds", () => {
|
|
50
|
+
expect(buildCropFilter({ x: -20, y: -20, width: 3000, height: 2000 }, 2560, 1440)).toBe("crop=2560:1440:0:0");
|
|
51
|
+
});
|
|
52
|
+
it("returns null when the region is entirely outside the video", () => {
|
|
53
|
+
expect(buildCropFilter({ x: 5000, y: 5000, width: 100, height: 100 }, 2560, 1440)).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe("cacheKeyForUrl", () => {
|
|
57
|
+
it("ignores the SAS query so re-minted URLs share a cache entry", () => {
|
|
58
|
+
const a = cacheKeyForUrl("https://acct.blob.core.windows.net/replay/rpa_1_2.mp4?sig=abc&se=2026");
|
|
59
|
+
const b = cacheKeyForUrl("https://acct.blob.core.windows.net/replay/rpa_1_2.mp4?sig=zzz&se=2027");
|
|
60
|
+
expect(a).toBe(b);
|
|
61
|
+
});
|
|
62
|
+
it("differs for different blobs", () => {
|
|
63
|
+
expect(cacheKeyForUrl("https://acct.blob.core.windows.net/replay/rpa_1_2.mp4")).not.toBe(cacheKeyForUrl("https://acct.blob.core.windows.net/replay/rpa_1_3.mp4"));
|
|
64
|
+
});
|
|
65
|
+
});
|
|
25
66
|
describe("runCommand", () => {
|
|
26
67
|
it("resolves on a zero exit code", async () => {
|
|
27
68
|
const result = await runCommand(process.execPath, ["-e", "process.stdout.write('hi')"], 10_000);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recording-frames.test.js","sourceRoot":"","sources":["../../src/__tests__/recording-frames.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"recording-frames.test.js","sourceRoot":"","sources":["../../src/__tests__/recording-frames.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seeer-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/seeer-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { deriveSeeerProxyBase, seeerAvailable, seeerProxyBase, } from "../seeer-client.js";
|
|
3
|
+
const ENV_KEYS = ["SEEER_SERVICE_PROXY_BASE", "SEEER_SERVICE_URL"];
|
|
4
|
+
const savedEnv = {};
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
for (const key of ENV_KEYS) {
|
|
7
|
+
savedEnv[key] = process.env[key];
|
|
8
|
+
delete process.env[key];
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
for (const key of ENV_KEYS) {
|
|
13
|
+
if (savedEnv[key] === undefined)
|
|
14
|
+
delete process.env[key];
|
|
15
|
+
else
|
|
16
|
+
process.env[key] = savedEnv[key];
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
describe("deriveSeeerProxyBase", () => {
|
|
20
|
+
it("maps the US API base to the US frontend origin", () => {
|
|
21
|
+
expect(deriveSeeerProxyBase("https://api.laminar.run")).toBe("https://app.laminar.run");
|
|
22
|
+
});
|
|
23
|
+
it("maps the CA API base to the CA frontend origin", () => {
|
|
24
|
+
expect(deriveSeeerProxyBase("https://ca.api.laminar.run")).toBe("https://ca.app.laminar.run");
|
|
25
|
+
});
|
|
26
|
+
it("is domain-agnostic (api.X -> app.X)", () => {
|
|
27
|
+
expect(deriveSeeerProxyBase("https://api.minicor.com")).toBe("https://app.minicor.com");
|
|
28
|
+
});
|
|
29
|
+
it("returns undefined for hosts without an api. label", () => {
|
|
30
|
+
expect(deriveSeeerProxyBase("http://localhost:3001")).toBeUndefined();
|
|
31
|
+
expect(deriveSeeerProxyBase("https://backend.example.com")).toBeUndefined();
|
|
32
|
+
});
|
|
33
|
+
it("returns undefined for missing or invalid input", () => {
|
|
34
|
+
expect(deriveSeeerProxyBase(undefined)).toBeUndefined();
|
|
35
|
+
expect(deriveSeeerProxyBase("not a url")).toBeUndefined();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe("seeerProxyBase precedence", () => {
|
|
39
|
+
it("prefers the explicit proxy override over derivation", () => {
|
|
40
|
+
process.env.SEEER_SERVICE_PROXY_BASE = "https://staging.laminar.run/";
|
|
41
|
+
expect(seeerProxyBase("https://api.laminar.run")).toBe("https://staging.laminar.run");
|
|
42
|
+
});
|
|
43
|
+
it("yields to an explicit direct URL (no proxy) so direct mode wins", () => {
|
|
44
|
+
process.env.SEEER_SERVICE_URL = "https://video-tool.example.run.app";
|
|
45
|
+
expect(seeerProxyBase("https://api.laminar.run")).toBeUndefined();
|
|
46
|
+
expect(seeerAvailable("https://api.laminar.run")).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
it("derives from the API base when nothing is configured", () => {
|
|
49
|
+
expect(seeerProxyBase("https://api.laminar.run")).toBe("https://app.laminar.run");
|
|
50
|
+
expect(seeerAvailable("https://api.laminar.run")).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
it("is unavailable when nothing is configured and no derivation is possible", () => {
|
|
53
|
+
expect(seeerAvailable("http://localhost:3001")).toBe(false);
|
|
54
|
+
expect(seeerAvailable(undefined)).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=seeer-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seeer-client.test.js","sourceRoot":"","sources":["../../src/__tests__/seeer-client.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -153,7 +153,7 @@ async function unsetStoredApiBase(region) {
|
|
|
153
153
|
}
|
|
154
154
|
const codeModeEnabled = shouldUseCodeMode();
|
|
155
155
|
const instructions = buildInstructions(true);
|
|
156
|
-
const server = new McpServer({ name: SERVER_NAME, version: "4.
|
|
156
|
+
const server = new McpServer({ name: SERVER_NAME, version: "4.2.0" }, {
|
|
157
157
|
instructions: codeModeEnabled
|
|
158
158
|
? buildCodeModeInstructions(instructions, { sessionLifecycle: true })
|
|
159
159
|
: instructions,
|
package/dist/lib.js
CHANGED
|
@@ -60,7 +60,7 @@ export async function createMinicorServer(transport, opts = {}) {
|
|
|
60
60
|
const localTools = opts.localTools ?? true;
|
|
61
61
|
const codeModeEnabled = opts.codeMode ?? shouldUseCodeMode();
|
|
62
62
|
const instructions = buildInstructions(localTools);
|
|
63
|
-
const server = new McpServer({ name: SERVER_NAME, version: "4.
|
|
63
|
+
const server = new McpServer({ name: SERVER_NAME, version: "4.2.0" }, {
|
|
64
64
|
instructions: codeModeEnabled
|
|
65
65
|
? buildCodeModeInstructions(instructions, {
|
|
66
66
|
sessionLifecycle: localTools,
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Extracts
|
|
3
|
-
*
|
|
2
|
+
* Extracts still frames from a recording (MP4) so that a vision-capable model
|
|
3
|
+
* can visually verify or debug an execution.
|
|
4
4
|
*
|
|
5
5
|
* The recording endpoints return a signed URL to an MP4. A model cannot "watch"
|
|
6
|
-
* a video URL, so this module downloads the video and uses ffmpeg to
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* a video URL, so this module downloads the video and uses ffmpeg to extract
|
|
7
|
+
* frames, returned as base64 JPEGs. Supports:
|
|
8
|
+
* - evenly-spaced sampling across the whole video (default)
|
|
9
|
+
* - exact timestamps ("show me t=41.5s")
|
|
10
|
+
* - dense sampling of a time range ("what happened between t=30s and t=45s")
|
|
11
|
+
* - region cropping at the recording's native resolution ("zoom in here")
|
|
12
|
+
*
|
|
13
|
+
* Downloads are cached under ~/.minicor/cache/recordings keyed on the blob
|
|
14
|
+
* identity (URL minus the SAS query), so successive calls against the same
|
|
15
|
+
* recording skip the download entirely.
|
|
16
|
+
*
|
|
17
|
+
* ffmpeg (and ideally ffprobe) must be available on the MCP host; when they are
|
|
18
|
+
* missing we throw a clear error so the caller can fall back to handing the raw
|
|
19
|
+
* URL to a human.
|
|
10
20
|
*/
|
|
11
21
|
export interface ExtractedFrame {
|
|
12
22
|
/** Human-readable label, e.g. "t=12.3s" or "frame 2". */
|
|
@@ -16,15 +26,49 @@ export interface ExtractedFrame {
|
|
|
16
26
|
/** Base64-encoded JPEG (no data: prefix). */
|
|
17
27
|
base64: string;
|
|
18
28
|
}
|
|
29
|
+
export interface FrameRegion {
|
|
30
|
+
/** Left edge in native video pixels. */
|
|
31
|
+
x: number;
|
|
32
|
+
/** Top edge in native video pixels. */
|
|
33
|
+
y: number;
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
/** Extra context padding around the region, in pixels. Default 0. */
|
|
37
|
+
pad?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface FrameRange {
|
|
40
|
+
/** Window start in seconds. */
|
|
41
|
+
start: number;
|
|
42
|
+
/** Window end in seconds. */
|
|
43
|
+
end: number;
|
|
44
|
+
/** Sampling rate within the window. Default 1 fps. */
|
|
45
|
+
fps?: number;
|
|
46
|
+
}
|
|
19
47
|
export interface ExtractFramesOptions {
|
|
20
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Number of evenly-spaced frames to sample. Default 4. Ignored when
|
|
50
|
+
* `timestamps` or `range` is provided.
|
|
51
|
+
*/
|
|
21
52
|
count?: number;
|
|
53
|
+
/** Exact timestamps (seconds) to extract. Takes precedence over `range`/`count`. */
|
|
54
|
+
timestamps?: number[];
|
|
55
|
+
/** Dense sampling of a time window. Takes precedence over `count`. */
|
|
56
|
+
range?: FrameRange;
|
|
57
|
+
/** Safety cap on total frames for timestamps/range modes. Default 16. */
|
|
58
|
+
maxFrames?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Crop to this region at the recording's NATIVE resolution before any
|
|
61
|
+
* scaling — the way to keep small on-screen text readable.
|
|
62
|
+
*/
|
|
63
|
+
region?: FrameRegion;
|
|
22
64
|
/**
|
|
23
65
|
* Optional max output width in px. When omitted (the default) frames keep the
|
|
24
66
|
* recording's ORIGINAL resolution — important for reading fine on-screen detail.
|
|
25
67
|
* Only set this if you explicitly want to trade resolution for smaller frames.
|
|
26
68
|
*/
|
|
27
69
|
maxWidth?: number;
|
|
70
|
+
/** Use the on-disk download cache. Default true. */
|
|
71
|
+
cache?: boolean;
|
|
28
72
|
/** Max bytes to download before aborting. Default 200 MB. */
|
|
29
73
|
maxBytes?: number;
|
|
30
74
|
/** Overall download timeout in ms. Default 60s. */
|
|
@@ -39,11 +83,22 @@ export interface ExtractFramesOptions {
|
|
|
39
83
|
* avoid black/blank frames at the very start and end.
|
|
40
84
|
*/
|
|
41
85
|
export declare function computeSampleTimestamps(durationSeconds: number, count: number): number[];
|
|
86
|
+
/**
|
|
87
|
+
* Computes timestamps for dense sampling of a [start, end] window at `fps`,
|
|
88
|
+
* capped at `maxFrames` (falling back to even spacing across the window when
|
|
89
|
+
* the requested rate would exceed the cap).
|
|
90
|
+
*/
|
|
91
|
+
export declare function computeRangeTimestamps(start: number, end: number, fps: number, maxFrames: number): number[];
|
|
42
92
|
/**
|
|
43
93
|
* Builds an ffmpeg scale filter that caps width while preserving aspect ratio.
|
|
44
94
|
* Returns null when no cap is requested, so frames keep their original resolution.
|
|
45
95
|
*/
|
|
46
96
|
export declare function buildScaleFilter(maxWidth?: number): string | null;
|
|
97
|
+
/**
|
|
98
|
+
* Builds an ffmpeg crop filter for a region (with optional padding), clamped to
|
|
99
|
+
* the video bounds when they are known. Returns null for degenerate regions.
|
|
100
|
+
*/
|
|
101
|
+
export declare function buildCropFilter(region: FrameRegion, videoWidth?: number | null, videoHeight?: number | null): string | null;
|
|
47
102
|
export interface CommandResult {
|
|
48
103
|
code: number | null;
|
|
49
104
|
stdout: string;
|
|
@@ -51,8 +106,26 @@ export interface CommandResult {
|
|
|
51
106
|
}
|
|
52
107
|
export declare function runCommand(command: string, args: string[], timeoutMs: number): Promise<CommandResult>;
|
|
53
108
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
109
|
+
* Stable cache key for a recording URL: the blob identity without the SAS
|
|
110
|
+
* query, so re-minted signed URLs for the same blob hit the same cache entry.
|
|
111
|
+
*/
|
|
112
|
+
export declare function cacheKeyForUrl(url: string): string;
|
|
113
|
+
/**
|
|
114
|
+
* Returns a local path to the recording, downloading it if not already cached.
|
|
115
|
+
* The returned file must NOT be deleted by the caller (it is shared).
|
|
116
|
+
*/
|
|
117
|
+
export declare function getCachedRecording(url: string, opts: {
|
|
118
|
+
maxBytes: number;
|
|
119
|
+
downloadTimeoutMs: number;
|
|
120
|
+
}): Promise<string>;
|
|
121
|
+
export interface VideoInfo {
|
|
122
|
+
durationSeconds: number | null;
|
|
123
|
+
width: number | null;
|
|
124
|
+
height: number | null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Downloads the recording at `url` (via the shared cache) and returns extracted
|
|
128
|
+
* JPEG frames. Throws with a clear message when ffmpeg is unavailable.
|
|
56
129
|
*/
|
|
57
130
|
export declare function extractFramesFromUrl(url: string, options?: ExtractFramesOptions): Promise<ExtractedFrame[]>;
|
|
58
131
|
//# sourceMappingURL=recording-frames.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recording-frames.d.ts","sourceRoot":"","sources":["../src/recording-frames.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"recording-frames.d.ts","sourceRoot":"","sources":["../src/recording-frames.ts"],"names":[],"mappings":"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"}
|