recordable 0.3.0 → 0.5.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 +198 -44
- package/dist/actions.d.ts +8 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +11 -5
- package/dist/actions.js.map +1 -1
- package/dist/audio/track.d.ts +10 -0
- package/dist/audio/track.d.ts.map +1 -1
- package/dist/audio/track.js +19 -0
- package/dist/audio/track.js.map +1 -1
- package/dist/browser/cursor.d.ts +8 -6
- package/dist/browser/cursor.d.ts.map +1 -1
- package/dist/browser/cursor.js +32 -21
- package/dist/browser/cursor.js.map +1 -1
- package/dist/browser/dom.d.ts +33 -13
- package/dist/browser/dom.d.ts.map +1 -1
- package/dist/browser/dom.js +158 -56
- package/dist/browser/dom.js.map +1 -1
- package/dist/browser/page-zoom.d.ts +11 -0
- package/dist/browser/page-zoom.d.ts.map +1 -0
- package/dist/browser/page-zoom.js +37 -0
- package/dist/browser/page-zoom.js.map +1 -0
- package/dist/browser/play-button.d.ts.map +1 -1
- package/dist/browser/play-button.js.map +1 -1
- package/dist/browser/runtime.d.ts +1 -0
- package/dist/browser/runtime.d.ts.map +1 -1
- package/dist/browser/runtime.js +22 -14
- package/dist/browser/runtime.js.map +1 -1
- package/dist/browser/targets.d.ts.map +1 -0
- package/dist/{targets.js → browser/targets.js} +3 -2
- package/dist/browser/targets.js.map +1 -0
- package/dist/compose/boundaries.d.ts +13 -0
- package/dist/compose/boundaries.d.ts.map +1 -0
- package/dist/compose/boundaries.js +49 -0
- package/dist/compose/boundaries.js.map +1 -0
- package/dist/compose/mix.d.ts +3 -2
- package/dist/compose/mix.d.ts.map +1 -1
- package/dist/compose/mix.js +9 -4
- package/dist/compose/mix.js.map +1 -1
- package/dist/compose/recordable.d.ts +28 -3
- package/dist/compose/recordable.d.ts.map +1 -1
- package/dist/compose/recordable.js +75 -18
- package/dist/compose/recordable.js.map +1 -1
- package/dist/compose/session.d.ts +20 -8
- package/dist/compose/session.d.ts.map +1 -1
- package/dist/compose/session.js +120 -38
- package/dist/compose/session.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -3
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/ffmpeg.d.ts +3 -0
- package/dist/ffmpeg.d.ts.map +1 -1
- package/dist/ffmpeg.js +22 -4
- package/dist/ffmpeg.js.map +1 -1
- package/dist/formats/json.d.ts +2 -1
- package/dist/formats/json.d.ts.map +1 -1
- package/dist/formats/json.js.map +1 -1
- package/dist/formats/markdown/method.d.ts.map +1 -1
- package/dist/formats/markdown/method.js +4 -3
- package/dist/formats/markdown/method.js.map +1 -1
- package/dist/fs.d.ts +16 -0
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +33 -4
- package/dist/fs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +3 -1
- package/dist/logger.js.map +1 -1
- package/dist/result.d.ts +30 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +8 -0
- package/dist/result.js.map +1 -0
- package/dist/timing.d.ts +2 -0
- package/dist/timing.d.ts.map +1 -1
- package/dist/timing.js +10 -4
- package/dist/timing.js.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +11 -10
- package/dist/validate.js.map +1 -1
- package/dist/video/recorder.d.ts +26 -3
- package/dist/video/recorder.d.ts.map +1 -1
- package/dist/video/recorder.js +50 -32
- package/dist/video/recorder.js.map +1 -1
- package/dist/video/stitch.js +3 -17
- package/dist/video/stitch.js.map +1 -1
- package/dist/voiceover/compile.d.ts.map +1 -1
- package/dist/voiceover/compile.js +42 -24
- package/dist/voiceover/compile.js.map +1 -1
- package/dist/voiceover/elevenlabs.d.ts.map +1 -1
- package/dist/voiceover/elevenlabs.js +41 -11
- package/dist/voiceover/elevenlabs.js.map +1 -1
- package/dist/voiceover/mock.d.ts.map +1 -1
- package/dist/voiceover/mock.js +38 -15
- package/dist/voiceover/mock.js.map +1 -1
- package/package.json +20 -6
- package/recordable.schema.json +81 -0
- package/dist/targets.d.ts.map +0 -1
- package/dist/targets.js.map +0 -1
- /package/dist/{targets.d.ts → browser/targets.d.ts} +0 -0
package/dist/video/stitch.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { writeFileSync } from "node:fs";
|
|
2
2
|
import { join as joinPath } from "node:path";
|
|
3
|
-
import { getDuration, runFfmpeg } from "../ffmpeg.js";
|
|
3
|
+
import { getDuration, runFfmpeg, videoEncodeArgs } from "../ffmpeg.js";
|
|
4
4
|
import { moveFile } from "../fs.js";
|
|
5
5
|
/** Stitch `segs` into `out`, choosing move / join / cross-fade automatically. */
|
|
6
6
|
export async function stitch(segs, cfg, log, out, tmpDir) {
|
|
@@ -29,16 +29,7 @@ async function join(segments, cfg, log, out, tmpDir) {
|
|
|
29
29
|
log("Record", `joined ${segments.length} segments`);
|
|
30
30
|
}
|
|
31
31
|
catch {
|
|
32
|
-
await runFfmpeg([
|
|
33
|
-
...base,
|
|
34
|
-
"-c:v",
|
|
35
|
-
cfg.videoCodec,
|
|
36
|
-
"-preset",
|
|
37
|
-
cfg.videoPreset,
|
|
38
|
-
"-crf",
|
|
39
|
-
String(cfg.videoCrf),
|
|
40
|
-
out,
|
|
41
|
-
]);
|
|
32
|
+
await runFfmpeg([...base, ...videoEncodeArgs(cfg), out]);
|
|
42
33
|
log("Record", `joined ${segments.length} segments (re-encoded)`);
|
|
43
34
|
}
|
|
44
35
|
}
|
|
@@ -96,12 +87,7 @@ async function stitchWithFades(segs, cfg, log, out) {
|
|
|
96
87
|
parts.join(";"),
|
|
97
88
|
"-map",
|
|
98
89
|
`[${acc}]`,
|
|
99
|
-
|
|
100
|
-
cfg.videoCodec,
|
|
101
|
-
"-preset",
|
|
102
|
-
cfg.videoPreset,
|
|
103
|
-
"-crf",
|
|
104
|
-
String(cfg.videoCrf),
|
|
90
|
+
...videoEncodeArgs(cfg),
|
|
105
91
|
"-pix_fmt",
|
|
106
92
|
"yuv420p",
|
|
107
93
|
out,
|
package/dist/video/stitch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stitch.js","sourceRoot":"","sources":["../../src/video/stitch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"stitch.js","sourceRoot":"","sources":["../../src/video/stitch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/voiceover/compile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/voiceover/compile.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGtE,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AASzD,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AASpB,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B;2EACuE;IACvE,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,4FAA4F;IAC5F,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;sEACkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,mFAAmF;AACnF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kFAAkF;IAClF,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAgOD;;0FAE0F;AAC1F,wBAAsB,eAAe,CACnC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,cAAc,CAAC,CAsDzB"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { parseMarkdown } from "../formats/markdown/parse.js";
|
|
3
|
+
import { parseMarkdown, } from "../formats/markdown/parse.js";
|
|
4
4
|
import { truncate } from "../utils.js";
|
|
5
|
+
import { RecordableError } from "../errors.js";
|
|
5
6
|
import { createLogger } from "../logger.js";
|
|
6
7
|
import { actionDurationMs } from "../timing.js";
|
|
7
8
|
import { cacheKey, FileCache } from "./cache.js";
|
|
8
9
|
import { ElevenLabsProvider, DEFAULT_MODEL, DEFAULT_FORMAT, } from "./elevenlabs.js";
|
|
9
10
|
import { MockTTSProvider } from "./mock.js";
|
|
10
|
-
import { extFor } from "./types.js";
|
|
11
|
+
import { extFor, } from "./types.js";
|
|
11
12
|
/** First-character index of the word containing `offset` (scan back to whitespace). */
|
|
12
13
|
function wordStart(text, offset) {
|
|
13
14
|
let i = Math.min(offset, text.length);
|
|
@@ -49,10 +50,9 @@ function keyFor(narration, vo) {
|
|
|
49
50
|
text: narration,
|
|
50
51
|
});
|
|
51
52
|
}
|
|
52
|
-
/** Synthesize one paragraph
|
|
53
|
-
*
|
|
54
|
-
async function
|
|
55
|
-
const { narration, markers } = block;
|
|
53
|
+
/** Synthesize one paragraph cache-first and write its audio asset to disk.
|
|
54
|
+
* A miss is a real synthesis — for a network provider, an external API call. */
|
|
55
|
+
async function synthesizeBlock(narration, opts) {
|
|
56
56
|
const key = keyFor(narration, opts.voiceover);
|
|
57
57
|
const preview = truncate(narration);
|
|
58
58
|
let result = opts.cache.get(key);
|
|
@@ -60,7 +60,6 @@ async function compileNarration(block, opts) {
|
|
|
60
60
|
opts.log("Voice", `cache hit "${preview}"`);
|
|
61
61
|
}
|
|
62
62
|
else {
|
|
63
|
-
// A miss means a real synthesis — for a network provider, an external API call.
|
|
64
63
|
opts.log("Voice", `synthesize "${preview}" via ${opts.providerName}`);
|
|
65
64
|
result = await opts.provider.synthesize(narration, {
|
|
66
65
|
format: opts.voiceover?.format,
|
|
@@ -72,12 +71,33 @@ async function compileNarration(block, opts) {
|
|
|
72
71
|
const asset = join(opts.assetsDir, `${key}.${extFor(result.format)}`);
|
|
73
72
|
mkdirSync(opts.assetsDir, { recursive: true });
|
|
74
73
|
writeFileSync(asset, result.audio);
|
|
75
|
-
|
|
74
|
+
return { result, asset };
|
|
75
|
+
}
|
|
76
|
+
/** Warn that a marker can't land on its word: earlier actions in this paragraph
|
|
77
|
+
* (their cursor travel, typing, inserts) already ran `-gap`ms past it, so this
|
|
78
|
+
* one and everything after it lag. Point at the exact spot and say why. */
|
|
79
|
+
function warnOverrun(m, narration, preview, gap, prevOffset, warn) {
|
|
80
|
+
const stacked = m.offset === prevOffset;
|
|
81
|
+
const cause = stacked
|
|
82
|
+
? `it shares a spot in the narration with the action before it`
|
|
83
|
+
: `the actions before it overrun by that much`;
|
|
84
|
+
const fix = stacked
|
|
85
|
+
? `move ${markerLabel(m.step)} to the word it actually describes, or add narration between the two`
|
|
86
|
+
: `add words before it, space the actions out, or move it into a fenced block (no audio)`;
|
|
87
|
+
warn(`Voiceover timing — ${markerLabel(m.step)} can't start on ${wordAt(narration, m.offset)} ` +
|
|
88
|
+
`(paragraph "${preview}"): ${cause}, so it and the rest lag ${-gap}ms. Fix: ${fix}.`);
|
|
89
|
+
}
|
|
90
|
+
/** Turn a clip's alignment into timed actions: a `wait` before each marker so it
|
|
91
|
+
* fires on its narrated word (warn, never retime, when it overruns), the marker
|
|
92
|
+
* itself, then a tail `wait` so the narration finishes before the next block. */
|
|
93
|
+
async function placeMarkers(narration, markers, result, opts) {
|
|
94
|
+
const preview = truncate(narration);
|
|
76
95
|
const alignment = result.alignment ?? {
|
|
77
96
|
chars: [],
|
|
78
97
|
startMs: [],
|
|
79
98
|
endMs: [],
|
|
80
99
|
};
|
|
100
|
+
const actions = [];
|
|
81
101
|
let elapsed = 0;
|
|
82
102
|
let prevOffset = -1;
|
|
83
103
|
for (const m of markers) {
|
|
@@ -88,27 +108,25 @@ async function compileNarration(block, opts) {
|
|
|
88
108
|
elapsed += gap;
|
|
89
109
|
}
|
|
90
110
|
else if (gap < 0) {
|
|
91
|
-
|
|
92
|
-
// (their cursor travel, typing, inserts) already ran `-gap`ms past it, so
|
|
93
|
-
// this one and everything after it lag. Point at the exact spot and say why.
|
|
94
|
-
const stacked = m.offset === prevOffset;
|
|
95
|
-
const cause = stacked
|
|
96
|
-
? `it shares a spot in the narration with the action before it`
|
|
97
|
-
: `the actions before it overrun by that much`;
|
|
98
|
-
const fix = stacked
|
|
99
|
-
? `move ${markerLabel(m.step)} to the word it actually describes, or add narration between the two`
|
|
100
|
-
: `add words before it, space the actions out, or move it into a fenced block (no audio)`;
|
|
101
|
-
opts.warn(`Voiceover timing — ${markerLabel(m.step)} can't start on ${wordAt(narration, m.offset)} ` +
|
|
102
|
-
`(paragraph "${preview}"): ${cause}, so it and the rest lag ${-gap}ms. Fix: ${fix}.`);
|
|
111
|
+
warnOverrun(m, narration, preview, gap, prevOffset, opts.warn);
|
|
103
112
|
}
|
|
104
113
|
actions.push(m.step);
|
|
105
114
|
elapsed += await actionDurationMs(m.step, opts.cfg);
|
|
106
115
|
prevOffset = m.offset;
|
|
107
116
|
}
|
|
108
|
-
// Let the narration finish before the next block begins.
|
|
109
117
|
const tail = Math.round(result.durationMs - elapsed);
|
|
110
118
|
if (tail > 0)
|
|
111
119
|
actions.push({ action: "wait", ms: tail });
|
|
120
|
+
return actions;
|
|
121
|
+
}
|
|
122
|
+
/** Synthesize one paragraph (cache-first) → its `audio()` clip, a `wait`/action
|
|
123
|
+
* pair per marker, and a tail `wait` so the voiceover finishes. */
|
|
124
|
+
async function compileNarration(block, opts) {
|
|
125
|
+
const { result, asset } = await synthesizeBlock(block.narration, opts);
|
|
126
|
+
const actions = [
|
|
127
|
+
{ action: "audio", path: asset, wait: false },
|
|
128
|
+
...(await placeMarkers(block.narration, block.markers, result, opts)),
|
|
129
|
+
];
|
|
112
130
|
return { actions, asset };
|
|
113
131
|
}
|
|
114
132
|
/** Apply env defaults to a voiceover block — frontmatter always wins. The env
|
|
@@ -132,18 +150,18 @@ function resolveProvider(provider, voiceover) {
|
|
|
132
150
|
if (provider)
|
|
133
151
|
return provider;
|
|
134
152
|
if (!voiceover) {
|
|
135
|
-
throw new
|
|
153
|
+
throw new RecordableError("CONFIG_INVALID", "compileMarkdown: no `voiceover` frontmatter and no `provider` — add a voiceover block or pass a provider.");
|
|
136
154
|
}
|
|
137
155
|
if (voiceover.provider === "mock")
|
|
138
156
|
return new MockTTSProvider();
|
|
139
157
|
const hasKey = voiceover.apiKey ?? process.env.ELEVENLABS_API_KEY;
|
|
140
158
|
if (!hasKey) {
|
|
141
|
-
throw new
|
|
159
|
+
throw new RecordableError("CONFIG_INVALID", "Voiceover: ElevenLabs needs an API key — set ELEVENLABS_API_KEY (e.g. in a .env beside " +
|
|
142
160
|
"the document) or `voiceover.apiKey`, or use RECORDABLE_TTS_PROVIDER=mock for silent audio.");
|
|
143
161
|
}
|
|
144
162
|
const voiceId = voiceover.voiceId;
|
|
145
163
|
if (!voiceId) {
|
|
146
|
-
throw new
|
|
164
|
+
throw new RecordableError("CONFIG_INVALID", "Voiceover: ElevenLabs needs a voice — set RECORDABLE_VOICE_ID (e.g. in a .env beside " +
|
|
147
165
|
"the document) or `voiceover.voiceId`.");
|
|
148
166
|
}
|
|
149
167
|
return new ElevenLabsProvider({ ...voiceover, voiceId });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/voiceover/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/voiceover/compile.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elevenlabs.d.ts","sourceRoot":"","sources":["../../src/voiceover/elevenlabs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAOpD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAUvE,eAAO,MAAM,aAAa,2BAA2B,CAAC;AACtD,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAG9C,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"elevenlabs.d.ts","sourceRoot":"","sources":["../../src/voiceover/elevenlabs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAOpD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAUvE,eAAO,MAAM,aAAa,2BAA2B,CAAC;AACtD,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAG9C,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;CACjB;AA0ED,qBAAa,kBAAmB,YAAW,WAAW;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,iBAAiB;IAE7C,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;IAK3E,8EAA8E;YAChE,WAAW;CAkD1B"}
|
|
@@ -10,6 +10,41 @@ import { alignmentDurationMs, normalizeAlignment, } from "./alignment.js";
|
|
|
10
10
|
export const DEFAULT_MODEL = "eleven_multilingual_v2";
|
|
11
11
|
export const DEFAULT_FORMAT = "mp3_44100_128";
|
|
12
12
|
const PACKAGE = "@elevenlabs/elevenlabs-js";
|
|
13
|
+
/** Read a property off an unknown value, or undefined if it isn't an object. */
|
|
14
|
+
function prop(obj, key) {
|
|
15
|
+
return typeof obj === "object" && obj !== null
|
|
16
|
+
? obj[key]
|
|
17
|
+
: undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Resolve the client constructor across SDK layouts. */
|
|
20
|
+
function resolveClientCtor(mod) {
|
|
21
|
+
const candidate = prop(mod, "ElevenLabsClient") ?? // named export (current ESM)
|
|
22
|
+
prop(prop(mod, "default"), "ElevenLabsClient") ?? // default-wrapped (CJS interop)
|
|
23
|
+
prop(mod, "default"); // bare default export
|
|
24
|
+
if (typeof candidate !== "function") {
|
|
25
|
+
throw new RecordableError("TTS_FAILED", `ElevenLabs: "${PACKAGE}" has no usable ElevenLabsClient export — ` +
|
|
26
|
+
`its API may have changed; check the installed version`);
|
|
27
|
+
}
|
|
28
|
+
return candidate;
|
|
29
|
+
}
|
|
30
|
+
/** Pull audio + optional alignment out of a synthesis response, unwrapping SDK
|
|
31
|
+
* drift. Throws if no usable audio is present. */
|
|
32
|
+
function extractSynthesis(res) {
|
|
33
|
+
// Response is the object directly in current SDKs, `.data`-wrapped in older.
|
|
34
|
+
const data = prop(res, "data") ?? res;
|
|
35
|
+
// Audio field is `audioBase64` (camelCase SDK) / `audio_base64` (raw REST).
|
|
36
|
+
const audioBase64 = prop(data, "audioBase64") ??
|
|
37
|
+
prop(data, "audio_base64") ??
|
|
38
|
+
prop(data, "audio");
|
|
39
|
+
if (typeof audioBase64 !== "string") {
|
|
40
|
+
throw new RecordableError("TTS_FAILED", "ElevenLabs returned no audio in its response");
|
|
41
|
+
}
|
|
42
|
+
const rawAlignment = prop(data, "alignment");
|
|
43
|
+
const alignment = typeof rawAlignment === "object" && rawAlignment !== null
|
|
44
|
+
? rawAlignment
|
|
45
|
+
: undefined;
|
|
46
|
+
return { audioBase64, alignment };
|
|
47
|
+
}
|
|
13
48
|
export class ElevenLabsProvider {
|
|
14
49
|
cfg;
|
|
15
50
|
constructor(cfg) {
|
|
@@ -23,7 +58,7 @@ export class ElevenLabsProvider {
|
|
|
23
58
|
async _synthesize(text, format) {
|
|
24
59
|
const apiKey = this.cfg.apiKey ?? process.env.ELEVENLABS_API_KEY;
|
|
25
60
|
if (!apiKey) {
|
|
26
|
-
throw new
|
|
61
|
+
throw new RecordableError("CONFIG_INVALID", "ElevenLabs: no API key — set ELEVENLABS_API_KEY (or voiceover.apiKey)");
|
|
27
62
|
}
|
|
28
63
|
// Non-literal specifier so tsc doesn't try to resolve the optional dep; it's
|
|
29
64
|
// present only when the voiceover add-on path is actually used.
|
|
@@ -32,10 +67,10 @@ export class ElevenLabsProvider {
|
|
|
32
67
|
mod = await import(PACKAGE);
|
|
33
68
|
}
|
|
34
69
|
catch {
|
|
35
|
-
throw new
|
|
70
|
+
throw new RecordableError("TTS_FAILED", `ElevenLabs: the "${PACKAGE}" package is not installed — ` +
|
|
36
71
|
`add it to use voiceover (it is an optional dependency)`);
|
|
37
72
|
}
|
|
38
|
-
const ElevenLabsClient = mod
|
|
73
|
+
const ElevenLabsClient = resolveClientCtor(mod);
|
|
39
74
|
const client = new ElevenLabsClient({ apiKey });
|
|
40
75
|
let res;
|
|
41
76
|
try {
|
|
@@ -49,15 +84,10 @@ export class ElevenLabsProvider {
|
|
|
49
84
|
catch (e) {
|
|
50
85
|
throw new RecordableError("TTS_FAILED", `ElevenLabs synthesis failed: ${e.message}`, { cause: e });
|
|
51
86
|
}
|
|
52
|
-
|
|
53
|
-
// Audio field is `audioBase64` (camelCase SDK) / `audio_base64` (raw REST).
|
|
54
|
-
const data = res?.data ?? res;
|
|
55
|
-
const audioBase64 = data.audioBase64 ?? data.audio_base64 ?? data.audio;
|
|
56
|
-
if (!audioBase64)
|
|
57
|
-
throw new RecordableError("TTS_FAILED", "ElevenLabs returned no audio in its response");
|
|
87
|
+
const { audioBase64, alignment: rawAlignment } = extractSynthesis(res);
|
|
58
88
|
const audio = Buffer.from(audioBase64, "base64");
|
|
59
|
-
const alignment =
|
|
60
|
-
? normalizeAlignment(
|
|
89
|
+
const alignment = rawAlignment
|
|
90
|
+
? normalizeAlignment(rawAlignment)
|
|
61
91
|
: undefined;
|
|
62
92
|
const durationMs = alignment ? alignmentDurationMs(alignment) : 0;
|
|
63
93
|
return { audio, format, durationMs, alignment };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elevenlabs.js","sourceRoot":"","sources":["../../src/voiceover/elevenlabs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GAEnB,MAAM,gBAAgB,CAAC;AAGxB,gFAAgF;AAChF,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,6EAA6E;AAC7E,4EAA4E;AAC5E,oCAAoC;AAEpC,MAAM,CAAC,MAAM,aAAa,GAAG,wBAAwB,CAAC;AACtD,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC;AAC9C,MAAM,OAAO,GAAG,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"elevenlabs.js","sourceRoot":"","sources":["../../src/voiceover/elevenlabs.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/voiceover/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAYvE,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,eAAgB,YAAW,WAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,GAAE,WAAgB;IAE7C,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;CAgB7E;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,SAAO,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/voiceover/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAYvE,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,eAAgB,YAAW,WAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,GAAE,WAAgB;IAE7C,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;CAgB7E;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,SAAO,GAAG,MAAM,CA4CvE"}
|
package/dist/voiceover/mock.js
CHANGED
|
@@ -20,22 +20,45 @@ export class MockTTSProvider {
|
|
|
20
20
|
}
|
|
21
21
|
/** Build a valid silent 16-bit mono WAV of `durationMs` — ffmpeg-compatible. */
|
|
22
22
|
export function silentWav(durationMs, sampleRate = 8000) {
|
|
23
|
+
// Canonical 44-byte RIFF/WAVE header for 16-bit mono PCM, then silent samples.
|
|
24
|
+
const CHANNELS = 1; // mono
|
|
25
|
+
const BITS_PER_SAMPLE = 16;
|
|
26
|
+
const BYTES_PER_SAMPLE = BITS_PER_SAMPLE / 8;
|
|
27
|
+
const BLOCK_ALIGN = CHANNELS * BYTES_PER_SAMPLE; // bytes per sample frame
|
|
28
|
+
const BYTE_RATE = sampleRate * BLOCK_ALIGN;
|
|
29
|
+
const FMT_CHUNK_SIZE = 16; // bytes of the fmt subchunk body (PCM)
|
|
30
|
+
const AUDIO_FORMAT_PCM = 1; // 1 = uncompressed PCM
|
|
31
|
+
const HEADER_SIZE = 44;
|
|
32
|
+
// Byte offsets of each field within the header (RIFF + fmt + data subchunks).
|
|
33
|
+
const OFF_RIFF_ID = 0; // "RIFF"
|
|
34
|
+
const OFF_RIFF_SIZE = 4; // file size minus 8 bytes (the "RIFF" id + this field)
|
|
35
|
+
const OFF_WAVE_ID = 8; // "WAVE"
|
|
36
|
+
const OFF_FMT_ID = 12; // "fmt "
|
|
37
|
+
const OFF_FMT_SIZE = 16; // fmt chunk body size
|
|
38
|
+
const OFF_AUDIO_FORMAT = 20; // PCM = 1
|
|
39
|
+
const OFF_CHANNELS = 22; // channel count
|
|
40
|
+
const OFF_SAMPLE_RATE = 24; // samples per second
|
|
41
|
+
const OFF_BYTE_RATE = 28; // sampleRate * blockAlign
|
|
42
|
+
const OFF_BLOCK_ALIGN = 32; // bytes per sample frame
|
|
43
|
+
const OFF_BITS_PER_SAMPLE = 34; // bits per sample
|
|
44
|
+
const OFF_DATA_ID = 36; // "data"
|
|
45
|
+
const OFF_DATA_SIZE = 40; // data chunk body size (= byte length of samples)
|
|
23
46
|
const numSamples = Math.max(0, Math.round((durationMs / 1000) * sampleRate));
|
|
24
|
-
const dataSize = numSamples *
|
|
25
|
-
const buf = Buffer.alloc(
|
|
26
|
-
buf.write("RIFF",
|
|
27
|
-
buf.writeUInt32LE(
|
|
28
|
-
buf.write("WAVE",
|
|
29
|
-
buf.write("fmt ",
|
|
30
|
-
buf.writeUInt32LE(
|
|
31
|
-
buf.writeUInt16LE(
|
|
32
|
-
buf.writeUInt16LE(
|
|
33
|
-
buf.writeUInt32LE(sampleRate,
|
|
34
|
-
buf.writeUInt32LE(
|
|
35
|
-
buf.writeUInt16LE(
|
|
36
|
-
buf.writeUInt16LE(
|
|
37
|
-
buf.write("data",
|
|
38
|
-
buf.writeUInt32LE(dataSize,
|
|
47
|
+
const dataSize = numSamples * BYTES_PER_SAMPLE; // 16-bit mono
|
|
48
|
+
const buf = Buffer.alloc(HEADER_SIZE + dataSize); // samples already zero = silence
|
|
49
|
+
buf.write("RIFF", OFF_RIFF_ID, "ascii");
|
|
50
|
+
buf.writeUInt32LE(HEADER_SIZE - 8 + dataSize, OFF_RIFF_SIZE);
|
|
51
|
+
buf.write("WAVE", OFF_WAVE_ID, "ascii");
|
|
52
|
+
buf.write("fmt ", OFF_FMT_ID, "ascii");
|
|
53
|
+
buf.writeUInt32LE(FMT_CHUNK_SIZE, OFF_FMT_SIZE);
|
|
54
|
+
buf.writeUInt16LE(AUDIO_FORMAT_PCM, OFF_AUDIO_FORMAT);
|
|
55
|
+
buf.writeUInt16LE(CHANNELS, OFF_CHANNELS);
|
|
56
|
+
buf.writeUInt32LE(sampleRate, OFF_SAMPLE_RATE);
|
|
57
|
+
buf.writeUInt32LE(BYTE_RATE, OFF_BYTE_RATE);
|
|
58
|
+
buf.writeUInt16LE(BLOCK_ALIGN, OFF_BLOCK_ALIGN);
|
|
59
|
+
buf.writeUInt16LE(BITS_PER_SAMPLE, OFF_BITS_PER_SAMPLE);
|
|
60
|
+
buf.write("data", OFF_DATA_ID, "ascii");
|
|
61
|
+
buf.writeUInt32LE(dataSize, OFF_DATA_SIZE);
|
|
39
62
|
return buf;
|
|
40
63
|
}
|
|
41
64
|
//# sourceMappingURL=mock.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.js","sourceRoot":"","sources":["../../src/voiceover/mock.ts"],"names":[],"mappings":"AAmBA,MAAM,OAAO,eAAe;IACG;IAA7B,YAA6B,OAAoB,EAAE;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEvD,KAAK,CAAC,UAAU,CAAC,IAAY,EAAE,QAAsB,EAAE;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC;QAEhD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QACxB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;QAE5C,OAAO;YACL,KAAK,EAAE,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC;YACxC,MAAM,EAAE,KAAK;YACb,UAAU;YACV,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE;SACrC,CAAC;IACJ,CAAC;CACF;AAED,gFAAgF;AAChF,MAAM,UAAU,SAAS,CAAC,UAAkB,EAAE,UAAU,GAAG,IAAI;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;IAC7E,MAAM,QAAQ,GAAG,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"mock.js","sourceRoot":"","sources":["../../src/voiceover/mock.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "recordable",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Programmatic, repeatable browser screen recording. Script a walkthrough as a fluent chain of actions — clicks, typing, smooth zoom/scroll, an animated cursor, and manual steps like logins — and capture it to MP4.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,15 +35,18 @@
|
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsc",
|
|
38
|
-
"
|
|
39
|
-
"test
|
|
38
|
+
"typecheck": "tsc -p tsconfig.typecheck.json",
|
|
39
|
+
"test": "tsx --test test/*.test.ts",
|
|
40
|
+
"test:e2e": "tsx --test test/e2e/*.e2e.ts",
|
|
40
41
|
"clean": "rm -rf dist",
|
|
41
42
|
"gen:schema": "tsx scripts/gen-schema.ts",
|
|
42
43
|
"lint": "eslint .",
|
|
43
44
|
"lint:fix": "eslint . --fix",
|
|
44
45
|
"format": "prettier --write .",
|
|
45
46
|
"format:check": "prettier --check .",
|
|
46
|
-
"prepublishOnly": "npm run clean && npm run gen:schema && npm run build"
|
|
47
|
+
"prepublishOnly": "npm run clean && npm run gen:schema && npm run build",
|
|
48
|
+
"commitlint": "commitlint",
|
|
49
|
+
"prepare": "husky && git config commit.template .gitmessage 2>/dev/null || true"
|
|
47
50
|
},
|
|
48
51
|
"keywords": [
|
|
49
52
|
"screen-recording",
|
|
@@ -60,10 +63,10 @@
|
|
|
60
63
|
"author": "Cam Parry <hello@camparry.com>",
|
|
61
64
|
"license": "MIT",
|
|
62
65
|
"engines": {
|
|
63
|
-
"node": ">=
|
|
66
|
+
"node": ">=20"
|
|
64
67
|
},
|
|
65
68
|
"dependencies": {
|
|
66
|
-
"
|
|
69
|
+
"ffmpeg-static": "^5.3.0",
|
|
67
70
|
"gray-matter": "^4.0.3",
|
|
68
71
|
"json5": "^2.2.3",
|
|
69
72
|
"markdown-it": "^14.2.0",
|
|
@@ -71,11 +74,15 @@
|
|
|
71
74
|
"zod": "^4.4.3"
|
|
72
75
|
},
|
|
73
76
|
"devDependencies": {
|
|
77
|
+
"@commitlint/cli": "^19.8.1",
|
|
78
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
74
79
|
"@eslint/js": "^10.0.1",
|
|
75
80
|
"@types/markdown-it": "^14.1.2",
|
|
76
81
|
"@types/node": "^20.0.0",
|
|
77
82
|
"eslint": "^10.5.0",
|
|
78
83
|
"eslint-config-prettier": "^10.1.8",
|
|
84
|
+
"husky": "^9.1.7",
|
|
85
|
+
"lint-staged": "^15.5.2",
|
|
79
86
|
"prettier": "^3.8.4",
|
|
80
87
|
"tsx": "^4.0.0",
|
|
81
88
|
"typescript": "^5.0.0",
|
|
@@ -83,5 +90,12 @@
|
|
|
83
90
|
},
|
|
84
91
|
"optionalDependencies": {
|
|
85
92
|
"@elevenlabs/elevenlabs-js": "^2.0.0"
|
|
93
|
+
},
|
|
94
|
+
"lint-staged": {
|
|
95
|
+
"*.{ts,js,mjs,cjs}": [
|
|
96
|
+
"eslint --fix --no-warn-ignored",
|
|
97
|
+
"prettier --write"
|
|
98
|
+
],
|
|
99
|
+
"*.{json,md,yml,yaml,css,html}": "prettier --write"
|
|
86
100
|
}
|
|
87
101
|
}
|
package/recordable.schema.json
CHANGED
|
@@ -132,6 +132,9 @@
|
|
|
132
132
|
"properties": {
|
|
133
133
|
"action": {
|
|
134
134
|
"enum": [
|
|
135
|
+
"start",
|
|
136
|
+
"end",
|
|
137
|
+
"split",
|
|
135
138
|
"pause",
|
|
136
139
|
"resume",
|
|
137
140
|
"waitForPlay",
|
|
@@ -157,6 +160,81 @@
|
|
|
157
160
|
}
|
|
158
161
|
},
|
|
159
162
|
"allOf": [
|
|
163
|
+
{
|
|
164
|
+
"if": {
|
|
165
|
+
"properties": {
|
|
166
|
+
"action": {
|
|
167
|
+
"const": "start"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"required": [
|
|
171
|
+
"action"
|
|
172
|
+
]
|
|
173
|
+
},
|
|
174
|
+
"then": {
|
|
175
|
+
"properties": {
|
|
176
|
+
"action": {
|
|
177
|
+
"const": "start"
|
|
178
|
+
},
|
|
179
|
+
"name": {
|
|
180
|
+
"type": "string"
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"required": [
|
|
184
|
+
"action"
|
|
185
|
+
],
|
|
186
|
+
"additionalProperties": false
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"if": {
|
|
191
|
+
"properties": {
|
|
192
|
+
"action": {
|
|
193
|
+
"const": "end"
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"required": [
|
|
197
|
+
"action"
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
"then": {
|
|
201
|
+
"properties": {
|
|
202
|
+
"action": {
|
|
203
|
+
"const": "end"
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"required": [
|
|
207
|
+
"action"
|
|
208
|
+
],
|
|
209
|
+
"additionalProperties": false
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"if": {
|
|
214
|
+
"properties": {
|
|
215
|
+
"action": {
|
|
216
|
+
"const": "split"
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
"required": [
|
|
220
|
+
"action"
|
|
221
|
+
]
|
|
222
|
+
},
|
|
223
|
+
"then": {
|
|
224
|
+
"properties": {
|
|
225
|
+
"action": {
|
|
226
|
+
"const": "split"
|
|
227
|
+
},
|
|
228
|
+
"name": {
|
|
229
|
+
"type": "string"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
"required": [
|
|
233
|
+
"action"
|
|
234
|
+
],
|
|
235
|
+
"additionalProperties": false
|
|
236
|
+
}
|
|
237
|
+
},
|
|
160
238
|
{
|
|
161
239
|
"if": {
|
|
162
240
|
"properties": {
|
|
@@ -677,6 +755,9 @@
|
|
|
677
755
|
}
|
|
678
756
|
]
|
|
679
757
|
},
|
|
758
|
+
"container": {
|
|
759
|
+
"type": "string"
|
|
760
|
+
},
|
|
680
761
|
"duration": {
|
|
681
762
|
"type": "number"
|
|
682
763
|
}
|
package/dist/targets.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AASA;;;;;mEAKmE;AACnE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGpD;AASD;sEACsE;AACtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM9C;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGtD"}
|
package/dist/targets.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,yDAAyD;AAEzD,gFAAgF;AAChF,6EAA6E;AAC7E,8EAA8E;AAC9E,mEAAmE;AACnE,MAAM,WAAW,GAAG,mBAAmB,CAAC;AAExC;;;;;mEAKmE;AACnE,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,aAAa,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IACvE,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC/E,CAAC;AAED,4EAA4E;AAC5E,gFAAgF;AAChF,gFAAgF;AAChF,4EAA4E;AAC5E,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAChD,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAElD;sEACsE;AACtE,MAAM,UAAU,eAAe,CAC7B,IAAY;IAEZ,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACrC,IAAI,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,uBAAuB;IAClE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,KAAK;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,KAAK,GAAG,sCAAsC,CAAC;IACrD,OAAO,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,KAAK,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACzE,CAAC"}
|
|
File without changes
|