recordable 0.1.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/LICENSE +21 -0
- package/README.md +303 -0
- package/dist/actions.d.ts +140 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +184 -0
- package/dist/actions.js.map +1 -0
- package/dist/audio/track.d.ts +45 -0
- package/dist/audio/track.d.ts.map +1 -0
- package/dist/audio/track.js +61 -0
- package/dist/audio/track.js.map +1 -0
- package/dist/browser/cursor.d.ts +33 -0
- package/dist/browser/cursor.d.ts.map +1 -0
- package/dist/browser/cursor.js +118 -0
- package/dist/browser/cursor.js.map +1 -0
- package/dist/browser/dom.d.ts +31 -0
- package/dist/browser/dom.d.ts.map +1 -0
- package/dist/browser/dom.js +134 -0
- package/dist/browser/dom.js.map +1 -0
- package/dist/browser/play-button.d.ts +11 -0
- package/dist/browser/play-button.d.ts.map +1 -0
- package/dist/browser/play-button.js +87 -0
- package/dist/browser/play-button.js.map +1 -0
- package/dist/browser/runtime.d.ts +66 -0
- package/dist/browser/runtime.d.ts.map +1 -0
- package/dist/browser/runtime.js +271 -0
- package/dist/browser/runtime.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +131 -0
- package/dist/cli.js.map +1 -0
- package/dist/compose/mix.d.ts +13 -0
- package/dist/compose/mix.d.ts.map +1 -0
- package/dist/compose/mix.js +50 -0
- package/dist/compose/mix.js.map +1 -0
- package/dist/compose/recordable.d.ts +149 -0
- package/dist/compose/recordable.d.ts.map +1 -0
- package/dist/compose/recordable.js +337 -0
- package/dist/compose/recordable.js.map +1 -0
- package/dist/compose/session.d.ts +38 -0
- package/dist/compose/session.d.ts.map +1 -0
- package/dist/compose/session.js +122 -0
- package/dist/compose/session.js.map +1 -0
- package/dist/config.d.ts +93 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/errors.js.map +1 -0
- package/dist/ffmpeg.d.ts +8 -0
- package/dist/ffmpeg.d.ts.map +1 -0
- package/dist/ffmpeg.js +55 -0
- package/dist/ffmpeg.js.map +1 -0
- package/dist/formats/json.d.ts +12 -0
- package/dist/formats/json.d.ts.map +1 -0
- package/dist/formats/json.js +20 -0
- package/dist/formats/json.js.map +1 -0
- package/dist/formats/markdown/method.d.ts +25 -0
- package/dist/formats/markdown/method.d.ts.map +1 -0
- package/dist/formats/markdown/method.js +48 -0
- package/dist/formats/markdown/method.js.map +1 -0
- package/dist/formats/markdown/parse.d.ts +44 -0
- package/dist/formats/markdown/parse.d.ts.map +1 -0
- package/dist/formats/markdown/parse.js +143 -0
- package/dist/formats/markdown/parse.js.map +1 -0
- package/dist/fs.d.ts +9 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +30 -0
- package/dist/fs.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +21 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +45 -0
- package/dist/logger.js.map +1 -0
- package/dist/schema.d.ts +5 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +100 -0
- package/dist/schema.js.map +1 -0
- package/dist/script.d.ts +21 -0
- package/dist/script.d.ts.map +1 -0
- package/dist/script.js +26 -0
- package/dist/script.js.map +1 -0
- package/dist/targets.d.ts +6 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +13 -0
- package/dist/targets.js.map +1 -0
- package/dist/timing.d.ts +41 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +149 -0
- package/dist/timing.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +8 -0
- package/dist/utils.js.map +1 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +54 -0
- package/dist/validate.js.map +1 -0
- package/dist/video/recorder.d.ts +57 -0
- package/dist/video/recorder.d.ts.map +1 -0
- package/dist/video/recorder.js +238 -0
- package/dist/video/recorder.js.map +1 -0
- package/dist/video/stitch.d.ts +15 -0
- package/dist/video/stitch.d.ts.map +1 -0
- package/dist/video/stitch.js +111 -0
- package/dist/video/stitch.js.map +1 -0
- package/dist/voiceover/alignment.d.ts +14 -0
- package/dist/voiceover/alignment.d.ts.map +1 -0
- package/dist/voiceover/alignment.js +13 -0
- package/dist/voiceover/alignment.js.map +1 -0
- package/dist/voiceover/cache.d.ts +22 -0
- package/dist/voiceover/cache.d.ts.map +1 -0
- package/dist/voiceover/cache.js +55 -0
- package/dist/voiceover/cache.js.map +1 -0
- package/dist/voiceover/compile.d.ts +35 -0
- package/dist/voiceover/compile.d.ts.map +1 -0
- package/dist/voiceover/compile.js +194 -0
- package/dist/voiceover/compile.js.map +1 -0
- package/dist/voiceover/elevenlabs.d.ts +16 -0
- package/dist/voiceover/elevenlabs.d.ts.map +1 -0
- package/dist/voiceover/elevenlabs.js +66 -0
- package/dist/voiceover/elevenlabs.js.map +1 -0
- package/dist/voiceover/index.d.ts +7 -0
- package/dist/voiceover/index.d.ts.map +1 -0
- package/dist/voiceover/index.js +8 -0
- package/dist/voiceover/index.js.map +1 -0
- package/dist/voiceover/mock.d.ts +15 -0
- package/dist/voiceover/mock.d.ts.map +1 -0
- package/dist/voiceover/mock.js +41 -0
- package/dist/voiceover/mock.js.map +1 -0
- package/dist/voiceover/types.d.ts +31 -0
- package/dist/voiceover/types.d.ts.map +1 -0
- package/dist/voiceover/types.js +10 -0
- package/dist/voiceover/types.js.map +1 -0
- package/package.json +86 -0
- package/recordable.schema.json +738 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import matter from "gray-matter";
|
|
2
|
+
import MarkdownIt from "markdown-it";
|
|
3
|
+
import { callToAction } from "../../actions.js";
|
|
4
|
+
import { parseVoiceover } from "../../validate.js";
|
|
5
|
+
import { isMethodCall, parseMethodCall, parseMethodCalls, } from "./method.js";
|
|
6
|
+
// ─── Markdown authoring surface ──────────────────────────────────────────────
|
|
7
|
+
//
|
|
8
|
+
// A recording can be authored as Markdown: fluent-API calls as inline backtick
|
|
9
|
+
// spans inside narration prose (voiceover/timed), or a fenced block of one call
|
|
10
|
+
// per line (a pure action list, no narration). It's a *surface* over the same
|
|
11
|
+
// keyed-action IR the JSON layer uses — every call goes through `callToAction`.
|
|
12
|
+
//
|
|
13
|
+
// markdown-it tokenises the document, so the awkward cases (blank-line
|
|
14
|
+
// boundaries, indented/`~~~` fences, code spans with commas or parens) are the
|
|
15
|
+
// library's problem; we only interpret the tokens.
|
|
16
|
+
//
|
|
17
|
+
// Pure and browser-free: no TTS, ffmpeg or runtime. The voiceover add-on consumes
|
|
18
|
+
// the offset-bearing narration blocks for timing; the core path extracts markers
|
|
19
|
+
// to a plain action list, exactly as JSON would run.
|
|
20
|
+
const md = new MarkdownIt();
|
|
21
|
+
// Sentinel marking a removed call-span while we normalise narration whitespace.
|
|
22
|
+
// A NUL never appears in prose and survives `\s+` collapsing (it isn't \s).
|
|
23
|
+
const SENTINEL = "\u0000";
|
|
24
|
+
/**
|
|
25
|
+
* Parse a Markdown document into config + ordered blocks. Pure: no audio, no
|
|
26
|
+
* network. Frontmatter (YAML, via gray-matter) carries recording config and an
|
|
27
|
+
* optional `voiceover` block; everything else is body content.
|
|
28
|
+
*/
|
|
29
|
+
export function parseMarkdown(md) {
|
|
30
|
+
const { data, content } = matter(md);
|
|
31
|
+
const { voiceover, ...config } = (data ?? {});
|
|
32
|
+
// `voiceover: true` opts in with everything from the environment (provider,
|
|
33
|
+
// voice, model); `false`/absent stays a plain, audio-free recording. An object
|
|
34
|
+
// is validated so a typo'd key (e.g. `voicId`) fails clearly here.
|
|
35
|
+
const vo = voiceover === true
|
|
36
|
+
? {}
|
|
37
|
+
: voiceover === false || voiceover === undefined
|
|
38
|
+
? undefined
|
|
39
|
+
: parseVoiceover(voiceover);
|
|
40
|
+
return {
|
|
41
|
+
config: config,
|
|
42
|
+
voiceover: vo,
|
|
43
|
+
blocks: parseBlocks(content),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Tokenise the body and emit a block per top-level token: any fenced/indented
|
|
48
|
+
* code block becomes an action list (the language tag is a visual aid only and is
|
|
49
|
+
* ignored), and each paragraph becomes a narration block.
|
|
50
|
+
*/
|
|
51
|
+
function parseBlocks(content) {
|
|
52
|
+
const blocks = [];
|
|
53
|
+
for (const t of md.parse(content, {})) {
|
|
54
|
+
if (t.type === "fence" || t.type === "code_block") {
|
|
55
|
+
const actions = parseMethodCalls(t.content).map((c) => callToAction(c.name, c.args));
|
|
56
|
+
if (actions.length)
|
|
57
|
+
blocks.push({ type: "actions", actions });
|
|
58
|
+
}
|
|
59
|
+
else if (t.type === "inline") {
|
|
60
|
+
// The `inline` token carries a paragraph's (or heading's) content.
|
|
61
|
+
const block = narrationFromInline(t.children ?? []);
|
|
62
|
+
if (block.narration || block.markers.length)
|
|
63
|
+
blocks.push(block);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return blocks;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Turn one prose paragraph into narration + markers. Call-shaped backtick spans
|
|
70
|
+
* are lifted out as markers; their character offset into the *stripped*
|
|
71
|
+
* narration (what TTS reads) is preserved for the compiler. Non-call backtick
|
|
72
|
+
* spans stay in the prose verbatim. Whitespace is collapsed without shifting any
|
|
73
|
+
* recorded offset.
|
|
74
|
+
*/
|
|
75
|
+
export function narrationBlock(raw) {
|
|
76
|
+
return narrationFromInline(md.parseInline(raw, {})[0]?.children ?? []);
|
|
77
|
+
}
|
|
78
|
+
/** Build a narration block from a paragraph's inline tokens (markdown-it). */
|
|
79
|
+
function narrationFromInline(children) {
|
|
80
|
+
const calls = [];
|
|
81
|
+
// Flatten the inline tokens to text, replacing each method-call span with a
|
|
82
|
+
// single sentinel and keeping non-call code spans (and other prose) verbatim.
|
|
83
|
+
// Each span holds at most one call, so a call span maps to exactly one marker.
|
|
84
|
+
let s = "";
|
|
85
|
+
for (const tok of children) {
|
|
86
|
+
if (tok.type === "code_inline" && isMethodCall(tok.content)) {
|
|
87
|
+
calls.push(parseMethodCall(tok.content));
|
|
88
|
+
s += SENTINEL;
|
|
89
|
+
}
|
|
90
|
+
else if (tok.type === "code_inline") {
|
|
91
|
+
s += "`" + tok.content + "`";
|
|
92
|
+
}
|
|
93
|
+
else if (tok.type === "softbreak" || tok.type === "hardbreak") {
|
|
94
|
+
s += " ";
|
|
95
|
+
}
|
|
96
|
+
else if (tok.type === "text") {
|
|
97
|
+
s += tok.content;
|
|
98
|
+
}
|
|
99
|
+
// Emphasis/link wrappers (em_open, link_open, …) carry no text of their own;
|
|
100
|
+
// their text arrives as separate `text` children, so they're skipped here.
|
|
101
|
+
}
|
|
102
|
+
// Collapse all whitespace to single spaces, then drop a space immediately
|
|
103
|
+
// after a sentinel so removing it later never leaves a double space (a single
|
|
104
|
+
// leading space before the sentinel is kept as the word boundary).
|
|
105
|
+
s = s.replace(/\s+/g, " ").trim();
|
|
106
|
+
s = s.replace(new RegExp(SENTINEL + " ", "g"), SENTINEL);
|
|
107
|
+
let narration = "";
|
|
108
|
+
const markers = [];
|
|
109
|
+
let ci = 0;
|
|
110
|
+
for (const ch of s) {
|
|
111
|
+
if (ch === SENTINEL) {
|
|
112
|
+
const c = calls[ci++];
|
|
113
|
+
markers.push({
|
|
114
|
+
step: callToAction(c.name, c.args),
|
|
115
|
+
offset: narration.length,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
narration += ch;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// A trailing marker leaves a dangling space ("Lumen. ▮"); drop it and clamp
|
|
123
|
+
// any offset that now points past the end so it fires after the last word.
|
|
124
|
+
narration = narration.replace(/\s+$/, "");
|
|
125
|
+
for (const m of markers)
|
|
126
|
+
if (m.offset > narration.length)
|
|
127
|
+
m.offset = narration.length;
|
|
128
|
+
return { type: "narration", narration, markers };
|
|
129
|
+
}
|
|
130
|
+
/** Extract a plain action list from parsed blocks (markers in order, narration
|
|
131
|
+
* and timing discarded; no audio). */
|
|
132
|
+
export function extractActions(blocks) {
|
|
133
|
+
const actions = [];
|
|
134
|
+
for (const b of blocks) {
|
|
135
|
+
if (b.type === "actions")
|
|
136
|
+
actions.push(...b.actions);
|
|
137
|
+
else
|
|
138
|
+
for (const m of b.markers)
|
|
139
|
+
actions.push(m.step);
|
|
140
|
+
}
|
|
141
|
+
return actions;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/formats/markdown/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/fs.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Move a file, falling back to copy+unlink across filesystem boundaries. */
|
|
2
|
+
export declare function moveFile(src: string, dest: string): void;
|
|
3
|
+
/** Build the timestamped output path and ensure its directory exists. */
|
|
4
|
+
export declare function getOutputPath(opts: {
|
|
5
|
+
outputDir: string;
|
|
6
|
+
outputName: string;
|
|
7
|
+
outputTimestamp: boolean;
|
|
8
|
+
}): string;
|
|
9
|
+
//# sourceMappingURL=fs.d.ts.map
|
package/dist/fs.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAKA,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAYxD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;CAC1B,GAAG,MAAM,CAQT"}
|
package/dist/fs.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Filesystem helpers: cross-device-safe move and timestamped output-path build.
|
|
2
|
+
import { mkdirSync, renameSync, copyFileSync, unlinkSync } from "node:fs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
/** Move a file, falling back to copy+unlink across filesystem boundaries. */
|
|
5
|
+
export function moveFile(src, dest) {
|
|
6
|
+
try {
|
|
7
|
+
renameSync(src, dest);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// Cross-device (tmp on a different filesystem) — copy then unlink.
|
|
11
|
+
copyFileSync(src, dest);
|
|
12
|
+
try {
|
|
13
|
+
unlinkSync(src);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
/* best effort */
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Build the timestamped output path and ensure its directory exists. */
|
|
21
|
+
export function getOutputPath(opts) {
|
|
22
|
+
const { outputDir, outputName, outputTimestamp } = opts;
|
|
23
|
+
const timestamp = outputTimestamp
|
|
24
|
+
? "-" + new Date().toISOString().replace(/\D/g, "").slice(0, 14)
|
|
25
|
+
: "";
|
|
26
|
+
const out = `${outputDir}/${outputName}${timestamp}.mp4`;
|
|
27
|
+
mkdirSync(dirname(out), { recursive: true });
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=fs.js.map
|
package/dist/fs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,IAAY;IAChD,IAAI,CAAC;QACH,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;QACnE,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC;YACH,UAAU,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,IAI7B;IACC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACxD,MAAM,SAAS,GAAG,eAAe;QAC/B,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChE,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,GAAG,GAAG,GAAG,SAAS,IAAI,UAAU,GAAG,SAAS,MAAM,CAAC;IACzD,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Recordable } from "./compose/recordable.js";
|
|
2
|
+
export { ACTIONS, callToAction, validateAction } from "./actions.js";
|
|
3
|
+
export type { Action } from "./actions.js";
|
|
4
|
+
export type { Script } from "./script.js";
|
|
5
|
+
export { fromJSON, runScript } from "./formats/json.js";
|
|
6
|
+
export { buildSchema } from "./schema.js";
|
|
7
|
+
export { parseMarkdown } from "./formats/markdown/parse.js";
|
|
8
|
+
export type { ParsedMarkdown, MarkdownBlock, NarrationBlock, ActionsBlock, } from "./formats/markdown/parse.js";
|
|
9
|
+
export type { RecordableConfig, VoiceoverConfig, AudioOptions, InsertOptions, WaitForOptions, ResolvedConfig, } from "./config.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrE,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Recordable } from "./compose/recordable.js";
|
|
2
|
+
export { ACTIONS, callToAction, validateAction } from "./actions.js";
|
|
3
|
+
export { fromJSON, runScript } from "./formats/json.js";
|
|
4
|
+
export { buildSchema } from "./schema.js";
|
|
5
|
+
export { parseMarkdown } from "./formats/markdown/parse.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGrE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A callable logger. Call it for a normal progress line — a padded `name` label
|
|
3
|
+
* plus an optional value — and use `.success` / `.warn` / `.error` for status,
|
|
4
|
+
* conveyed by the colour of the `[Recordable]` prefix: blue progress, green
|
|
5
|
+
* success, yellow warn, red error. Stream + `silent` behaviour per method below.
|
|
6
|
+
*/
|
|
7
|
+
export interface Logger {
|
|
8
|
+
(name: string, value?: string): void;
|
|
9
|
+
/** Completion line, green prefix → stdout. Suppressed when `silent`. */
|
|
10
|
+
success(name: string, value?: string): void;
|
|
11
|
+
/** Non-fatal diagnostic → stderr. Suppressed when `silent`. */
|
|
12
|
+
warn(message: string): void;
|
|
13
|
+
/** Failure → stderr. Always printed, even when `silent`. */
|
|
14
|
+
error(message: string): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build a logger. `isSilent` is read on every call so runtime `silent` changes
|
|
18
|
+
* (via `setConfig`) take effect immediately.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createLogger(isSilent: () => boolean): Logger;
|
|
21
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,wEAAwE;IACxE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,+DAA+D;IAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4DAA4D;IAC5D,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AA6BD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,OAAO,GAAG,MAAM,CAiB5D"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Console logger: a status-coloured `[Recordable]` prefix plus a message body.
|
|
2
|
+
const PREFIX = "[Recordable]";
|
|
3
|
+
// 256-colour codes for the prefix, keyed by status.
|
|
4
|
+
const COLOR = {
|
|
5
|
+
info: "38;5;111",
|
|
6
|
+
success: "38;5;114",
|
|
7
|
+
warn: "38;5;221",
|
|
8
|
+
error: "38;5;203",
|
|
9
|
+
};
|
|
10
|
+
/** Colour is on only for TTY streams, and never when NO_COLOR is set. */
|
|
11
|
+
function colorEnabled(stream) {
|
|
12
|
+
return !process.env.NO_COLOR && Boolean(stream.isTTY);
|
|
13
|
+
}
|
|
14
|
+
/** Format a line: a status-coloured prefix followed by the message body. */
|
|
15
|
+
function format(code, stream, label, value) {
|
|
16
|
+
const prefix = colorEnabled(stream) ? `\x1b[${code}m${PREFIX}\x1b[0m` : PREFIX;
|
|
17
|
+
const body = value !== undefined ? `${label.padEnd(8)}${value}` : label;
|
|
18
|
+
return `${prefix} ${body}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build a logger. `isSilent` is read on every call so runtime `silent` changes
|
|
22
|
+
* (via `setConfig`) take effect immediately.
|
|
23
|
+
*/
|
|
24
|
+
export function createLogger(isSilent) {
|
|
25
|
+
const log = ((name, value) => {
|
|
26
|
+
if (isSilent())
|
|
27
|
+
return;
|
|
28
|
+
console.log(format(COLOR.info, process.stdout, name, value));
|
|
29
|
+
});
|
|
30
|
+
log.success = (name, value) => {
|
|
31
|
+
if (isSilent())
|
|
32
|
+
return;
|
|
33
|
+
console.log(format(COLOR.success, process.stdout, name, value));
|
|
34
|
+
};
|
|
35
|
+
log.warn = (message) => {
|
|
36
|
+
if (isSilent())
|
|
37
|
+
return;
|
|
38
|
+
console.warn(format(COLOR.warn, process.stderr, message));
|
|
39
|
+
};
|
|
40
|
+
log.error = (message) => {
|
|
41
|
+
console.error(format(COLOR.error, process.stderr, message));
|
|
42
|
+
};
|
|
43
|
+
return log;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAkB/E,MAAM,MAAM,GAAG,cAAc,CAAC;AAE9B,oDAAoD;AACpD,MAAM,KAAK,GAAG;IACZ,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,UAAU;IACnB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,UAAU;CAClB,CAAC;AAEF,yEAAyE;AACzE,SAAS,YAAY,CAAC,MAA0B;IAC9C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,4EAA4E;AAC5E,SAAS,MAAM,CACb,IAAY,EACZ,MAA0B,EAC1B,KAAa,EACb,KAAc;IAEd,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,MAAM,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/E,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IACxE,OAAO,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,QAAuB;IAClD,MAAM,GAAG,GAAG,CAAC,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QAC5C,IAAI,QAAQ,EAAE;YAAE,OAAO;QACvB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAW,CAAC;IACb,GAAG,CAAC,OAAO,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,IAAI,QAAQ,EAAE;YAAE,OAAO;QACvB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC;IACF,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE;QACrB,IAAI,QAAQ,EAAE;YAAE,OAAO;QACvB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC;IACF,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,EAAE;QACtB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAYA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA6E1C,+DAA+D;AAC/D,wBAAgB,WAAW,IAAI,UAAU,CA+BxC"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { ACTIONS } from "./actions.js";
|
|
3
|
+
import { ConfigSchema } from "./config.js";
|
|
4
|
+
const SCHEMA_URL = "https://json-schema.org/draft/2020-12/schema";
|
|
5
|
+
/** Recursively delete every `key` from a JSON Schema object tree. */
|
|
6
|
+
function stripKey(node, key) {
|
|
7
|
+
if (Array.isArray(node)) {
|
|
8
|
+
node.forEach((n) => stripKey(n, key));
|
|
9
|
+
}
|
|
10
|
+
else if (node && typeof node === "object") {
|
|
11
|
+
delete node[key];
|
|
12
|
+
Object.values(node).forEach((v) => stripKey(v, key));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** The properties + required keys an action contributes (beyond `action`),
|
|
16
|
+
* read from its Zod schema. `setConfig`'s nested config points at the shared
|
|
17
|
+
* `$defs/config` rather than inlining the whole config schema. */
|
|
18
|
+
function actionShape(name) {
|
|
19
|
+
const js = z.toJSONSchema(ACTIONS[name], {
|
|
20
|
+
io: "input",
|
|
21
|
+
});
|
|
22
|
+
const properties = (js.properties ?? {});
|
|
23
|
+
const required = (js.required ?? []);
|
|
24
|
+
if ("config" in properties)
|
|
25
|
+
properties.config = { $ref: "#/$defs/config" };
|
|
26
|
+
return { properties, required };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The `action` schema: a single object whose `action` key enumerates every action,
|
|
30
|
+
* with one `if/then` per action applying that action's keys.
|
|
31
|
+
*
|
|
32
|
+
* This shape (rather than a `oneOf` of per-action objects) is what makes editor
|
|
33
|
+
* autocomplete offer *all* action names: VS Code only suggests `const` values
|
|
34
|
+
* from `oneOf` branches the current object already satisfies, so a `oneOf` lists
|
|
35
|
+
* just the no-arg actions until you've typed the other keys. The `enum` + `then`
|
|
36
|
+
* form keeps full autocomplete while preserving required-key and typo checks.
|
|
37
|
+
*/
|
|
38
|
+
function actionSchema() {
|
|
39
|
+
const actions = Object.keys(ACTIONS);
|
|
40
|
+
const allOf = actions.map((action) => {
|
|
41
|
+
const { properties, required } = actionShape(action);
|
|
42
|
+
return {
|
|
43
|
+
if: { properties: { action: { const: action } }, required: ["action"] },
|
|
44
|
+
then: {
|
|
45
|
+
properties: { action: { const: action }, ...properties },
|
|
46
|
+
required: ["action", ...required],
|
|
47
|
+
additionalProperties: false,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
type: "object",
|
|
53
|
+
required: ["action"],
|
|
54
|
+
properties: {
|
|
55
|
+
action: { enum: actions, description: "The action to perform." },
|
|
56
|
+
},
|
|
57
|
+
allOf,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Schema for the `config` block — derived from the Zod {@link ConfigSchema}.
|
|
61
|
+
* Uses the input view (every field optional) and strips the emitted defaults so
|
|
62
|
+
* the authoring schema stays type-only. `baseDir` is set by the CLI/runtime, not
|
|
63
|
+
* authored in script files, so it's omitted. */
|
|
64
|
+
function configSchema() {
|
|
65
|
+
const schema = z.toJSONSchema(ConfigSchema, { io: "input" });
|
|
66
|
+
delete schema.$schema;
|
|
67
|
+
stripKey(schema, "default");
|
|
68
|
+
delete schema.properties.baseDir;
|
|
69
|
+
return schema;
|
|
70
|
+
}
|
|
71
|
+
/** Build the full JSON Schema for a Recordable script file. */
|
|
72
|
+
export function buildSchema() {
|
|
73
|
+
const action = actionSchema();
|
|
74
|
+
const objectForm = {
|
|
75
|
+
type: "object",
|
|
76
|
+
required: ["actions"],
|
|
77
|
+
additionalProperties: false,
|
|
78
|
+
properties: {
|
|
79
|
+
$schema: { type: "string" },
|
|
80
|
+
config: { $ref: "#/$defs/config" },
|
|
81
|
+
actions: { type: "array", items: { $ref: "#/$defs/action" } },
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
const arrayForm = {
|
|
85
|
+
type: "array",
|
|
86
|
+
items: { $ref: "#/$defs/action" },
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
$schema: SCHEMA_URL,
|
|
90
|
+
$id: "https://raw.githubusercontent.com/paragramagency/recordable/main/recordable.schema.json",
|
|
91
|
+
title: "Recordable script",
|
|
92
|
+
description: "A declarative recording script: config + an array of actions.",
|
|
93
|
+
oneOf: [objectForm, arrayForm],
|
|
94
|
+
$defs: {
|
|
95
|
+
config: configSchema(),
|
|
96
|
+
action,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/script.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Action } from "./actions.js";
|
|
2
|
+
import type { RecordableConfig } from "./config.js";
|
|
3
|
+
/** A whole script: a bare array of actions, or an object pairing config + actions. */
|
|
4
|
+
export type Script = Action[] | {
|
|
5
|
+
$schema?: string;
|
|
6
|
+
config?: RecordableConfig;
|
|
7
|
+
actions: Action[];
|
|
8
|
+
};
|
|
9
|
+
/** Split a `Script` into its optional config and action array. */
|
|
10
|
+
export declare function splitScript(script: Script): {
|
|
11
|
+
config?: RecordableConfig;
|
|
12
|
+
actions: Action[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Resolve relative `visit` URLs (`./`, `../`) against `baseDir` so a script and
|
|
16
|
+
* its pages travel together regardless of cwd: each becomes a `file://` URL.
|
|
17
|
+
* Mutates the actions in place; a no-op when `baseDir` is empty.
|
|
18
|
+
* (Relative `outputDir`/`assetsDir` are resolved alongside, in the config.)
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveVisitUrls(actions: Action[], baseDir: string): void;
|
|
21
|
+
//# sourceMappingURL=script.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../src/script.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAsBpD,sFAAsF;AACtF,MAAM,MAAM,MAAM,GACd,MAAM,EAAE,GACR;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvE,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;IAC3C,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAGA;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAWzE"}
|
package/dist/script.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
/** Split a `Script` into its optional config and action array. */
|
|
4
|
+
export function splitScript(script) {
|
|
5
|
+
if (Array.isArray(script))
|
|
6
|
+
return { actions: script };
|
|
7
|
+
return { config: script.config, actions: script.actions };
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve relative `visit` URLs (`./`, `../`) against `baseDir` so a script and
|
|
11
|
+
* its pages travel together regardless of cwd: each becomes a `file://` URL.
|
|
12
|
+
* Mutates the actions in place; a no-op when `baseDir` is empty.
|
|
13
|
+
* (Relative `outputDir`/`assetsDir` are resolved alongside, in the config.)
|
|
14
|
+
*/
|
|
15
|
+
export function resolveVisitUrls(actions, baseDir) {
|
|
16
|
+
if (!baseDir)
|
|
17
|
+
return;
|
|
18
|
+
for (const step of actions) {
|
|
19
|
+
if (step.action === "visit" &&
|
|
20
|
+
typeof step.url === "string" &&
|
|
21
|
+
/^\.\.?\//.test(step.url)) {
|
|
22
|
+
step.url = pathToFileURL(resolve(baseDir, step.url)).href;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script.js","sourceRoot":"","sources":["../src/script.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA6BzC,kEAAkE;AAClE,MAAM,UAAU,WAAW,CAAC,MAAc;IAIxC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACtD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;AAC5D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAiB,EAAE,OAAe;IACjE,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IACE,IAAI,CAAC,MAAM,KAAK,OAAO;YACvB,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ;YAC5B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EACzB,CAAC;YACD,IAAI,CAAC,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Resolve a target string to a Puppeteer selector.
|
|
2
|
+
* Prefix with `text:` for plain-text matching; everything else is a CSS selector. */
|
|
3
|
+
export declare function resolveTarget(target: string): string;
|
|
4
|
+
/** Returns true if the string is a CSS position keyword or percentage. */
|
|
5
|
+
export declare function isPositionValue(value: string): boolean;
|
|
6
|
+
//# sourceMappingURL=targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAGA;sFACsF;AACtF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGtD"}
|
package/dist/targets.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Target resolution: author-facing target strings → Puppeteer selectors, plus
|
|
2
|
+
// the position-keyword test used by zoom/scroll origins.
|
|
3
|
+
/** Resolve a target string to a Puppeteer selector.
|
|
4
|
+
* Prefix with `text:` for plain-text matching; everything else is a CSS selector. */
|
|
5
|
+
export function resolveTarget(target) {
|
|
6
|
+
return target.startsWith("text:") ? `::-p-text(${target.slice(5)})` : target;
|
|
7
|
+
}
|
|
8
|
+
/** Returns true if the string is a CSS position keyword or percentage. */
|
|
9
|
+
export function isPositionValue(value) {
|
|
10
|
+
const token = "(top|bottom|left|right|center|\\d+%)";
|
|
11
|
+
return new RegExp(`^${token}(\\s+${token})?$`, "i").test(value.trim());
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=targets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,yDAAyD;AAEzD;sFACsF;AACtF,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAC/E,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"}
|
package/dist/timing.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { RecordableConfig } from "./config.js";
|
|
2
|
+
import type { Action } from "./actions.js";
|
|
3
|
+
/** Cursor "press" dip on click — scale down… */
|
|
4
|
+
export declare const PRESS_DOWN_MS = 120;
|
|
5
|
+
/** …then settle back. clickEffect spends their sum. */
|
|
6
|
+
export declare const PRESS_SETTLE_MS = 60;
|
|
7
|
+
/** Settle beat between arriving at a target and pressing (jitter base). */
|
|
8
|
+
export declare const PRE_CLICK_MS = 100;
|
|
9
|
+
/** Post-click probe: how long a click waits for a possible navigation to begin. */
|
|
10
|
+
export declare const NAV_PROBE_MS = 200;
|
|
11
|
+
/** Cursor-move duration for a known pixel distance — eased, clamped. */
|
|
12
|
+
export declare function cursorMoveMs(dist: number): number;
|
|
13
|
+
/** Estimated wall-clock an interactive action spends getting the cursor to its
|
|
14
|
+
* target and pressing — *before* its payload (the keystrokes of a `type`, the
|
|
15
|
+
* value-set of a `select`). The compiler adds this to elapsed so the next
|
|
16
|
+
* narrated word is placed after the gesture, not on top of it. With the cursor
|
|
17
|
+
* overlay off, only the real (non-animated) costs remain. */
|
|
18
|
+
export declare function gestureLeadMs(step: Action, cfg: RecordableConfig): number;
|
|
19
|
+
/** How long an action occupies the timeline, so the next wait measures from its end.
|
|
20
|
+
* Omitted durations use the config default, never an elastic fit. The cursor's
|
|
21
|
+
* travel-and-press to a target (`gestureLeadMs`) is added on top, so a click/type
|
|
22
|
+
* doesn't silently push the rest of the paragraph late. */
|
|
23
|
+
export declare function actionDurationMs(step: Action, cfg: RecordableConfig): Promise<number>;
|
|
24
|
+
/** Returns `base` ± `variance` (defaults to ±50% of base). */
|
|
25
|
+
export declare function jitter(base: number, variance?: number): number;
|
|
26
|
+
/** Deterministic 32-bit string hash (FNV-1a). Seeds the typing PRNG so the same
|
|
27
|
+
* text always types with the same rhythm (reproducible recordings). */
|
|
28
|
+
export declare function hashString(s: string): number;
|
|
29
|
+
/** mulberry32 PRNG → a function yielding floats in [0, 1). Pure integer math,
|
|
30
|
+
* platform-independent, so a given seed reproduces the same sequence anywhere. */
|
|
31
|
+
export declare function rng(seed: number): () => number;
|
|
32
|
+
/** Total time (ms) a `type` action occupies — a pure function of text length and
|
|
33
|
+
* speed (cps). This is the contract the voiceover compiler estimates against, so
|
|
34
|
+
* it MUST stay identical to the compiler's `type` estimate. Jitter never alters it. */
|
|
35
|
+
export declare function typingDuration(text: string, speed: number): number;
|
|
36
|
+
/** Per-keystroke delays (ms) that sum to exactly `total`, with seeded, zero-sum
|
|
37
|
+
* jitter. Returns `[leadPause, delayAfterChar1, …]` (lead beat + one per code
|
|
38
|
+
* point). Punctuation gets a heavier structural weight (a natural micro-pause),
|
|
39
|
+
* but all weights are normalised back onto `total` so the sum is invariant. */
|
|
40
|
+
export declare function typingGaps(text: string, speed: number, total?: number, amount?: number): number[];
|
|
41
|
+
//# sourceMappingURL=timing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAW3C,gDAAgD;AAChD,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,uDAAuD;AACvD,eAAO,MAAM,eAAe,KAAK,CAAC;AAIlC,2EAA2E;AAC3E,eAAO,MAAM,YAAY,MAAM,CAAC;AAEhC,mFAAmF;AACnF,eAAO,MAAM,YAAY,MAAM,CAAC;AAMhC,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAQD;;;;8DAI8D;AAC9D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAmBzE;AAED;;;4DAG4D;AAC5D,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAID,8DAA8D;AAC9D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAE3D;AAQD;wEACwE;AACxE,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAO5C;AAED;mFACmF;AACnF,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAQ9C;AAED;;wFAEwF;AACxF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;gFAGgF;AAChF,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAoC,EAC3C,MAAM,SAAO,GACZ,MAAM,EAAE,CAgBV"}
|