@vosjs/render-core 0.8.0 → 0.10.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.
@@ -1,4 +1,5 @@
1
- import { RecordingMeta, CursorEvent, RecordingSkip, RecordingOutput, Backdrop, RecordingArtifact, ProjectDoc, RecordingPageMedia } from '@vosjs/studio-core';
1
+ import { RecordingMeta, PeerStepSpan, CursorEvent, RecordingSkip, RecordingOutput, Backdrop, RecordingArtifact, ProjectDoc, RecordingPageMedia } from '@vosjs/studio-core';
2
+ export { PeerStepSpan } from '@vosjs/studio-core';
2
3
 
3
4
  /**
4
5
  * The recorder's driver: what it needs from a browser, as a STRUCTURAL
@@ -415,6 +416,156 @@ declare function deadWarns(r: DeadReport): boolean;
415
416
  /** The dead time in words, naming the steps and what to cut. */
416
417
  declare function deadLine(r: DeadReport): string;
417
418
 
419
+ /**
420
+ * `setup`: the steps that run BEFORE the camera rolls. A sign-in form, a
421
+ * cookie banner, the "choose your editor" modal, an onboarding tour: things
422
+ * a take must get past and must not show. They run after the first
423
+ * navigation and before `Page.startScreencast`, with no cursor synthesis,
424
+ * no pace accounting and nothing written to `meta.steps`. Then the recorder
425
+ * navigates to `url` again and the take begins where the setup left it.
426
+ *
427
+ * A `type` step's `text` may be `{ "env": "DEMO_PASSWORD" }`: resolved at run
428
+ * time from the `env` the caller hands in (the shell's for the CLI, the
429
+ * job's own map for a hosted take), never logged, never stored. The
430
+ * guarantee is narrow and real: the secret is never in a file that travels
431
+ * (`actions.json` is committed and pushed with the take; `meta.json` is read
432
+ * by the digest) and never in the footage.
433
+ *
434
+ * `teardown`: the same steps, run AFTER the take, off camera too: what the
435
+ * take created in the product (an API key, a project, an invite) removed
436
+ * again, so a rehearsal or a re-record leaves the account as it found it.
437
+ * They run once the screencast has stopped, on the take's own page and
438
+ * context (a session's cookies apply), and also when the take stops early
439
+ * or throws once its first step has run. A teardown that fails never fails
440
+ * the take: the footage is fine, and what is left behind is reported.
441
+ */
442
+
443
+ type SetupText = string | {
444
+ env: string;
445
+ };
446
+ type SetupStep = ({
447
+ do: 'wait';
448
+ ms: number;
449
+ } | {
450
+ do: 'click';
451
+ selector: string;
452
+ ms?: number;
453
+ } | {
454
+ do: 'type';
455
+ selector: string;
456
+ text: SetupText;
457
+ ms?: number;
458
+ } | {
459
+ do: 'press';
460
+ key: string;
461
+ ms?: number;
462
+ } | {
463
+ do: 'goto';
464
+ url: string;
465
+ }) & {
466
+ id?: string;
467
+ };
468
+ /** Which list a step belongs to, as its messages and log lines name it. */
469
+ type StepPhase = 'setup' | 'teardown';
470
+ /**
471
+ * Why a page address is not one the recorder opens, or null. A script's
472
+ * `url` and a setup's `goto` open a browser, so only http and https are
473
+ * taken: a `file:` address would read this machine's disk into a take
474
+ * and a `javascript:` one would run in the page.
475
+ */
476
+ declare function urlSchemeProblem(url: string): string | null;
477
+ /**
478
+ * Structural validation, mirrored on `validateActions` for `steps`. The
479
+ * same verbs and rules hold for `teardown`; `phase` names the list.
480
+ */
481
+ declare function validateSetup(value: unknown, phase?: StepPhase): string[];
482
+ /** The names a setup reads from its env, so a host can say what it must supply. */
483
+ declare function setupEnvNames(steps: SetupStep[] | undefined): string[];
484
+ /**
485
+ * Every name a script reads from its env, its setup's and its teardown's,
486
+ * each once: what a host must supply before the take begins.
487
+ */
488
+ declare function scriptEnvNames(script: {
489
+ setup?: SetupStep[];
490
+ teardown?: SetupStep[];
491
+ }): string[];
492
+ /** A `{ env }` text resolved, or thrown in words. The value is never returned to a log. */
493
+ declare function resolveSetupText(t: SetupText, env: Record<string, string | undefined>, phase?: StepPhase): {
494
+ value: string;
495
+ secret: boolean;
496
+ };
497
+ /**
498
+ * The first `{ env }` a teardown reads that `env` does not hold, in words,
499
+ * or null. Asked BEFORE the take: a take that creates something its
500
+ * teardown cannot then remove is the one case teardown exists for.
501
+ */
502
+ declare function teardownEnvProblem(steps: SetupStep[] | undefined, env: Record<string, string | undefined>): string | null;
503
+ interface SetupResult {
504
+ ran: number;
505
+ /** what the log may say about each step: the verb and the selector, never a typed value */
506
+ lines: string[];
507
+ /**
508
+ * The step that failed: for a setup, a selector that never appeared (the
509
+ * take does not start); for a teardown, the step it stopped at. `error`
510
+ * is the driver's reason, one line, never a typed value.
511
+ */
512
+ failed?: {
513
+ step: number;
514
+ do: string;
515
+ selector?: string;
516
+ error?: string;
517
+ };
518
+ }
519
+ /** How long a whole teardown may take before it is stopped and reported. */
520
+ declare const TEARDOWN_BOUND_MS = 60000;
521
+ /**
522
+ * What a teardown did, on the take's result: how many of its steps ran,
523
+ * and where it stopped. Never a typed value.
524
+ */
525
+ interface TeardownReport {
526
+ ran: number;
527
+ of: number;
528
+ failed?: {
529
+ step: number;
530
+ do: string;
531
+ selector?: string;
532
+ error: string;
533
+ };
534
+ }
535
+ /** The teardown in one line, for the end of a take or a rehearsal. */
536
+ declare function teardownLine(report: TeardownReport): string;
537
+ /**
538
+ * Run the setup (or the teardown) on a page, with plain Playwright actions:
539
+ * no humanized pointer, no cursor events, no frames. A selector that never
540
+ * appears fails the steps there, because a take that begins at a
541
+ * half-finished sign-in is the wall by another name. With `boundMs`, the
542
+ * steps together run no longer than that: the step running when it passes
543
+ * fails, and the call it left pending is abandoned.
544
+ */
545
+ declare function runSetup(page: RecorderPage, steps: SetupStep[], opts: {
546
+ sleep: (ms: number) => Promise<void>;
547
+ /** Absent means no env at all: a `{ env }` text then fails in words. */
548
+ env?: Record<string, string | undefined>;
549
+ /** How a `goto` opens its page and waits for it (the take's ready mode); absent, network idle. */
550
+ goto?: (url: string) => Promise<unknown>;
551
+ /** Which list these are, for the log and the messages (default `setup`). */
552
+ phase?: StepPhase;
553
+ /** The longest the steps may take together, in ms. */
554
+ boundMs?: number;
555
+ now?: () => number;
556
+ }): Promise<SetupResult>;
557
+ /** A `{ env }` the shell did not provide: a usage error, not a page's. */
558
+ declare class SetupEnvError extends Error {
559
+ constructor(message: string);
560
+ }
561
+ /** A setup step whose selector never appeared: the take does not start. */
562
+ declare class SetupError extends Error {
563
+ failed: NonNullable<SetupResult['failed']>;
564
+ constructor(failed: NonNullable<SetupResult['failed']>);
565
+ }
566
+ /** `--header name=value`, repeatable: extra request headers on every request. */
567
+ declare function parseHeaders(given: string[] | undefined): Record<string, string>;
568
+
418
569
  /**
419
570
  * The page's own console errors, as the recorder reports them. A page
420
571
  * under recording is someone else's, and its errors are context, never the
@@ -563,99 +714,6 @@ declare function noticeLine(n: Notice): string;
563
714
  */
564
715
  declare function noticeAdvice(notices: readonly Pick<Notice, 'kind'>[]): string;
565
716
 
566
- /**
567
- * `setup`: the steps that run BEFORE the camera rolls. A sign-in form, a
568
- * cookie banner, the "choose your editor" modal, an onboarding tour: things
569
- * a take must get past and must not show. They run after the first
570
- * navigation and before `Page.startScreencast`, with no cursor synthesis,
571
- * no pace accounting and nothing written to `meta.steps`. Then the recorder
572
- * navigates to `url` again and the take begins where the setup left it.
573
- *
574
- * A `type` step's `text` may be `{ "env": "DEMO_PASSWORD" }`: resolved at run
575
- * time from the `env` the caller hands in (the shell's for the CLI, the
576
- * job's own map for a hosted take), never logged, never stored. The
577
- * guarantee is narrow and real: the secret is never in a file that travels
578
- * (`actions.json` is committed and pushed with the take; `meta.json` is read
579
- * by the digest) and never in the footage.
580
- */
581
-
582
- type SetupText = string | {
583
- env: string;
584
- };
585
- type SetupStep = ({
586
- do: 'wait';
587
- ms: number;
588
- } | {
589
- do: 'click';
590
- selector: string;
591
- ms?: number;
592
- } | {
593
- do: 'type';
594
- selector: string;
595
- text: SetupText;
596
- ms?: number;
597
- } | {
598
- do: 'press';
599
- key: string;
600
- ms?: number;
601
- } | {
602
- do: 'goto';
603
- url: string;
604
- }) & {
605
- id?: string;
606
- };
607
- /**
608
- * Why a page address is not one the recorder opens, or null. A script's
609
- * `url` and a setup's `goto` open a browser, so only http and https are
610
- * taken: a `file:` address would read this machine's disk into a take
611
- * and a `javascript:` one would run in the page.
612
- */
613
- declare function urlSchemeProblem(url: string): string | null;
614
- /** Structural validation, mirrored on `validateActions` for `steps`. */
615
- declare function validateSetup(value: unknown): string[];
616
- /** The names a setup reads from its env, so a host can say what it must supply. */
617
- declare function setupEnvNames(steps: SetupStep[] | undefined): string[];
618
- /** A `{ env }` text resolved, or thrown in words. The value is never returned to a log. */
619
- declare function resolveSetupText(t: SetupText, env: Record<string, string | undefined>): {
620
- value: string;
621
- secret: boolean;
622
- };
623
- interface SetupResult {
624
- ran: number;
625
- /** what the log may say about each step: the verb and the selector, never a typed value */
626
- lines: string[];
627
- /** a selector that never appeared; the take does not start */
628
- failed?: {
629
- step: number;
630
- do: string;
631
- selector?: string;
632
- };
633
- }
634
- /**
635
- * Run the setup on a page, with plain Playwright actions: no humanized
636
- * pointer, no cursor events, no frames. A selector that never appears
637
- * fails the setup, because a take that begins at a half-finished sign-in is
638
- * the wall by another name.
639
- */
640
- declare function runSetup(page: RecorderPage, steps: SetupStep[], opts: {
641
- sleep: (ms: number) => Promise<void>;
642
- /** Absent means no env at all: a `{ env }` text then fails in words. */
643
- env?: Record<string, string | undefined>;
644
- /** How a `goto` opens its page and waits for it (the take's ready mode); absent, network idle. */
645
- goto?: (url: string) => Promise<unknown>;
646
- }): Promise<SetupResult>;
647
- /** A `{ env }` the shell did not provide: a usage error, not a page's. */
648
- declare class SetupEnvError extends Error {
649
- constructor(message: string);
650
- }
651
- /** A setup step whose selector never appeared: the take does not start. */
652
- declare class SetupError extends Error {
653
- failed: NonNullable<SetupResult['failed']>;
654
- constructor(failed: NonNullable<SetupResult['failed']>);
655
- }
656
- /** `--header name=value`, repeatable: extra request headers on every request. */
657
- declare function parseHeaders(given: string[] | undefined): Record<string, string>;
658
-
659
717
  /**
660
718
  * When a page counts as ready for the take to begin. The default is the
661
719
  * DOM: after `load`, the page must make no DOM change for a beat (counted
@@ -872,6 +930,278 @@ declare function overrunOf(plannedMs: number, tookMs: number): number | null;
872
930
  /** The overruns in one line for the log and the done event, or null when none. */
873
931
  declare function overrunLine(overruns: readonly StepOverrun[]): string | null;
874
932
 
933
+ /**
934
+ * What an `expect` and an `await` wait for: a condition on the page, read
935
+ * without touching it (no cursor, no input), polled until it holds or the
936
+ * time runs out. `expect` polls on camera for a few seconds; `await` polls
937
+ * off camera for as long as a slow result takes. One reader for both, so
938
+ * "appeared" means the same thing in either.
939
+ */
940
+
941
+ interface WaitCondition {
942
+ /** an element matching this selector is visible */
943
+ selector?: string;
944
+ /** some visible text on the page contains this */
945
+ text?: string;
946
+ /** no element matching this selector is visible */
947
+ gone?: string;
948
+ /** with `selector`: the element is enabled (true) or disabled (false) */
949
+ enabled?: boolean;
950
+ /**
951
+ * A JavaScript expression evaluated in the page (awaited when it answers
952
+ * a promise): the condition holds when its value is truthy, or, with
953
+ * `equals`, when its value equals that one. For an app that keeps its
954
+ * state in script rather than in the DOM (a canvas, a document model).
955
+ */
956
+ js?: string;
957
+ /** with `js`: the value the expression must equal (compared as JSON) */
958
+ equals?: unknown;
959
+ }
960
+ /** What the condition found the last time it looked: what a miss is said from. */
961
+ interface ConditionState {
962
+ holds: boolean;
963
+ /** with `selector`: whether a match was visible */
964
+ visible?: boolean;
965
+ /**
966
+ * with `js`: what the expression answered the last time it was read, as
967
+ * JSON when it has a JSON form (absent for `undefined`), and in words
968
+ * either way (`said`), or the error it threw (`threw`).
969
+ */
970
+ value?: unknown;
971
+ said?: string;
972
+ threw?: string;
973
+ }
974
+ /**
975
+ * The visible text of the page contains `text`: `innerText` is what the
976
+ * page renders, so a hidden element's words never count.
977
+ */
978
+ declare function visibleTextScript(text: string): string;
979
+ /** The longest a js value is said in a line, in characters. */
980
+ declare const JS_SAID_MAX = 120;
981
+ /** The most a js value kept on the step holds, in characters of JSON. */
982
+ declare const JS_VALUE_MAX = 2048;
983
+ /**
984
+ * The page script that evaluates a step's expression and answers what it
985
+ * found, as a string (the one evaluate shape every driver shares). The
986
+ * expression is the script author's own, run on their own page: it is
987
+ * wrapped, never parsed, and a newline closes it before the paren so a
988
+ * trailing line comment cannot swallow the wrapper.
989
+ */
990
+ declare function jsConditionScript(expr: string): string;
991
+ /** Two JSON values alike: the same keys and values whatever the key order. */
992
+ declare function sameJson(a: unknown, b: unknown): boolean;
993
+ /**
994
+ * A js value as a step keeps it (`meta.steps[].value`): the value itself
995
+ * while its JSON fits, else its JSON cut short as a string.
996
+ */
997
+ declare function keptValue(value: unknown): unknown;
998
+ /** Read the condition once. A page mid-navigation reads as "not yet". */
999
+ declare function readCondition(page: RecorderPage, c: WaitCondition): Promise<ConditionState>;
1000
+ /** What a poll found: whether the condition held, after how long, and the last read. */
1001
+ interface PollResult {
1002
+ ok: boolean;
1003
+ ms: number;
1004
+ last: ConditionState;
1005
+ }
1006
+ /**
1007
+ * Poll the condition every `everyMs` until it holds or `timeoutMs` pass.
1008
+ * `between` runs before each look but the first (an `await`'s reload).
1009
+ * With `confirm`, a hold counts only once it has held on that many reads
1010
+ * in a row, `confirm.gapMs` apart: a page that renders after network quiet
1011
+ * reads half-built for a moment, and a `gone` condition holds on a list
1012
+ * that has not been drawn yet. The clock is the wall's: a rehearsal waits
1013
+ * as long as a take would, because how long a result takes is what a
1014
+ * rehearsal is for.
1015
+ */
1016
+ declare function pollCondition(page: RecorderPage, c: WaitCondition, opts: {
1017
+ timeoutMs: number;
1018
+ everyMs: number;
1019
+ sleep: (ms: number) => Promise<void>;
1020
+ now?: () => number;
1021
+ between?: () => Promise<void>;
1022
+ confirm?: {
1023
+ reads: number;
1024
+ gapMs: number;
1025
+ };
1026
+ }): Promise<PollResult>;
1027
+ /** The DOM counts as settled after this long with no change. */
1028
+ declare const DOM_QUIET_MS = 800;
1029
+ /** The longest a settle waits on a page that never stops changing. */
1030
+ declare const DOM_SETTLE_CAP_MS = 5000;
1031
+ /**
1032
+ * The page's own count of DOM changes: an observer installed once per
1033
+ * document, read back as a number. A string, the one evaluate shape every
1034
+ * driver shares.
1035
+ */
1036
+ declare const DOM_CHANGE_PROBE = "(() => {\n if (!window.__vosDomChanges) {\n window.__vosDomChanges = { n: 0 };\n new MutationObserver((list) => { window.__vosDomChanges.n += list.length })\n .observe(document, { subtree: true, childList: true, attributes: true, characterData: true });\n }\n return window.__vosDomChanges.n;\n})()";
1037
+ /**
1038
+ * Wait until the DOM has not changed for `quietMs`, at most `capMs`: what
1039
+ * a page does after its network went quiet (a list rendered from data, a
1040
+ * hydration). The count is polled from here rather than timed in the
1041
+ * page, because a background tab throttles its own timers.
1042
+ */
1043
+ declare function domSettled(page: RecorderPage, opts: {
1044
+ sleep: (ms: number) => Promise<void>;
1045
+ now?: () => number;
1046
+ quietMs?: number;
1047
+ capMs?: number;
1048
+ tickMs?: number;
1049
+ }): Promise<{
1050
+ settled: boolean;
1051
+ ms: number;
1052
+ }>;
1053
+ /** Seconds as the recorder says them: `5 s`, `2.5 s`, `3 min 20 s`. */
1054
+ declare function sayDuration(ms: number): string;
1055
+ /** What the condition waits for, in words: `'#result' to appear`. */
1056
+ declare function sayCondition(c: WaitCondition): string;
1057
+ /** Why the condition did not hold, in words: `'Generate' stayed disabled for 5 s`. */
1058
+ declare function conditionMiss(c: WaitCondition, last: ConditionState, ms: number): string;
1059
+ /** An expression as a line names it: in backticks, cut short. */
1060
+ declare function sayJs(expr: string): string;
1061
+ /** A kept value as a line says it: its JSON, cut short. */
1062
+ declare function sayValue(value: unknown): string;
1063
+
1064
+ /**
1065
+ * `peers`: other people on the same page, off camera. A collaboration
1066
+ * product shows best with a second person on the canvas: their cursor, the
1067
+ * shape they drew, the comment they left, arriving in the filmed page the
1068
+ * way the app syncs them. A peer is a second browser context (its own
1069
+ * cookies, so its own user, from its own storage state or none) on the
1070
+ * same URL, driven by its own step list, interleaved with the take's.
1071
+ *
1072
+ * What a peer is, and is not:
1073
+ *
1074
+ * - NOT FILMED. Only the take's own page is captured. A peer's page is
1075
+ * never screencast, scanned, masked or listened to; what it does reaches
1076
+ * the footage only through the app (its sync, its presence, its remote
1077
+ * cursors), which is what a viewer would see.
1078
+ * - NOT ON THE CURSOR TRACK. A peer's pointer moves its own page; the take's
1079
+ * CursorTrack is synthesized from the take's own steps alone, so a zoom,
1080
+ * a click ring or a dwell is never planned on a peer's gesture.
1081
+ * - ORDERED BY THE TAKE'S STEPS. A peer step may name a take step by id:
1082
+ * `with` starts it as that step starts (the two run together), `after` as
1083
+ * that step ends. A step naming neither follows the peer's previous step
1084
+ * at once; a peer's first step with neither starts as the camera rolls.
1085
+ * The take never waits on a peer: it waits on what the peer's work
1086
+ * SHOWS, with an `expect` or an `await` on its own page, so the footage
1087
+ * holds exactly the moment the sync landed. When the take's steps end,
1088
+ * a peer step still waiting on a trigger never runs (said), and one
1089
+ * already running finishes, bounded, before the trailing hold.
1090
+ * - PACED, NOT INSTANT. A peer's pointer glides on the same clock as the
1091
+ * take's (an app that draws remote cursors shows it travelling) and its
1092
+ * typing is paced per key, so what it does reads as a person.
1093
+ * - BOUNDED. Every peer step runs inside its own bound, as a take step
1094
+ * does; a selector that never appears or a check that never holds is a
1095
+ * skip with its reason, listed with the take's (`--strict` fails on it).
1096
+ *
1097
+ * A peer takes the take's gestures and checks (`wait`, `move`, `hover`,
1098
+ * `click`, `type`, `press`, `scroll`, `drag` with an inline `path`, and
1099
+ * `expect`), never a `paste`, a `download`, an `await` (a peer that must
1100
+ * wait for a result is the take's `await`), a guard, a `read`, a `caption`
1101
+ * or `settle`, which all belong to the filmed page.
1102
+ */
1103
+
1104
+ /** One other person on the page: their own context, their own steps. */
1105
+ interface Peer {
1106
+ /** How the peer is named in lines and in `meta.peers`: a short word. */
1107
+ id: string;
1108
+ /** The page the peer opens; absent, the take's own `url`. */
1109
+ url?: string;
1110
+ /** The peer's viewport in CSS px; absent, the take's. */
1111
+ viewport?: {
1112
+ width: number;
1113
+ height: number;
1114
+ };
1115
+ /**
1116
+ * A Playwright storage state the peer's context is made from: the second
1117
+ * person's own sign-in. The host resolves the name (the CLI: a path from
1118
+ * the actions file's directory) and never sends the file anywhere.
1119
+ * Absent, the peer is signed out.
1120
+ */
1121
+ storageState?: string;
1122
+ steps: PeerStep[];
1123
+ }
1124
+ /** A peer's step: one of the take's gestures or checks, and when it starts. */
1125
+ type PeerStep = ActionStep & {
1126
+ /**
1127
+ * Start as the take's step with this id starts: the two run together.
1128
+ * (`with`, never `at`: a `type` step's `at` is where its caret goes.)
1129
+ */
1130
+ with?: string;
1131
+ /** Start as the take's step with this id ends. */
1132
+ after?: string;
1133
+ };
1134
+ /** The verbs a peer takes: the gestures and the on-page check. */
1135
+ declare const PEER_VERBS: readonly ["wait", "move", "hover", "click", "type", "press", "scroll", "drag", "expect"];
1136
+ /** The most peers a take may have: each is a whole browser context. */
1137
+ declare const MAX_PEERS = 4;
1138
+ /** The most steps one peer may take. */
1139
+ declare const MAX_PEER_STEPS = 200;
1140
+ /**
1141
+ * Structural validation of `peers`, given the take's own steps (a trigger
1142
+ * names one of their ids). `validate` is the take's step validator, run on
1143
+ * each peer's list so a peer step is checked in exactly the take's words.
1144
+ */
1145
+ declare function validatePeers(value: unknown, takeSteps: unknown, validate: (steps: unknown[]) => string[]): string[];
1146
+ /** What a hosted recorder says of a script with peers, or null. */
1147
+ declare function peersHostedRefusal(peers: unknown): string | null;
1148
+ /**
1149
+ * The take's step boundaries, as promises a peer step waits on. The take
1150
+ * calls `begin` as the camera rolls, `start`/`end` around each step and
1151
+ * `close` once its steps are over; a trigger still pending then resolves
1152
+ * false and its step never runs.
1153
+ */
1154
+ declare class StepSignals {
1155
+ private readonly started;
1156
+ private readonly ended;
1157
+ private readonly began;
1158
+ private closed;
1159
+ constructor(ids: Iterable<string>);
1160
+ begin(): void;
1161
+ start(id: string | undefined): void;
1162
+ end(id: string | undefined): void;
1163
+ close(): void;
1164
+ get isClosed(): boolean;
1165
+ /** When a step with this trigger may start: true, or false for never. */
1166
+ when(trigger: {
1167
+ with?: string;
1168
+ after?: string;
1169
+ }): {
1170
+ ready: Promise<boolean>;
1171
+ already: boolean;
1172
+ };
1173
+ }
1174
+
1175
+ /** The most a peer step's kept value holds, in characters of JSON (as a take step's). */
1176
+ declare const PEER_VALUE_MAX = 2048;
1177
+ /**
1178
+ * What a peer's check last answered, kept on its step the way the take's
1179
+ * own steps keep theirs (`meta.steps[].value`): the value itself while its
1180
+ * JSON fits, else that JSON cut short as a string; absent when the read
1181
+ * answered nothing JSON can hold, or no value at all (a check that only
1182
+ * holds or not).
1183
+ */
1184
+ declare function peerValue(last: ConditionState): unknown;
1185
+ /** What a peer did: its steps as they ran, and the ones that never did. */
1186
+ interface PeerRun {
1187
+ id: string;
1188
+ steps: PeerStepSpan[];
1189
+ /** Steps whose trigger never fired before the take's steps were over. */
1190
+ notRun: number[];
1191
+ }
1192
+ /**
1193
+ * Drive one peer's steps on its page, each when its trigger fires. Never
1194
+ * throws for a page's reasons: a miss is a skip on the run.
1195
+ */
1196
+ declare function runPeer(peer: Peer, rawPage: RecorderPage, signals: StepSignals, opts: {
1197
+ clock: RecorderClock;
1198
+ /** The take's footage clock, ms: what a span is placed by. */
1199
+ footageMs: () => number;
1200
+ log: (msg: string) => void;
1201
+ /** A rehearsal: no travel, every pause cut short. */
1202
+ dry?: boolean;
1203
+ }): Promise<PeerRun>;
1204
+
875
1205
  /**
876
1206
  * The action script — the declarative recipe an agent (or human) writes to
877
1207
  * drive a take. Small on purpose: selectors + a handful of verbs. The recorder
@@ -903,6 +1233,15 @@ interface ActionsFile {
903
1233
  * or stored.
904
1234
  */
905
1235
  setup?: SetupStep[];
1236
+ /**
1237
+ * Run AFTER the take, off camera, with the same verbs as `setup`: what
1238
+ * the take created in the product (an API key, a project, an invite)
1239
+ * removed again. They run once the screencast has stopped, on the take's
1240
+ * own page, after a rehearsal too, and when the take stops early or
1241
+ * throws after its first step. A failing teardown never fails the take;
1242
+ * it stops at the step that failed and is reported.
1243
+ */
1244
+ teardown?: SetupStep[];
906
1245
  /**
907
1246
  * When the first page counts as ready for step 1: `dom` (default),
908
1247
  * once its DOM has made no change for a beat after `load`, at most 8 s;
@@ -917,6 +1256,15 @@ interface ActionsFile {
917
1256
  */
918
1257
  settle?: boolean;
919
1258
  steps: ActionStep[];
1259
+ /**
1260
+ * Other people on the page, OFF CAMERA: each a browser context of its
1261
+ * own (its own storage state, so its own user) on the same `url`, driven
1262
+ * by its own steps, each started `with` a take step or `after` one (by
1263
+ * id). Only the take's page is filmed, and only its own steps make the
1264
+ * cursor track; a peer's work reaches the footage through the app's own
1265
+ * sync. A hosted take refuses peers.
1266
+ */
1267
+ peers?: Peer[];
920
1268
  }
921
1269
  type ActionStep = ({
922
1270
  do: 'wait';
@@ -1037,9 +1385,12 @@ type ActionStep = ({
1037
1385
  /**
1038
1386
  * Check that the page is as the flow expects, with no cursor move: an
1039
1387
  * element visible (`selector`; with `enabled`, enabled or disabled), some
1040
- * visible text containing `text`, or `gone` no longer visible. Exactly
1041
- * one of the three. Waits up to `timeout` seconds (default 5); a
1042
- * condition that never holds is a skip with its reason.
1388
+ * visible text containing `text`, `gone` no longer visible, or `js`, an
1389
+ * expression evaluated in the page that holds when its value is truthy
1390
+ * (with `equals`, when its value equals that one): the state a canvas
1391
+ * app keeps in script, never in the DOM. Exactly one of the four. Waits
1392
+ * up to `timeout` seconds (default 5); a condition that never holds is a
1393
+ * skip with its reason, which names the value a `js` last answered.
1043
1394
  */
1044
1395
  | {
1045
1396
  do: 'expect';
@@ -1047,6 +1398,8 @@ type ActionStep = ({
1047
1398
  text?: string;
1048
1399
  gone?: string;
1049
1400
  enabled?: boolean;
1401
+ js?: string;
1402
+ equals?: unknown;
1050
1403
  timeout?: number;
1051
1404
  }
1052
1405
  /**
@@ -1099,6 +1452,15 @@ type ActionStep = ({
1099
1452
  * `vos actions script` leads the beat with it.
1100
1453
  */
1101
1454
  caption?: string;
1455
+ /**
1456
+ * The cut's camera on this step: `true` marks the step as its beat's
1457
+ * payoff, the moment worth the zoom (`vos plan --zooms per-beat` keeps
1458
+ * the proposal on it, and only it); `false` means never zoom here (the
1459
+ * planner's proposal on it is rejected). The planner still decides the
1460
+ * level and the focus; a mark never invents a zoom. On a gesture only
1461
+ * (ZOOM_MARK_VERBS).
1462
+ */
1463
+ zoom?: boolean;
1102
1464
  /**
1103
1465
  * A selector whose words the recorder keeps once the step has settled
1104
1466
  * (`meta.steps[].text`: trimmed, whitespace collapsed, at most 2 KB), so
@@ -1116,15 +1478,19 @@ type ActionStep = ({
1116
1478
  */
1117
1479
  settle?: boolean;
1118
1480
  };
1119
- /** What an `await` waits for: exactly one of the three. */
1481
+ /** What an `await` waits for: exactly one of the four (`equals` rides with `js`). */
1120
1482
  interface AwaitUntil {
1121
1483
  selector?: string;
1122
1484
  text?: string;
1123
1485
  gone?: string;
1486
+ js?: string;
1487
+ equals?: unknown;
1124
1488
  }
1125
1489
  /** The guards a step may carry: one today, a step that spends. */
1126
1490
  declare const STEP_GUARDS: readonly ["spend"];
1127
1491
  type StepGuard = (typeof STEP_GUARDS)[number];
1492
+ /** The verbs a `zoom` mark may sit on: the gestures a camera can be about. */
1493
+ declare const ZOOM_MARK_VERBS: readonly string[];
1128
1494
  /** How long an `expect` waits by default, in seconds. */
1129
1495
  declare const EXPECT_TIMEOUT_S = 5;
1130
1496
  /** An `await`'s defaults, in seconds. */
@@ -1168,10 +1534,11 @@ declare function guardVerdict(actions: Pick<ActionsFile, 'steps'>, confirm: read
1168
1534
  };
1169
1535
  /**
1170
1536
  * What a hosted recorder cannot do with a script, in words, or []: a
1171
- * guarded step has nobody to confirm it on a fleet, and a download has no
1172
- * take directory to land in there.
1537
+ * guarded step has nobody to confirm it on a fleet, a download has no
1538
+ * take directory to land in there, and a `js` check is code a stranger's
1539
+ * script would run in the fleet's browser.
1173
1540
  */
1174
- declare function hostedRefusals(actions: Pick<ActionsFile, 'steps'>): string[];
1541
+ declare function hostedRefusals(actions: Pick<ActionsFile, 'steps' | 'peers'>): string[];
1175
1542
  /**
1176
1543
  * The files a script names beside itself, in order: a drag's path file
1177
1544
  * and a paste's file. A host reads them before anything is captured.
@@ -1293,6 +1660,8 @@ interface SkippedStep {
1293
1660
  selector: string;
1294
1661
  /** why, when it is not a selector that never appeared: an expect that never held, a download that never came */
1295
1662
  reason?: string;
1663
+ /** A PEER's step (`peers[].id`): `step` is then an index into that peer's steps. */
1664
+ peer?: string;
1296
1665
  }
1297
1666
  /** A click whose target was disabled when it was pressed: the press happened, and likely did nothing. */
1298
1667
  interface DisabledClick {
@@ -1378,6 +1747,13 @@ interface RecordResult {
1378
1747
  overruns: StepOverrun[];
1379
1748
  /** The actions as recorded, `url` resolved: what a take directory writes back. */
1380
1749
  actions: ActionsFile;
1750
+ /** What each peer did, off camera (also `meta.peers`); [] with none. */
1751
+ peers: PeerRun[];
1752
+ /**
1753
+ * What the script's `teardown` did after the take, off camera; null when
1754
+ * it has none. A failure here is reported and never fails the take.
1755
+ */
1756
+ teardown: TeardownReport | null;
1381
1757
  }
1382
1758
  interface RecordOpts {
1383
1759
  /** Stop the capture at this many seconds (the hosted cap). */
@@ -1416,9 +1792,10 @@ interface RecordOpts {
1416
1792
  */
1417
1793
  context?: RecorderContext;
1418
1794
  /**
1419
- * The environment a setup's `{ env }` texts resolve from: the shell's
1420
- * for the CLI, the job's own map on the fleet. Absent means no env at
1421
- * all, so a setup that reads one fails in words.
1795
+ * The environment a setup's and a teardown's `{ env }` texts resolve
1796
+ * from: the shell's for the CLI, the job's own map on the fleet. Absent
1797
+ * means no env at all, so a setup that reads one fails in words, and a
1798
+ * teardown that reads one refuses the take before it begins.
1422
1799
  */
1423
1800
  env?: Record<string, string | undefined>;
1424
1801
  /** The platform the take is recorded on, for `meta.platform`. */
@@ -1462,6 +1839,14 @@ interface RecordOpts {
1462
1839
  stopOnHang?: boolean;
1463
1840
  /** How often a long `await` reports it is still waiting (default 30 s). */
1464
1841
  awaitHeartbeatMs?: number;
1842
+ /**
1843
+ * Where a peer's `storageState` is read from: the CLI resolves the name
1844
+ * from the actions file's directory to a path the browser opens, and
1845
+ * throws in words when there is none. A host that hands in none cannot
1846
+ * sign a peer in, and such a script is refused before anything is
1847
+ * captured.
1848
+ */
1849
+ peerStorageState?: (name: string) => Promise<string> | string;
1465
1850
  }
1466
1851
  /**
1467
1852
  * The expression a scroll tick evaluates: move the first scrollable
@@ -1567,97 +1952,6 @@ declare function splitSegmentsAtSkips(segments: ProjectDoc['segments'], skips: r
1567
1952
  at: number;
1568
1953
  }[] | undefined): ProjectDoc['segments'];
1569
1954
 
1570
- /**
1571
- * What an `expect` and an `await` wait for: a condition on the page, read
1572
- * without touching it (no cursor, no input), polled until it holds or the
1573
- * time runs out. `expect` polls on camera for a few seconds; `await` polls
1574
- * off camera for as long as a slow result takes. One reader for both, so
1575
- * "appeared" means the same thing in either.
1576
- */
1577
-
1578
- interface WaitCondition {
1579
- /** an element matching this selector is visible */
1580
- selector?: string;
1581
- /** some visible text on the page contains this */
1582
- text?: string;
1583
- /** no element matching this selector is visible */
1584
- gone?: string;
1585
- /** with `selector`: the element is enabled (true) or disabled (false) */
1586
- enabled?: boolean;
1587
- }
1588
- /** What the condition found the last time it looked: what a miss is said from. */
1589
- interface ConditionState {
1590
- holds: boolean;
1591
- /** with `selector`: whether a match was visible */
1592
- visible?: boolean;
1593
- }
1594
- /**
1595
- * The visible text of the page contains `text`: `innerText` is what the
1596
- * page renders, so a hidden element's words never count.
1597
- */
1598
- declare function visibleTextScript(text: string): string;
1599
- /** Read the condition once. A page mid-navigation reads as "not yet". */
1600
- declare function readCondition(page: RecorderPage, c: WaitCondition): Promise<ConditionState>;
1601
- /** What a poll found: whether the condition held, after how long, and the last read. */
1602
- interface PollResult {
1603
- ok: boolean;
1604
- ms: number;
1605
- last: ConditionState;
1606
- }
1607
- /**
1608
- * Poll the condition every `everyMs` until it holds or `timeoutMs` pass.
1609
- * `between` runs before each look but the first (an `await`'s reload).
1610
- * With `confirm`, a hold counts only once it has held on that many reads
1611
- * in a row, `confirm.gapMs` apart: a page that renders after network quiet
1612
- * reads half-built for a moment, and a `gone` condition holds on a list
1613
- * that has not been drawn yet. The clock is the wall's: a rehearsal waits
1614
- * as long as a take would, because how long a result takes is what a
1615
- * rehearsal is for.
1616
- */
1617
- declare function pollCondition(page: RecorderPage, c: WaitCondition, opts: {
1618
- timeoutMs: number;
1619
- everyMs: number;
1620
- sleep: (ms: number) => Promise<void>;
1621
- now?: () => number;
1622
- between?: () => Promise<void>;
1623
- confirm?: {
1624
- reads: number;
1625
- gapMs: number;
1626
- };
1627
- }): Promise<PollResult>;
1628
- /** The DOM counts as settled after this long with no change. */
1629
- declare const DOM_QUIET_MS = 800;
1630
- /** The longest a settle waits on a page that never stops changing. */
1631
- declare const DOM_SETTLE_CAP_MS = 5000;
1632
- /**
1633
- * The page's own count of DOM changes: an observer installed once per
1634
- * document, read back as a number. A string, the one evaluate shape every
1635
- * driver shares.
1636
- */
1637
- declare const DOM_CHANGE_PROBE = "(() => {\n if (!window.__vosDomChanges) {\n window.__vosDomChanges = { n: 0 };\n new MutationObserver((list) => { window.__vosDomChanges.n += list.length })\n .observe(document, { subtree: true, childList: true, attributes: true, characterData: true });\n }\n return window.__vosDomChanges.n;\n})()";
1638
- /**
1639
- * Wait until the DOM has not changed for `quietMs`, at most `capMs`: what
1640
- * a page does after its network went quiet (a list rendered from data, a
1641
- * hydration). The count is polled from here rather than timed in the
1642
- * page, because a background tab throttles its own timers.
1643
- */
1644
- declare function domSettled(page: RecorderPage, opts: {
1645
- sleep: (ms: number) => Promise<void>;
1646
- now?: () => number;
1647
- quietMs?: number;
1648
- capMs?: number;
1649
- tickMs?: number;
1650
- }): Promise<{
1651
- settled: boolean;
1652
- ms: number;
1653
- }>;
1654
- /** Seconds as the recorder says them: `5 s`, `2.5 s`, `3 min 20 s`. */
1655
- declare function sayDuration(ms: number): string;
1656
- /** What the condition waits for, in words: `'#result' to appear`. */
1657
- declare function sayCondition(c: WaitCondition): string;
1658
- /** Why the condition did not hold, in words: `'Generate' stayed disabled for 5 s`. */
1659
- declare function conditionMiss(c: WaitCondition, last: ConditionState, ms: number): string;
1660
-
1661
1955
  /** The most a download keeps: a file the page made, never a disk's worth. */
1662
1956
  declare const OUTPUT_MAX_BYTES: number;
1663
1957
  /**
@@ -2045,4 +2339,4 @@ declare function inlinePoints(path: {
2045
2339
  */
2046
2340
  declare function inlineScript<T extends Pick<ActionsFile, 'steps'>>(actions: T, files: LoadedFiles): T;
2047
2341
 
2048
- export { APP_QUIET_MS, APP_SETTLE_CAP_MS, AWAIT_HEARTBEAT_MS, AWAIT_POLL_S, AWAIT_TIMEOUT_S, type ActionStep, type ActionsFile, type Arrival, type AwaitUntil, CHANGE_AGE_PROBE, CLICK_BUTTONS, type ClickButton, type ConditionState, DEAD_SHARE_WARN_PCT, DEAD_STRETCH_WARN_MS, DEFAULT_READY, DOM_CHANGE_PROBE, DOM_QUIET_MS, DOM_SETTLE_CAP_MS, DOWNLOAD_TIMEOUT_S, DRAG_HOLD_MS, DRAG_MODIFIERS, type DeadReport, type DeadStep, type DisabledClick, type DragModifier, EXPECT_TIMEOUT_S, EXPOSURE_ADVICE, EXPOSURE_MATCHERS_SRC, EXPOSURE_PROBE, type EncodePageOptions, type Exposure, type ExposureKind, ExposureLog, type FrameRec, type FrameSink, type FreezeSpan, type FreshPlanOptions, type GuardedStep, type HeardSound, IDLE_CALL_MS, KEY_ROUNDTRIP_MS, KEY_SEQUENCE_GAP_MS, type LoadedFiles, MAX_KEYS, MAX_PATH_POINTS, MEDIA_DRAIN_PROBE, MEDIA_WATCH_SCRIPT, MIN_SKIP_MS, MODIFIERS, MOTION_TICK_MS, MULTI_CLICK_GAP_MS, type MaskReport, type MaskRule, type MediaDrain, type MediaNote, type Modifier, NAV_TIMEOUT_MS, NETWORKIDLE_HYDRATION_MS, NOTICE_SRC, type Notice, NoticeLog, OUTPUT_MAX_BYTES, OVERRUN_MIN_MS, OVERRUN_MIN_PLANNED_MS, OVERRUN_SHARE, type OutputSink, PAGE_ERROR_LINE_CHARS, PASTE_MAX_BYTES, PASTE_READ_WINDOW_MS, PASTE_TYPES, PASTE_UNREAD_MS, PATH_DEFAULT_MS, POINTER_MAX_MS, POINTER_MIN_MS, POINTER_MS_PER_PX, PRESS_HOLD_MS, PRESS_KEYS, PRESS_LEAD_MS, type PaceReport, type PageError, PageErrorLog, PageSoundLog, type PasteItem, type PathPoint, type PathSample, type PollResult, type PressKey, QUIET_MS, READY_MODES, READY_SETTLE_CAP_MS, READ_BEAT_MS, RESPONSE_MS, type ReadyMode, type ReadyOpts, type ReadyReport, type RecordOpts, RecordRefusedError, type RecordResult, type RecorderApiResponse, type RecorderBrowser, type RecorderButtonOpts, type RecorderCdp, type RecorderClock, type RecorderConsoleMessage, type RecorderContext, type RecorderDownload, type RecorderLocator, type RecorderLocatorRoot, type RecorderMediaElement, type RecorderPage, type RecorderRect, type RecorderResponse, type RecorderRoute, SCROLL_MAX_MS, SCROLL_MIN_MS, SCROLL_MS_PER_PX, SCROLL_SETTLE_MS, SETTLE_CAP_MS, SETTLE_MS, SETTLE_VERBS, STEP_GUARDS, STEP_MARGIN_MS, type ScannedNotice, type ScriptFiles, SetupEnvError, SetupError, type SetupResult, type SetupStep, type SetupText, type SkippedStep, type SoundSink, StepBound, type StepGuard, type StepOverrun, type StepPace, type StoppedTake, type SurfaceFit, type SurfaceSize, TRAILING_HOLD_MS, TakeClock, WAIT_MARGIN_MS, WALL_PROBE, type WaitCondition, WallError, type WallKind, type WallVerdict, appSettled, askedMs, base64Bytes, bounded, buildEncodePage, buttonNumber, capReached, cappedLine, chordProblem, clampWait, clockMotion, clockTyping, conditionMiss, deadLine, deadTime, deadWarns, domSettled, easeInOutCubic, exposureLine, extForType, fetchInPageScript, fileNameProblem, fitSurfaceToViewport, formatDurationCap, guardVerdict, guardedSteps, hangReason, headersFor, holdLeftMs, hostedRefusals, inlinePoints, inlineScript, isIdpHost, isKeyName, isSignInPath, jpegDims, keySequencePlanMs, loadScriptFiles, maskInitScript, modifierBits, nameFromUrl, noticeAdvice, noticeLine, outputName, overrunLine, overrunOf, paceLine, paceReport, pageErrorLine, parseHeaders, pasteTypeOf, pathDurationMs, plainName, planFreshTake, pointerTravelMs, pollCondition, pressSequence, publicUrl, readAllBytes, readCondition, readMediaSource, readPath, readyLine, readyProblem, realSleep, recordTake, redirectedAway, reloadUntilReady, resolveChord, resolveModifier, resolveSetupText, runSetup, sayCondition, sayDuration, schedulePath, scriptFiles, scrollByScript, scrollTravelMs, settleMs, settleOn, settleVerdict, setupEnvNames, soundSrcForMeta, splitChord, splitSegmentsAtSkips, stageClipboardScript, stepBoundMs, syntheticPasteScript, typeOfName, untilReady, urlSchemeProblem, validateActions, validateSetup, visibleTextScript, wallVerdict, withFittingExport, withPageSound };
2342
+ export { APP_QUIET_MS, APP_SETTLE_CAP_MS, AWAIT_HEARTBEAT_MS, AWAIT_POLL_S, AWAIT_TIMEOUT_S, type ActionStep, type ActionsFile, type Arrival, type AwaitUntil, CHANGE_AGE_PROBE, CLICK_BUTTONS, type ClickButton, type ConditionState, DEAD_SHARE_WARN_PCT, DEAD_STRETCH_WARN_MS, DEFAULT_READY, DOM_CHANGE_PROBE, DOM_QUIET_MS, DOM_SETTLE_CAP_MS, DOWNLOAD_TIMEOUT_S, DRAG_HOLD_MS, DRAG_MODIFIERS, type DeadReport, type DeadStep, type DisabledClick, type DragModifier, EXPECT_TIMEOUT_S, EXPOSURE_ADVICE, EXPOSURE_MATCHERS_SRC, EXPOSURE_PROBE, type EncodePageOptions, type Exposure, type ExposureKind, ExposureLog, type FrameRec, type FrameSink, type FreezeSpan, type FreshPlanOptions, type GuardedStep, type HeardSound, IDLE_CALL_MS, JS_SAID_MAX, JS_VALUE_MAX, KEY_ROUNDTRIP_MS, KEY_SEQUENCE_GAP_MS, type LoadedFiles, MAX_KEYS, MAX_PATH_POINTS, MAX_PEERS, MAX_PEER_STEPS, MEDIA_DRAIN_PROBE, MEDIA_WATCH_SCRIPT, MIN_SKIP_MS, MODIFIERS, MOTION_TICK_MS, MULTI_CLICK_GAP_MS, type MaskReport, type MaskRule, type MediaDrain, type MediaNote, type Modifier, NAV_TIMEOUT_MS, NETWORKIDLE_HYDRATION_MS, NOTICE_SRC, type Notice, NoticeLog, OUTPUT_MAX_BYTES, OVERRUN_MIN_MS, OVERRUN_MIN_PLANNED_MS, OVERRUN_SHARE, type OutputSink, PAGE_ERROR_LINE_CHARS, PASTE_MAX_BYTES, PASTE_READ_WINDOW_MS, PASTE_TYPES, PASTE_UNREAD_MS, PATH_DEFAULT_MS, PEER_VALUE_MAX, PEER_VERBS, POINTER_MAX_MS, POINTER_MIN_MS, POINTER_MS_PER_PX, PRESS_HOLD_MS, PRESS_KEYS, PRESS_LEAD_MS, type PaceReport, type PageError, PageErrorLog, PageSoundLog, type PasteItem, type PathPoint, type PathSample, type Peer, type PeerRun, type PeerStep, type PollResult, type PressKey, QUIET_MS, READY_MODES, READY_SETTLE_CAP_MS, READ_BEAT_MS, RESPONSE_MS, type ReadyMode, type ReadyOpts, type ReadyReport, type RecordOpts, RecordRefusedError, type RecordResult, type RecorderApiResponse, type RecorderBrowser, type RecorderButtonOpts, type RecorderCdp, type RecorderClock, type RecorderConsoleMessage, type RecorderContext, type RecorderDownload, type RecorderLocator, type RecorderLocatorRoot, type RecorderMediaElement, type RecorderPage, type RecorderRect, type RecorderResponse, type RecorderRoute, SCROLL_MAX_MS, SCROLL_MIN_MS, SCROLL_MS_PER_PX, SCROLL_SETTLE_MS, SETTLE_CAP_MS, SETTLE_MS, SETTLE_VERBS, STEP_GUARDS, STEP_MARGIN_MS, type ScannedNotice, type ScriptFiles, SetupEnvError, SetupError, type SetupResult, type SetupStep, type SetupText, type SkippedStep, type SoundSink, StepBound, type StepGuard, type StepOverrun, type StepPace, type StepPhase, StepSignals, type StoppedTake, type SurfaceFit, type SurfaceSize, TEARDOWN_BOUND_MS, TRAILING_HOLD_MS, TakeClock, type TeardownReport, WAIT_MARGIN_MS, WALL_PROBE, type WaitCondition, WallError, type WallKind, type WallVerdict, ZOOM_MARK_VERBS, appSettled, askedMs, base64Bytes, bounded, buildEncodePage, buttonNumber, capReached, cappedLine, chordProblem, clampWait, clockMotion, clockTyping, conditionMiss, deadLine, deadTime, deadWarns, domSettled, easeInOutCubic, exposureLine, extForType, fetchInPageScript, fileNameProblem, fitSurfaceToViewport, formatDurationCap, guardVerdict, guardedSteps, hangReason, headersFor, holdLeftMs, hostedRefusals, inlinePoints, inlineScript, isIdpHost, isKeyName, isSignInPath, jpegDims, jsConditionScript, keptValue, keySequencePlanMs, loadScriptFiles, maskInitScript, modifierBits, nameFromUrl, noticeAdvice, noticeLine, outputName, overrunLine, overrunOf, paceLine, paceReport, pageErrorLine, parseHeaders, pasteTypeOf, pathDurationMs, peerValue, peersHostedRefusal, plainName, planFreshTake, pointerTravelMs, pollCondition, pressSequence, publicUrl, readAllBytes, readCondition, readMediaSource, readPath, readyLine, readyProblem, realSleep, recordTake, redirectedAway, reloadUntilReady, resolveChord, resolveModifier, resolveSetupText, runPeer, runSetup, sameJson, sayCondition, sayDuration, sayJs, sayValue, schedulePath, scriptEnvNames, scriptFiles, scrollByScript, scrollTravelMs, settleMs, settleOn, settleVerdict, setupEnvNames, soundSrcForMeta, splitChord, splitSegmentsAtSkips, stageClipboardScript, stepBoundMs, syntheticPasteScript, teardownEnvProblem, teardownLine, typeOfName, untilReady, urlSchemeProblem, validateActions, validatePeers, validateSetup, visibleTextScript, wallVerdict, withFittingExport, withPageSound };