deio-scroll 1.0.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.
Files changed (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/dist/api/server.d.ts +3 -0
  4. package/dist/api/server.d.ts.map +1 -0
  5. package/dist/api/server.js +393 -0
  6. package/dist/api/server.js.map +1 -0
  7. package/dist/artifacts/store.d.ts +24 -0
  8. package/dist/artifacts/store.d.ts.map +1 -0
  9. package/dist/artifacts/store.js +43 -0
  10. package/dist/artifacts/store.js.map +1 -0
  11. package/dist/browser/componentInteraction.d.ts +24 -0
  12. package/dist/browser/componentInteraction.d.ts.map +1 -0
  13. package/dist/browser/componentInteraction.js +328 -0
  14. package/dist/browser/componentInteraction.js.map +1 -0
  15. package/dist/browser/composition.d.ts +42 -0
  16. package/dist/browser/composition.d.ts.map +1 -0
  17. package/dist/browser/composition.js +132 -0
  18. package/dist/browser/composition.js.map +1 -0
  19. package/dist/browser/cookies.d.ts +3 -0
  20. package/dist/browser/cookies.d.ts.map +1 -0
  21. package/dist/browser/cookies.js +20 -0
  22. package/dist/browser/cookies.js.map +1 -0
  23. package/dist/browser/curves.d.ts +4 -0
  24. package/dist/browser/curves.d.ts.map +1 -0
  25. package/dist/browser/curves.js +35 -0
  26. package/dist/browser/curves.js.map +1 -0
  27. package/dist/browser/detectScrollMode.d.ts +5 -0
  28. package/dist/browser/detectScrollMode.d.ts.map +1 -0
  29. package/dist/browser/detectScrollMode.js +61 -0
  30. package/dist/browser/detectScrollMode.js.map +1 -0
  31. package/dist/browser/directionGuardrails.d.ts +22 -0
  32. package/dist/browser/directionGuardrails.d.ts.map +1 -0
  33. package/dist/browser/directionGuardrails.js +99 -0
  34. package/dist/browser/directionGuardrails.js.map +1 -0
  35. package/dist/browser/goto.d.ts +9 -0
  36. package/dist/browser/goto.d.ts.map +1 -0
  37. package/dist/browser/goto.js +62 -0
  38. package/dist/browser/goto.js.map +1 -0
  39. package/dist/browser/hydrate.d.ts +8 -0
  40. package/dist/browser/hydrate.d.ts.map +1 -0
  41. package/dist/browser/hydrate.js +73 -0
  42. package/dist/browser/hydrate.js.map +1 -0
  43. package/dist/browser/mediaClock.d.ts +9 -0
  44. package/dist/browser/mediaClock.d.ts.map +1 -0
  45. package/dist/browser/mediaClock.js +86 -0
  46. package/dist/browser/mediaClock.js.map +1 -0
  47. package/dist/browser/motion.d.ts +21 -0
  48. package/dist/browser/motion.d.ts.map +1 -0
  49. package/dist/browser/motion.js +42 -0
  50. package/dist/browser/motion.js.map +1 -0
  51. package/dist/browser/networkPolicy.d.ts +11 -0
  52. package/dist/browser/networkPolicy.d.ts.map +1 -0
  53. package/dist/browser/networkPolicy.js +119 -0
  54. package/dist/browser/networkPolicy.js.map +1 -0
  55. package/dist/browser/prime.d.ts +3 -0
  56. package/dist/browser/prime.d.ts.map +1 -0
  57. package/dist/browser/prime.js +13 -0
  58. package/dist/browser/prime.js.map +1 -0
  59. package/dist/browser/sanitize.d.ts +3 -0
  60. package/dist/browser/sanitize.d.ts.map +1 -0
  61. package/dist/browser/sanitize.js +37 -0
  62. package/dist/browser/sanitize.js.map +1 -0
  63. package/dist/browser/scroll.d.ts +29 -0
  64. package/dist/browser/scroll.d.ts.map +1 -0
  65. package/dist/browser/scroll.js +420 -0
  66. package/dist/browser/scroll.js.map +1 -0
  67. package/dist/browser/scrollEasing.d.ts +5 -0
  68. package/dist/browser/scrollEasing.d.ts.map +1 -0
  69. package/dist/browser/scrollEasing.js +40 -0
  70. package/dist/browser/scrollEasing.js.map +1 -0
  71. package/dist/browser/scrollReadiness.d.ts +25 -0
  72. package/dist/browser/scrollReadiness.d.ts.map +1 -0
  73. package/dist/browser/scrollReadiness.js +105 -0
  74. package/dist/browser/scrollReadiness.js.map +1 -0
  75. package/dist/browser/urlGuard.d.ts +4 -0
  76. package/dist/browser/urlGuard.d.ts.map +1 -0
  77. package/dist/browser/urlGuard.js +22 -0
  78. package/dist/browser/urlGuard.js.map +1 -0
  79. package/dist/browser/virtualScroll.d.ts +19 -0
  80. package/dist/browser/virtualScroll.d.ts.map +1 -0
  81. package/dist/browser/virtualScroll.js +50 -0
  82. package/dist/browser/virtualScroll.js.map +1 -0
  83. package/dist/capture/detectMargins.d.ts +6 -0
  84. package/dist/capture/detectMargins.d.ts.map +1 -0
  85. package/dist/capture/detectMargins.js +145 -0
  86. package/dist/capture/detectMargins.js.map +1 -0
  87. package/dist/capture/frameRecorder.d.ts +29 -0
  88. package/dist/capture/frameRecorder.d.ts.map +1 -0
  89. package/dist/capture/frameRecorder.js +74 -0
  90. package/dist/capture/frameRecorder.js.map +1 -0
  91. package/dist/capture/stitchFrames.d.ts +9 -0
  92. package/dist/capture/stitchFrames.d.ts.map +1 -0
  93. package/dist/capture/stitchFrames.js +62 -0
  94. package/dist/capture/stitchFrames.js.map +1 -0
  95. package/dist/cli.d.ts +3 -0
  96. package/dist/cli.d.ts.map +1 -0
  97. package/dist/cli.js +329 -0
  98. package/dist/cli.js.map +1 -0
  99. package/dist/config/browserLaunch.d.ts +13 -0
  100. package/dist/config/browserLaunch.d.ts.map +1 -0
  101. package/dist/config/browserLaunch.js +63 -0
  102. package/dist/config/browserLaunch.js.map +1 -0
  103. package/dist/config/recordingProfile.d.ts +10 -0
  104. package/dist/config/recordingProfile.d.ts.map +1 -0
  105. package/dist/config/recordingProfile.js +25 -0
  106. package/dist/config/recordingProfile.js.map +1 -0
  107. package/dist/config/runtimeMode.d.ts +2 -0
  108. package/dist/config/runtimeMode.d.ts.map +1 -0
  109. package/dist/config/runtimeMode.js +4 -0
  110. package/dist/config/runtimeMode.js.map +1 -0
  111. package/dist/config/virtualScroll.d.ts +8 -0
  112. package/dist/config/virtualScroll.d.ts.map +1 -0
  113. package/dist/config/virtualScroll.js +19 -0
  114. package/dist/config/virtualScroll.js.map +1 -0
  115. package/dist/contracts.d.ts +157 -0
  116. package/dist/contracts.d.ts.map +1 -0
  117. package/dist/contracts.js +136 -0
  118. package/dist/contracts.js.map +1 -0
  119. package/dist/editor/compileVideo.d.ts +21 -0
  120. package/dist/editor/compileVideo.d.ts.map +1 -0
  121. package/dist/editor/compileVideo.js +104 -0
  122. package/dist/editor/compileVideo.js.map +1 -0
  123. package/dist/editor/composeComparison.d.ts +30 -0
  124. package/dist/editor/composeComparison.d.ts.map +1 -0
  125. package/dist/editor/composeComparison.js +315 -0
  126. package/dist/editor/composeComparison.js.map +1 -0
  127. package/dist/editor/composeResponsiveness.d.ts +19 -0
  128. package/dist/editor/composeResponsiveness.d.ts.map +1 -0
  129. package/dist/editor/composeResponsiveness.js +198 -0
  130. package/dist/editor/composeResponsiveness.js.map +1 -0
  131. package/dist/editor/frameVideo.d.ts +11 -0
  132. package/dist/editor/frameVideo.d.ts.map +1 -0
  133. package/dist/editor/frameVideo.js +181 -0
  134. package/dist/editor/frameVideo.js.map +1 -0
  135. package/dist/index.d.ts +3 -0
  136. package/dist/index.d.ts.map +1 -0
  137. package/dist/index.js +2 -0
  138. package/dist/index.js.map +1 -0
  139. package/dist/inspection/inspectWebsite.d.ts +21 -0
  140. package/dist/inspection/inspectWebsite.d.ts.map +1 -0
  141. package/dist/inspection/inspectWebsite.js +412 -0
  142. package/dist/inspection/inspectWebsite.js.map +1 -0
  143. package/dist/jobs/manager.d.ts +123 -0
  144. package/dist/jobs/manager.d.ts.map +1 -0
  145. package/dist/jobs/manager.js +378 -0
  146. package/dist/jobs/manager.js.map +1 -0
  147. package/dist/jobs/store.d.ts +150 -0
  148. package/dist/jobs/store.d.ts.map +1 -0
  149. package/dist/jobs/store.js +446 -0
  150. package/dist/jobs/store.js.map +1 -0
  151. package/dist/jobs/thumbnail.d.ts +2 -0
  152. package/dist/jobs/thumbnail.d.ts.map +1 -0
  153. package/dist/jobs/thumbnail.js +36 -0
  154. package/dist/jobs/thumbnail.js.map +1 -0
  155. package/dist/pipeline/processRecordingRequest.d.ts +4 -0
  156. package/dist/pipeline/processRecordingRequest.d.ts.map +1 -0
  157. package/dist/pipeline/processRecordingRequest.js +17 -0
  158. package/dist/pipeline/processRecordingRequest.js.map +1 -0
  159. package/dist/pipeline/recordComparison.d.ts +4 -0
  160. package/dist/pipeline/recordComparison.d.ts.map +1 -0
  161. package/dist/pipeline/recordComparison.js +99 -0
  162. package/dist/pipeline/recordComparison.js.map +1 -0
  163. package/dist/pipeline/recordResponsiveness.d.ts +4 -0
  164. package/dist/pipeline/recordResponsiveness.d.ts.map +1 -0
  165. package/dist/pipeline/recordResponsiveness.js +122 -0
  166. package/dist/pipeline/recordResponsiveness.js.map +1 -0
  167. package/dist/pipeline/recordWebsite.d.ts +11 -0
  168. package/dist/pipeline/recordWebsite.d.ts.map +1 -0
  169. package/dist/pipeline/recordWebsite.js +446 -0
  170. package/dist/pipeline/recordWebsite.js.map +1 -0
  171. package/dist/pipeline/styleRecording.d.ts +12 -0
  172. package/dist/pipeline/styleRecording.d.ts.map +1 -0
  173. package/dist/pipeline/styleRecording.js +59 -0
  174. package/dist/pipeline/styleRecording.js.map +1 -0
  175. package/dist/transcode/ffmpeg.d.ts +4 -0
  176. package/dist/transcode/ffmpeg.d.ts.map +1 -0
  177. package/dist/transcode/ffmpeg.js +62 -0
  178. package/dist/transcode/ffmpeg.js.map +1 -0
  179. package/dist/transcode/probe.d.ts +7 -0
  180. package/dist/transcode/probe.d.ts.map +1 -0
  181. package/dist/transcode/probe.js +91 -0
  182. package/dist/transcode/probe.js.map +1 -0
  183. package/dist/transcode/quality.d.ts +8 -0
  184. package/dist/transcode/quality.d.ts.map +1 -0
  185. package/dist/transcode/quality.js +13 -0
  186. package/dist/transcode/quality.js.map +1 -0
  187. package/dist/types.d.ts +302 -0
  188. package/dist/types.d.ts.map +1 -0
  189. package/dist/types.js +2 -0
  190. package/dist/types.js.map +1 -0
  191. package/dist/worker.d.ts +3 -0
  192. package/dist/worker.d.ts.map +1 -0
  193. package/dist/worker.js +22 -0
  194. package/dist/worker.js.map +1 -0
  195. package/package.json +63 -0
  196. package/public/assets/index-C63t4P1L.css +1 -0
  197. package/public/assets/index-Sfgf7dSH.js +9 -0
  198. package/public/background_presets/gray_noise_gradient.png +0 -0
  199. package/public/background_presets/paper_blue.png +0 -0
  200. package/public/background_presets/red_blocks_gradient.png +0 -0
  201. package/public/deio-scroll-mark.svg +12 -0
  202. package/public/favicon.svg +1 -0
  203. package/public/icons.svg +24 -0
  204. package/public/index.html +16 -0
  205. package/public/scrollizard-mark.png +0 -0
@@ -0,0 +1,61 @@
1
+ const DOCUMENT_SCROLL_THRESHOLD_PX = 48;
2
+ export async function detectScrollMode(page, requestedMode = "auto") {
3
+ if (requestedMode === "document" || requestedMode === "virtual") {
4
+ return requestedMode;
5
+ }
6
+ const signals = await page.evaluate((threshold) => {
7
+ const docMaxScroll = Math.max(0, document.documentElement.scrollHeight - window.innerHeight);
8
+ const bodyStyle = getComputedStyle(document.body);
9
+ const htmlStyle = getComputedStyle(document.documentElement);
10
+ const bodyScrollLocked = bodyStyle.overflowY === "hidden" || bodyStyle.overflow === "hidden";
11
+ const htmlScrollLocked = htmlStyle.overflowY === "hidden" || htmlStyle.overflow === "hidden";
12
+ const viewportLocked = Math.abs(document.documentElement.scrollHeight - window.innerHeight) <=
13
+ threshold &&
14
+ Math.abs((document.body?.scrollHeight ?? 0) - window.innerHeight) <=
15
+ threshold;
16
+ const fixedViewportShell = [...document.querySelectorAll("body *")].some((element) => {
17
+ const style = getComputedStyle(element);
18
+ const rect = element.getBoundingClientRect();
19
+ return ((style.position === "fixed" || style.position === "sticky") &&
20
+ rect.height >= window.innerHeight * 0.85 &&
21
+ rect.width >= window.innerWidth * 0.85);
22
+ });
23
+ const canvasHeavy = document.querySelectorAll("canvas").length >= 3;
24
+ const innerScrollContainers = [...document.querySelectorAll("*")].filter((element) => {
25
+ const style = getComputedStyle(element);
26
+ return ((style.overflowY === "auto" || style.overflowY === "scroll") &&
27
+ element.scrollHeight > element.clientHeight + threshold);
28
+ }).length;
29
+ return {
30
+ docMaxScroll,
31
+ viewportLocked,
32
+ bodyScrollLocked,
33
+ htmlScrollLocked,
34
+ fixedViewportShell,
35
+ canvasHeavy,
36
+ innerScrollContainers,
37
+ };
38
+ }, DOCUMENT_SCROLL_THRESHOLD_PX);
39
+ if (signals.docMaxScroll > DOCUMENT_SCROLL_THRESHOLD_PX) {
40
+ return "document";
41
+ }
42
+ const canNativeScroll = await page.evaluate(() => {
43
+ const before = window.scrollY;
44
+ window.scrollTo({ top: 100, left: 0, behavior: "instant" });
45
+ const after = window.scrollY;
46
+ window.scrollTo({ top: 0, left: 0, behavior: "instant" });
47
+ return after > before;
48
+ });
49
+ if (canNativeScroll) {
50
+ return "document";
51
+ }
52
+ const lowNativeScroll = signals.docMaxScroll <= DOCUMENT_SCROLL_THRESHOLD_PX;
53
+ const virtualSignals = [
54
+ lowNativeScroll && (signals.bodyScrollLocked || signals.htmlScrollLocked),
55
+ lowNativeScroll && signals.fixedViewportShell,
56
+ signals.canvasHeavy && lowNativeScroll,
57
+ signals.innerScrollContainers > 0 && lowNativeScroll,
58
+ ];
59
+ return virtualSignals.some(Boolean) ? "virtual" : "document";
60
+ }
61
+ //# sourceMappingURL=detectScrollMode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectScrollMode.js","sourceRoot":"","sources":["../../src/browser/detectScrollMode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { MotionPlanAdjustment, MotionTarget, ResolvedMotionBeat, ScrollCurve } from "../types.js";
2
+ export declare function normalizeResolvedBeats(options: {
3
+ beats: ResolvedMotionBeat[];
4
+ startHoldMs: number;
5
+ viewportHeight: number;
6
+ /** Converts position units to CSS/wheel pixels. Document scroll uses 1. */
7
+ positionScale?: number;
8
+ adjustments?: MotionPlanAdjustment[];
9
+ }): {
10
+ beats: {
11
+ target: MotionTarget;
12
+ position: number;
13
+ transitionMs: number;
14
+ holdMs: number;
15
+ curve: ScrollCurve;
16
+ interaction?: import("../types.js").ComponentInteraction;
17
+ framing?: import("../types.js").ResolvedBeatFraming;
18
+ }[];
19
+ adjustments: MotionPlanAdjustment[];
20
+ };
21
+ export declare function peakCurveSlope(curve: ScrollCurve): number;
22
+ //# sourceMappingURL=directionGuardrails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directionGuardrails.d.ts","sourceRoot":"","sources":["../../src/browser/directionGuardrails.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACZ,MAAM,aAAa,CAAC;AAOrB,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACtC;;;;;;;;;;;EAgFA;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,UAWhD"}
@@ -0,0 +1,99 @@
1
+ import { resolveScrollCurve } from "./curves.js";
2
+ import { applyScrollCurve } from "./scrollEasing.js";
3
+ const SAFE_CURVE = { preset: "ease-in-out-cubic" };
4
+ const MAX_VIEWPORTS_PER_SECOND = 1.5;
5
+ export function normalizeResolvedBeats(options) {
6
+ const scale = options.positionScale ?? 1;
7
+ const mergeDistance = Math.max(100, options.viewportHeight * 0.12);
8
+ const adjustments = [...(options.adjustments ?? [])];
9
+ const merged = [];
10
+ options.beats.forEach((beat, sourceIndex) => {
11
+ const previous = merged.at(-1);
12
+ const distancePx = previous
13
+ ? Math.abs(beat.position - previous.position) * scale
14
+ : Number.POSITIVE_INFINITY;
15
+ // Nearby scroll positions can still represent separate UI controls (for
16
+ // example two tabs inside one fixed product mockup). Never collapse an
17
+ // authored interaction into another beat.
18
+ if (previous && distancePx <= mergeDistance && !previous.interaction && !beat.interaction) {
19
+ const preferIncoming = targetRank(beat.target) > targetRank(previous.target);
20
+ const requested = beat.target;
21
+ if (preferIncoming) {
22
+ previous.target = beat.target;
23
+ previous.position = beat.position;
24
+ previous.framing = beat.framing;
25
+ }
26
+ previous.holdMs = Math.max(previous.holdMs, beat.holdMs);
27
+ adjustments.push({
28
+ beatIndex: sourceIndex,
29
+ code: "merged-nearby-beat",
30
+ message: `Merged a target only ${Math.round(distancePx)}px from the previous beat`,
31
+ requested,
32
+ resolved: previous.target,
33
+ });
34
+ return;
35
+ }
36
+ merged.push({ ...beat, sourceIndex });
37
+ });
38
+ let previousPosition = 0;
39
+ let previousHoldMs = options.startHoldMs;
40
+ for (const beat of merged) {
41
+ const bezier = resolveScrollCurve(beat.curve);
42
+ const startSlope = applyScrollCurve(0.001, bezier) / 0.001;
43
+ const endSlope = (1 - applyScrollCurve(0.999, bezier)) / 0.001;
44
+ const startsFast = previousHoldMs > 0 && startSlope > 0.25;
45
+ const stopsFast = beat.holdMs > 0 && endSlope > 0.25;
46
+ if (startsFast || stopsFast) {
47
+ const requested = beat.curve.preset ?? "custom";
48
+ beat.curve = SAFE_CURVE;
49
+ adjustments.push({
50
+ beatIndex: beat.sourceIndex,
51
+ code: "replaced-boundary-curve",
52
+ message: "Replaced a curve that would start or stop abruptly at a hold",
53
+ requested,
54
+ resolved: SAFE_CURVE.preset,
55
+ });
56
+ }
57
+ const distancePx = Math.abs(beat.position - previousPosition) * scale;
58
+ const peakSlope = peakCurveSlope(beat.curve);
59
+ const maxVelocity = options.viewportHeight * MAX_VIEWPORTS_PER_SECOND;
60
+ const minimumDurationMs = Math.ceil(((distancePx * peakSlope) / Math.max(1, maxVelocity) * 1000) / 50) * 50;
61
+ if (minimumDurationMs > beat.transitionMs) {
62
+ const requested = beat.transitionMs;
63
+ beat.transitionMs = minimumDurationMs;
64
+ adjustments.push({
65
+ beatIndex: beat.sourceIndex,
66
+ code: "stretched-transition",
67
+ message: `Stretched the transition to stay below ${MAX_VIEWPORTS_PER_SECOND} viewport heights per second`,
68
+ requested,
69
+ resolved: beat.transitionMs,
70
+ });
71
+ }
72
+ previousPosition = beat.position;
73
+ previousHoldMs = beat.holdMs;
74
+ }
75
+ return {
76
+ beats: merged.map(({ sourceIndex: _sourceIndex, ...beat }) => beat),
77
+ adjustments,
78
+ };
79
+ }
80
+ export function peakCurveSlope(curve) {
81
+ const bezier = resolveScrollCurve(curve);
82
+ let previous = 0;
83
+ let peak = 0;
84
+ const sampleCount = 1000;
85
+ for (let index = 1; index <= sampleCount; index += 1) {
86
+ const value = applyScrollCurve(index / sampleCount, bezier);
87
+ peak = Math.max(peak, (value - previous) * sampleCount);
88
+ previous = value;
89
+ }
90
+ return peak;
91
+ }
92
+ function targetRank(target) {
93
+ if (target.type === "selector")
94
+ return 3;
95
+ if (target.type === "progress")
96
+ return 2;
97
+ return 1;
98
+ }
99
+ //# sourceMappingURL=directionGuardrails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directionGuardrails.js","sourceRoot":"","sources":["../../src/browser/directionGuardrails.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Page } from 'playwright';
2
+ export interface PageAccessSnapshot {
3
+ status?: number;
4
+ title: string;
5
+ bodyText: string;
6
+ }
7
+ export declare function gotoReachablePage(page: Page, url: string): Promise<void>;
8
+ export declare function detectSiteProtectionBlock(snapshot: PageAccessSnapshot): boolean;
9
+ //# sourceMappingURL=goto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goto.d.ts","sourceRoot":"","sources":["../../src/browser/goto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,YAAY,CAAA;AAIhD,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB;AAKD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,iBA+B9D;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,kBAAkB,WAmBrE"}
@@ -0,0 +1,62 @@
1
+ import { assertAddressAllowed, assertSafeTargetUrl, installNetworkGuard, targetNetworkPolicyFromEnv } from './networkPolicy.js';
2
+ import { waitForScrollReady } from './scrollReadiness.js';
3
+ const SITE_PROTECTION_MESSAGE = 'Automation blocked by site protection. This website does not allow automated browser capture.';
4
+ export async function gotoReachablePage(page, url) {
5
+ const policy = targetNetworkPolicyFromEnv();
6
+ await assertSafeTargetUrl(url, policy);
7
+ await installNetworkGuard(page, policy);
8
+ let response;
9
+ try {
10
+ response = await page.goto(url, { waitUntil: 'load', timeout: 30000 });
11
+ }
12
+ catch (loadError) {
13
+ try {
14
+ response = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 15000 });
15
+ }
16
+ catch {
17
+ throw loadError;
18
+ }
19
+ }
20
+ await assertSafeTargetUrl(page.url(), policy);
21
+ const server = await response?.serverAddr().catch(() => null);
22
+ if (server?.ipAddress) {
23
+ assertAddressAllowed(server.ipAddress, new URL(page.url()).hostname, policy);
24
+ }
25
+ await assertPageAllowsAutomation(page, response?.status());
26
+ const readiness = await waitForScrollReady(page);
27
+ // Some challenge pages render a neutral shell first and replace it with the
28
+ // denial after their browser-verification script completes.
29
+ await assertPageAllowsAutomation(page, response?.status());
30
+ if (readiness.waited) {
31
+ console.log(readiness.timedOut
32
+ ? 'Scroll readiness remained locked; continuing with virtual-scroll detection.'
33
+ : 'Waited for a temporary scroll intro to release the document.');
34
+ }
35
+ }
36
+ export function detectSiteProtectionBlock(snapshot) {
37
+ if (snapshot.status === 401 || snapshot.status === 403)
38
+ return true;
39
+ const content = `${snapshot.title}\n${snapshot.bodyText}`
40
+ .replace(/\s+/g, ' ')
41
+ .trim()
42
+ .toLowerCase();
43
+ return (/\baccess denied\b/.test(content) ||
44
+ /\bfailed to verify (?:your )?browser\b/.test(content) ||
45
+ /\b(?:unable|could not) to verify (?:your )?browser\b/.test(content) ||
46
+ /\bbrowser verification (?:failed|required)\b/.test(content) ||
47
+ /\bverify (?:that )?you are human\b/.test(content) ||
48
+ /\bchecking (?:your )?browser\b/.test(content) ||
49
+ /\bsecurity checkpoint\b/.test(content) ||
50
+ /\bcaptcha (?:required|verification|challenge)\b/.test(content) ||
51
+ (/\bcode 21\b/.test(content) && /\b(?:browser|verify|security|challenge)\b/.test(content)));
52
+ }
53
+ async function assertPageAllowsAutomation(page, status) {
54
+ const snapshot = await page.evaluate(() => ({
55
+ title: document.title || '',
56
+ bodyText: (document.body?.innerText || '').slice(0, 8_000),
57
+ })).catch(() => ({ title: '', bodyText: '' }));
58
+ if (detectSiteProtectionBlock({ status, ...snapshot })) {
59
+ throw new Error(SITE_PROTECTION_MESSAGE);
60
+ }
61
+ }
62
+ //# sourceMappingURL=goto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goto.js","sourceRoot":"","sources":["../../src/browser/goto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Page } from "playwright";
2
+ export interface HydrateOptions {
3
+ fast?: boolean;
4
+ /** Wheel nudges help virtual-scroll sites; skip on document-scroll pages. */
5
+ useWheel?: boolean;
6
+ }
7
+ export declare function hydrateLazyContent(page: Page, viewportHeight: number, options?: HydrateOptions): Promise<void>;
8
+ //# sourceMappingURL=hydrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../../src/browser/hydrate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAUvC,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA2BD,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,EACV,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,cAAmB,iBAqE7B"}
@@ -0,0 +1,73 @@
1
+ const DEFAULT_SCROLL_SETTLE_MS = 350;
2
+ const DEFAULT_MAX_SCROLL_PASSES = 1;
3
+ const DEFAULT_MAX_SCROLL_STEPS = 24;
4
+ const FAST_SCROLL_SETTLE_MS = 180;
5
+ const FAST_MAX_SCROLL_PASSES = 1;
6
+ const FAST_MAX_SCROLL_STEPS = 10;
7
+ async function documentHeight(page) {
8
+ return page.evaluate(() => Math.max(document.documentElement.scrollHeight, document.body?.scrollHeight ?? 0, window.innerHeight));
9
+ }
10
+ async function waitForStableDocumentHeight(page, settleMs, fast) {
11
+ const checks = fast ? 2 : 4;
12
+ let last = await documentHeight(page);
13
+ for (let index = 0; index < checks; index += 1) {
14
+ await page.waitForTimeout(fast ? 150 : 350);
15
+ const next = await documentHeight(page);
16
+ if (Math.abs(next - last) < 8)
17
+ return;
18
+ last = next;
19
+ }
20
+ }
21
+ export async function hydrateLazyContent(page, viewportHeight, options = {}) {
22
+ const fast = options.fast ?? false;
23
+ const useWheel = options.useWheel ?? true;
24
+ const scrollSettleMs = fast
25
+ ? FAST_SCROLL_SETTLE_MS
26
+ : DEFAULT_SCROLL_SETTLE_MS;
27
+ const maxPasses = fast ? FAST_MAX_SCROLL_PASSES : DEFAULT_MAX_SCROLL_PASSES;
28
+ const maxSteps = fast ? FAST_MAX_SCROLL_STEPS : DEFAULT_MAX_SCROLL_STEPS;
29
+ const networkIdleTimeout = fast ? 1200 : 3000;
30
+ await page
31
+ .waitForLoadState("networkidle", { timeout: networkIdleTimeout })
32
+ .catch(() => undefined);
33
+ await page.evaluate(() => window.scrollTo({ top: 0, left: 0, behavior: "instant" }));
34
+ await page.waitForTimeout(fast ? 120 : 300);
35
+ let previousHeight = await documentHeight(page);
36
+ for (let pass = 0; pass < maxPasses; pass += 1) {
37
+ let y = 0;
38
+ for (let step = 0; step < maxSteps; step += 1) {
39
+ const height = await documentHeight(page);
40
+ const maxY = Math.max(0, height - viewportHeight);
41
+ y = Math.min(maxY, step === 0 ? 0 : y + Math.floor(viewportHeight * (fast ? 0.9 : 0.78)));
42
+ await page.evaluate((nextY) => window.scrollTo({ top: nextY, left: 0, behavior: "instant" }), y);
43
+ if (useWheel) {
44
+ await page.mouse
45
+ .wheel(0, Math.floor(viewportHeight * (fast ? 0.3 : 0.18)))
46
+ .catch(() => undefined);
47
+ }
48
+ await page.waitForTimeout(scrollSettleMs);
49
+ if (y >= maxY)
50
+ break;
51
+ }
52
+ await page.evaluate(() => window.scrollTo({
53
+ top: document.documentElement.scrollHeight,
54
+ left: 0,
55
+ behavior: "instant",
56
+ }));
57
+ await page.waitForTimeout(scrollSettleMs);
58
+ const nextHeight = await documentHeight(page);
59
+ if (Math.abs(nextHeight - previousHeight) < 8)
60
+ break;
61
+ previousHeight = nextHeight;
62
+ }
63
+ await page.evaluate(() => window.scrollTo({
64
+ top: document.documentElement.scrollHeight,
65
+ left: 0,
66
+ behavior: "instant",
67
+ }));
68
+ await page.waitForTimeout(fast ? 200 : 700);
69
+ await page.evaluate(() => window.scrollTo({ top: 0, left: 0, behavior: "instant" }));
70
+ await page.waitForTimeout(fast ? 200 : 700);
71
+ await waitForStableDocumentHeight(page, scrollSettleMs, fast);
72
+ }
73
+ //# sourceMappingURL=hydrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrate.js","sourceRoot":"","sources":["../../src/browser/hydrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Page } from "playwright";
2
+ /**
3
+ * Screenshot capture can be substantially slower than its output frame rate.
4
+ * Native videos otherwise advance at wall-clock speed and appear fast-forwarded
5
+ * in the encoded sequence. This controller keeps them on the output timeline.
6
+ */
7
+ export declare function installMediaClock(page: Page): Promise<void>;
8
+ export declare function createMediaClockSync(page: Page, fps: number): Promise<(frameNumber: number) => Promise<void>>;
9
+ //# sourceMappingURL=mediaClock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediaClock.d.ts","sourceRoot":"","sources":["../../src/browser/mediaClock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAgEjE;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,yBAGrC,MAAM,oBAelC"}
@@ -0,0 +1,86 @@
1
+ import { performance } from "node:perf_hooks";
2
+ const MEDIA_CLOCK_KEY = "__websiterecorderMediaClock";
3
+ /**
4
+ * Screenshot capture can be substantially slower than its output frame rate.
5
+ * Native videos otherwise advance at wall-clock speed and appear fast-forwarded
6
+ * in the encoded sequence. This controller keeps them on the output timeline.
7
+ */
8
+ export async function installMediaClock(page) {
9
+ // Use source text rather than a serialized TypeScript callback. tsx/esbuild
10
+ // annotates nested functions with a global __name helper that is not present
11
+ // in a page's isolated init-script world.
12
+ await page.addInitScript({ content: `(() => {
13
+ const key = ${JSON.stringify(MEDIA_CLOCK_KEY)};
14
+ const state = {
15
+ active: false,
16
+ rate: 0.08,
17
+ videos: new Set(),
18
+ register(video) {
19
+ this.videos.add(video);
20
+ video.muted = true;
21
+ setPlaybackRate(video, this.rate);
22
+ if (!this.active) video.pause();
23
+ },
24
+ sync(rate) {
25
+ this.active = true;
26
+ this.rate = rate;
27
+ document.querySelectorAll("video").forEach((video) => this.register(video));
28
+ for (const video of this.videos) {
29
+ if (!video.isConnected) continue;
30
+ video.muted = true;
31
+ setPlaybackRate(video, rate);
32
+ video.play().catch(() => undefined);
33
+ }
34
+ for (const animation of document.getAnimations()) {
35
+ if (animation.timeline && animation.timeline !== document.timeline) continue;
36
+ try {
37
+ animation.playbackRate = rate;
38
+ } catch {
39
+ try {
40
+ animation.updatePlaybackRate(rate);
41
+ } catch {
42
+ // Scroll-timeline or page-owned animations can reject control.
43
+ }
44
+ }
45
+ }
46
+ },
47
+ };
48
+
49
+ // Chromium's supported range varies by media implementation. Keep the
50
+ // controller from failing the whole capture when a page rejects a rate.
51
+ function setPlaybackRate(video, rate) {
52
+ try {
53
+ video.playbackRate = Math.max(0.0625, Math.min(16, rate));
54
+ } catch {
55
+ try {
56
+ video.playbackRate = 0.25;
57
+ } catch {
58
+ // Leave the site's default rate in place rather than failing capture.
59
+ }
60
+ }
61
+ }
62
+
63
+ Object.defineProperty(window, key, { value: state, configurable: true });
64
+ document.addEventListener("play", (event) => {
65
+ const video = event.target;
66
+ if (video instanceof HTMLVideoElement) state.register(video);
67
+ }, true);
68
+ document.addEventListener("DOMContentLoaded", () => {
69
+ document.querySelectorAll("video").forEach((video) => state.register(video));
70
+ }, { once: true });
71
+ })()` });
72
+ }
73
+ export async function createMediaClockSync(page, fps) {
74
+ const startedAt = performance.now();
75
+ return async (frameNumber) => {
76
+ const outputSeconds = frameNumber / fps;
77
+ const wallSeconds = Math.max(0.001, (performance.now() - startedAt) / 1000);
78
+ // A little floor avoids stalling media on very slow, high-resolution captures.
79
+ const rate = Math.min(1, Math.max(0.0625, outputSeconds / wallSeconds || 0.08));
80
+ await page.evaluate(({ key, rate: nextRate }) => {
81
+ const state = window[key];
82
+ state?.sync?.(nextRate);
83
+ }, { key: MEDIA_CLOCK_KEY, rate });
84
+ };
85
+ }
86
+ //# sourceMappingURL=mediaClock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediaClock.js","sourceRoot":"","sources":["../../src/browser/mediaClock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,MAAM,eAAe,GAAG,6BAA6B,CAAC;AAEtD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAU;IAChD,4EAA4E;IAC5E,6EAA6E;IAC7E,0CAA0C;IAC1C,MAAM,IAAI,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE;kBACpB,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0D1C,EAAE,CAAC,CAAC;AACX,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAU,EAAE,GAAW;IAChE,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAEpC,OAAO,KAAK,EAAE,WAAmB,EAAE,EAAE;QACnC,MAAM,aAAa,GAAG,WAAW,GAAG,GAAG,CAAC;QACxC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5E,+EAA+E;QAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC;QAChF,MAAM,IAAI,CAAC,QAAQ,CACjB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;YAC1B,MAAM,KAAK,GAAI,MAEZ,CAAC,GAAG,CAAC,CAAC;YACT,KAAK,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC,EACD,EAAE,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,CAC/B,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { BezierControlPoints } from "./curves.js";
2
+ export interface TimelineBeat {
3
+ position: number;
4
+ transitionMs: number;
5
+ holdMs: number;
6
+ bezier: BezierControlPoints;
7
+ }
8
+ export interface MotionSample {
9
+ position: number;
10
+ phase: "transition" | "hold";
11
+ beatIndex: number;
12
+ phaseProgress?: number;
13
+ }
14
+ export declare function buildMotionTimeline(options: {
15
+ fps: number;
16
+ startPosition?: number;
17
+ startHoldMs?: number;
18
+ beats: TimelineBeat[];
19
+ }): MotionSample[];
20
+ export declare function framesForDuration(durationMs: number, fps: number): number;
21
+ //# sourceMappingURL=motion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"motion.d.ts","sourceRoot":"","sources":["../../src/browser/motion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,GAAG,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,GAAG,YAAY,EAAE,CAwCjB;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,UAEhE"}
@@ -0,0 +1,42 @@
1
+ import { applyScrollCurve } from "./scrollEasing.js";
2
+ export function buildMotionTimeline(options) {
3
+ const fps = Math.max(1, options.fps);
4
+ const samples = [];
5
+ let position = options.startPosition ?? 0;
6
+ const startHoldFrames = framesForDuration(options.startHoldMs ?? 0, fps);
7
+ for (let frame = 0; frame < startHoldFrames; frame += 1) {
8
+ samples.push({ position, phase: "hold", beatIndex: -1, phaseProgress: startHoldFrames <= 1 ? 1 : frame / (startHoldFrames - 1) });
9
+ }
10
+ options.beats.forEach((beat, beatIndex) => {
11
+ const start = position;
12
+ const transitionFrames = Math.max(1, framesForDuration(beat.transitionMs, fps));
13
+ for (let frame = 1; frame <= transitionFrames; frame += 1) {
14
+ const progress = frame / transitionFrames;
15
+ const eased = applyScrollCurve(progress, beat.bezier);
16
+ samples.push({
17
+ position: start + (beat.position - start) * eased,
18
+ phase: "transition",
19
+ beatIndex,
20
+ phaseProgress: progress,
21
+ });
22
+ }
23
+ position = beat.position;
24
+ const holdFrames = framesForDuration(beat.holdMs, fps);
25
+ for (let frame = 0; frame < holdFrames; frame += 1) {
26
+ samples.push({
27
+ position,
28
+ phase: "hold",
29
+ beatIndex,
30
+ phaseProgress: holdFrames <= 1 ? 1 : frame / (holdFrames - 1),
31
+ });
32
+ }
33
+ });
34
+ if (samples.length === 0) {
35
+ samples.push({ position, phase: "hold", beatIndex: -1, phaseProgress: 1 });
36
+ }
37
+ return samples;
38
+ }
39
+ export function framesForDuration(durationMs, fps) {
40
+ return Math.max(0, Math.round((Math.max(0, durationMs) / 1000) * fps));
41
+ }
42
+ //# sourceMappingURL=motion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"motion.js","sourceRoot":"","sources":["../../src/browser/motion.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAgBrD,MAAM,UAAU,mBAAmB,CAAC,OAKnC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,IAAI,QAAQ,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC;IAE1C,MAAM,eAAe,GAAG,iBAAiB,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACzE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,eAAe,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,eAAe,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,eAAe,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IACpI,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,QAAQ,CAAC;QACvB,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC;QAChF,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,gBAAgB,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YAC1D,MAAM,QAAQ,GAAG,KAAK,GAAG,gBAAgB,CAAC;YAC1C,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC;gBACX,QAAQ,EAAE,KAAK,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,GAAG,KAAK;gBACjD,KAAK,EAAE,YAAY;gBACnB,SAAS;gBACT,aAAa,EAAE,QAAQ;aACxB,CAAC,CAAC;QACL,CAAC;QACD,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAEzB,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACvD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,CAAC,IAAI,CAAC;gBACX,QAAQ;gBACR,KAAK,EAAE,MAAM;gBACb,SAAS;gBACT,aAAa,EAAE,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC;aAC9D,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,UAAkB,EAAE,GAAW;IAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Page } from "playwright";
2
+ export interface TargetNetworkPolicy {
3
+ allowLocalhost: boolean;
4
+ allowPrivateNetworks: boolean;
5
+ }
6
+ export declare function targetNetworkPolicyFromEnv(): TargetNetworkPolicy;
7
+ export declare function installNetworkGuard(page: Page, policy?: TargetNetworkPolicy): Promise<void>;
8
+ export declare function assertSafeTargetUrl(value: string, policy?: TargetNetworkPolicy): Promise<URL>;
9
+ export declare function assertAddressAllowed(address: string, hostname: string, policy: TargetNetworkPolicy): void;
10
+ export declare function addressCategory(address: string): "public" | "loopback" | "private";
11
+ //# sourceMappingURL=networkPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"networkPolicy.d.ts","sourceRoot":"","sources":["../../src/browser/networkPolicy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAS,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,OAAO,CAAC;IACxB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAKD,wBAAgB,0BAA0B,IAAI,mBAAmB,CAMhE;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,MAAM,sBAA+B,iBAYtC;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,MAAM,sBAA+B,gBAiBtC;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,QAa5B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CA0BlF"}