@percy/sdk-utils 1.31.14-beta.2 → 1.31.14-beta.4

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/dist/bundle.js CHANGED
@@ -326,6 +326,86 @@
326
326
  }
327
327
  }
328
328
 
329
+ // Returns the readiness config for a snapshot.
330
+ // Priority: per-snapshot options > global percy.config > empty object (triggers balanced default).
331
+ // SDKs obtain percy.config via the healthcheck endpoint in isPercyEnabled().
332
+ function getReadinessConfig(snapshotOptions = {}) {
333
+ var _percy$config;
334
+ return (snapshotOptions === null || snapshotOptions === void 0 ? void 0 : snapshotOptions.readiness) || ((_percy$config = info.config) === null || _percy$config === void 0 || (_percy$config = _percy$config.snapshot) === null || _percy$config === void 0 ? void 0 : _percy$config.readiness) || {};
335
+ }
336
+
337
+ // Returns true if readiness should be skipped for this snapshot.
338
+ function isReadinessDisabled(snapshotOptions = {}) {
339
+ let config = getReadinessConfig(snapshotOptions);
340
+ return (config === null || config === void 0 ? void 0 : config.preset) === 'disabled';
341
+ }
342
+
343
+ // Returns a JavaScript code string that SDKs evaluate in the browser
344
+ // to run readiness checks BEFORE serialize.
345
+ //
346
+ // This is the READINESS-ONLY call. Serialize stays as a separate sync call.
347
+ // The two-call pattern:
348
+ // 1. await evaluate(waitForReadyScript(config)) — async, readiness
349
+ // 2. evaluate('return PercyDOM.serialize(options)') — sync, unchanged
350
+ //
351
+ // Usage:
352
+ // // Puppeteer/Playwright (page.evaluate auto-awaits):
353
+ // await page.evaluate(waitForReadyScript(config));
354
+ //
355
+ // // Selenium (executeAsyncScript with callback):
356
+ // driver.execute_async_script(waitForReadyScript(config, { callback: true }));
357
+ //
358
+ // Graceful degradation:
359
+ // - If PercyDOM.waitForReady is not available (old CLI): resolves immediately
360
+ // - If waitForReady throws: resolves immediately (catch swallows the error)
361
+ // - If readiness times out: waitForReady resolves with { timed_out: true }
362
+ //
363
+ // IMPORTANT: The output is intended for CDP / executeScript / executeAsyncScript channels.
364
+ // Do NOT inline this string into HTML — `</script>` sequences in user config would break out
365
+ // of a <script> tag. SDK authors must add HTML escaping before any HTML-inline use.
366
+ function waitForReadyScript(readinessConfig = {}, {
367
+ callback = false
368
+ } = {}) {
369
+ // U+2028 (LINE SEPARATOR) and U+2029 (PARAGRAPH SEPARATOR) are valid in JSON strings but
370
+ // were illegal in JS source string literals before ES2019. Escaping them keeps the emitted
371
+ // script source legal on older engines that may host the SDK eval.
372
+ let config = JSON.stringify(readinessConfig).replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
373
+ if (callback) {
374
+ // For executeAsyncScript — last argument is the callback
375
+ return `
376
+ var done = arguments[arguments.length - 1];
377
+ try {
378
+ if (typeof PercyDOM !== 'undefined' && typeof PercyDOM.waitForReady === 'function') {
379
+ PercyDOM.waitForReady(${config}).then(function(r) { done(r); }).catch(function() { done(); });
380
+ } else { done(); }
381
+ } catch(e) { done(); }
382
+ `;
383
+ }
384
+
385
+ // For page.evaluate (auto-await Promises)
386
+ return `
387
+ if (typeof PercyDOM !== 'undefined' && typeof PercyDOM.waitForReady === 'function') {
388
+ return PercyDOM.waitForReady(${config});
389
+ }
390
+ `;
391
+ }
392
+
393
+ // Iframe depth constants shared with @percy/dom's serialize-frames. Kept
394
+ // here so external Percy SDKs (Capybara, Cypress, Playwright, etc.) can
395
+ // clamp their own pre-CLI configuration to the same bounds the CLI enforces.
396
+ //
397
+ // MIRROR: must match @percy/dom/src/serialize-frames.js. The pair is kept
398
+ // duplicated (rather than imported across the package boundary) because the
399
+ // previous cross-package import broke Node 14 CI; the parity test below
400
+ // enforces alignment instead. Don't change one without changing the other.
401
+ const DEFAULT_MAX_IFRAME_DEPTH = 3;
402
+ const HARD_MAX_IFRAME_DEPTH = 10;
403
+ function clampIframeDepth(raw) {
404
+ const n = Number(raw);
405
+ if (!Number.isFinite(n) || n < 1) return DEFAULT_MAX_IFRAME_DEPTH;
406
+ return Math.min(Math.floor(n), HARD_MAX_IFRAME_DEPTH);
407
+ }
408
+
329
409
  var index = /*#__PURE__*/Object.freeze({
330
410
  __proto__: null,
331
411
  logger: logger,
@@ -340,15 +420,26 @@
340
420
  captureAutomateScreenshot: captureAutomateScreenshot,
341
421
  postBuildEvents: postBuildEvents,
342
422
  getResponsiveWidths: getResponsiveWidths,
423
+ DEFAULT_MAX_IFRAME_DEPTH: DEFAULT_MAX_IFRAME_DEPTH,
424
+ HARD_MAX_IFRAME_DEPTH: HARD_MAX_IFRAME_DEPTH,
425
+ clampIframeDepth: clampIframeDepth,
426
+ waitForReadyScript: waitForReadyScript,
427
+ getReadinessConfig: getReadinessConfig,
428
+ isReadinessDisabled: isReadinessDisabled,
343
429
  'default': index
344
430
  });
345
431
 
432
+ exports.DEFAULT_MAX_IFRAME_DEPTH = DEFAULT_MAX_IFRAME_DEPTH;
433
+ exports.HARD_MAX_IFRAME_DEPTH = HARD_MAX_IFRAME_DEPTH;
346
434
  exports.captureAutomateScreenshot = captureAutomateScreenshot;
435
+ exports.clampIframeDepth = clampIframeDepth;
347
436
  exports["default"] = index;
348
437
  exports.fetchPercyDOM = fetchPercyDOM;
349
438
  exports.flushSnapshots = flushSnapshots;
439
+ exports.getReadinessConfig = getReadinessConfig;
350
440
  exports.getResponsiveWidths = getResponsiveWidths;
351
441
  exports.isPercyEnabled = isPercyEnabled;
442
+ exports.isReadinessDisabled = isReadinessDisabled;
352
443
  exports.logger = logger;
353
444
  exports.percy = info;
354
445
  exports.postBuildEvents = postBuildEvents;
@@ -356,6 +447,7 @@
356
447
  exports.postSnapshot = postSnapshot;
357
448
  exports.request = request;
358
449
  exports.waitForPercyIdle = waitForPercyIdle;
450
+ exports.waitForReadyScript = waitForReadyScript;
359
451
 
360
452
  Object.defineProperty(exports, '__esModule', { value: true });
361
453
 
package/dist/index.js CHANGED
@@ -3,12 +3,14 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.HARD_MAX_IFRAME_DEPTH = exports.DEFAULT_MAX_IFRAME_DEPTH = void 0;
6
7
  Object.defineProperty(exports, "captureAutomateScreenshot", {
7
8
  enumerable: true,
8
9
  get: function () {
9
10
  return _postScreenshot.default;
10
11
  }
11
12
  });
13
+ exports.clampIframeDepth = clampIframeDepth;
12
14
  exports.default = void 0;
13
15
  Object.defineProperty(exports, "fetchPercyDOM", {
14
16
  enumerable: true,
@@ -22,6 +24,12 @@ Object.defineProperty(exports, "flushSnapshots", {
22
24
  return _flushSnapshots.default;
23
25
  }
24
26
  });
27
+ Object.defineProperty(exports, "getReadinessConfig", {
28
+ enumerable: true,
29
+ get: function () {
30
+ return _serializeDom.getReadinessConfig;
31
+ }
32
+ });
25
33
  Object.defineProperty(exports, "getResponsiveWidths", {
26
34
  enumerable: true,
27
35
  get: function () {
@@ -34,6 +42,12 @@ Object.defineProperty(exports, "isPercyEnabled", {
34
42
  return _percyEnabled.default;
35
43
  }
36
44
  });
45
+ Object.defineProperty(exports, "isReadinessDisabled", {
46
+ enumerable: true,
47
+ get: function () {
48
+ return _serializeDom.isReadinessDisabled;
49
+ }
50
+ });
37
51
  Object.defineProperty(exports, "logger", {
38
52
  enumerable: true,
39
53
  get: function () {
@@ -76,6 +90,12 @@ Object.defineProperty(exports, "waitForPercyIdle", {
76
90
  return _percyIdle.default;
77
91
  }
78
92
  });
93
+ Object.defineProperty(exports, "waitForReadyScript", {
94
+ enumerable: true,
95
+ get: function () {
96
+ return _serializeDom.waitForReadyScript;
97
+ }
98
+ });
79
99
  var _logger = _interopRequireDefault(require("./logger.js"));
80
100
  var _percyInfo = _interopRequireDefault(require("./percy-info.js"));
81
101
  var _request = _interopRequireDefault(require("./request.js"));
@@ -88,8 +108,26 @@ var _postBuildEvent = _interopRequireDefault(require("./post-build-event.js"));
88
108
  var _flushSnapshots = _interopRequireDefault(require("./flush-snapshots.js"));
89
109
  var _postScreenshot = _interopRequireDefault(require("./post-screenshot.js"));
90
110
  var _getResponsiveWidths = _interopRequireDefault(require("./get-responsive-widths.js"));
111
+ var _serializeDom = require("./serialize-dom.js");
91
112
  var _default = _interopRequireWildcard(require("./index.js"));
92
113
  exports.default = _default;
93
114
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
94
115
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
95
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
116
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
117
+ // Iframe depth constants shared with @percy/dom's serialize-frames. Kept
118
+ // here so external Percy SDKs (Capybara, Cypress, Playwright, etc.) can
119
+ // clamp their own pre-CLI configuration to the same bounds the CLI enforces.
120
+ //
121
+ // MIRROR: must match @percy/dom/src/serialize-frames.js. The pair is kept
122
+ // duplicated (rather than imported across the package boundary) because the
123
+ // previous cross-package import broke Node 14 CI; the parity test below
124
+ // enforces alignment instead. Don't change one without changing the other.
125
+ const DEFAULT_MAX_IFRAME_DEPTH = exports.DEFAULT_MAX_IFRAME_DEPTH = 3;
126
+ const HARD_MAX_IFRAME_DEPTH = exports.HARD_MAX_IFRAME_DEPTH = 10;
127
+ function clampIframeDepth(raw) {
128
+ const n = Number(raw);
129
+ if (!Number.isFinite(n) || n < 1) return DEFAULT_MAX_IFRAME_DEPTH;
130
+ return Math.min(Math.floor(n), HARD_MAX_IFRAME_DEPTH);
131
+ }
132
+
133
+ // export the namespace by default
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ exports.getReadinessConfig = getReadinessConfig;
8
+ exports.isReadinessDisabled = isReadinessDisabled;
9
+ exports.waitForReadyScript = waitForReadyScript;
10
+ var _percyInfo = _interopRequireDefault(require("./percy-info.js"));
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ // Returns the readiness config for a snapshot.
13
+ // Priority: per-snapshot options > global percy.config > empty object (triggers balanced default).
14
+ // SDKs obtain percy.config via the healthcheck endpoint in isPercyEnabled().
15
+ function getReadinessConfig(snapshotOptions = {}) {
16
+ var _percy$config;
17
+ return (snapshotOptions === null || snapshotOptions === void 0 ? void 0 : snapshotOptions.readiness) || ((_percy$config = _percyInfo.default.config) === null || _percy$config === void 0 || (_percy$config = _percy$config.snapshot) === null || _percy$config === void 0 ? void 0 : _percy$config.readiness) || {};
18
+ }
19
+
20
+ // Returns true if readiness should be skipped for this snapshot.
21
+ function isReadinessDisabled(snapshotOptions = {}) {
22
+ let config = getReadinessConfig(snapshotOptions);
23
+ return (config === null || config === void 0 ? void 0 : config.preset) === 'disabled';
24
+ }
25
+
26
+ // Returns a JavaScript code string that SDKs evaluate in the browser
27
+ // to run readiness checks BEFORE serialize.
28
+ //
29
+ // This is the READINESS-ONLY call. Serialize stays as a separate sync call.
30
+ // The two-call pattern:
31
+ // 1. await evaluate(waitForReadyScript(config)) — async, readiness
32
+ // 2. evaluate('return PercyDOM.serialize(options)') — sync, unchanged
33
+ //
34
+ // Usage:
35
+ // // Puppeteer/Playwright (page.evaluate auto-awaits):
36
+ // await page.evaluate(waitForReadyScript(config));
37
+ //
38
+ // // Selenium (executeAsyncScript with callback):
39
+ // driver.execute_async_script(waitForReadyScript(config, { callback: true }));
40
+ //
41
+ // Graceful degradation:
42
+ // - If PercyDOM.waitForReady is not available (old CLI): resolves immediately
43
+ // - If waitForReady throws: resolves immediately (catch swallows the error)
44
+ // - If readiness times out: waitForReady resolves with { timed_out: true }
45
+ //
46
+ // IMPORTANT: The output is intended for CDP / executeScript / executeAsyncScript channels.
47
+ // Do NOT inline this string into HTML — `</script>` sequences in user config would break out
48
+ // of a <script> tag. SDK authors must add HTML escaping before any HTML-inline use.
49
+ function waitForReadyScript(readinessConfig = {}, {
50
+ callback = false
51
+ } = {}) {
52
+ // U+2028 (LINE SEPARATOR) and U+2029 (PARAGRAPH SEPARATOR) are valid in JSON strings but
53
+ // were illegal in JS source string literals before ES2019. Escaping them keeps the emitted
54
+ // script source legal on older engines that may host the SDK eval.
55
+ let config = JSON.stringify(readinessConfig).replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
56
+ if (callback) {
57
+ // For executeAsyncScript — last argument is the callback
58
+ return `
59
+ var done = arguments[arguments.length - 1];
60
+ try {
61
+ if (typeof PercyDOM !== 'undefined' && typeof PercyDOM.waitForReady === 'function') {
62
+ PercyDOM.waitForReady(${config}).then(function(r) { done(r); }).catch(function() { done(); });
63
+ } else { done(); }
64
+ } catch(e) { done(); }
65
+ `;
66
+ }
67
+
68
+ // For page.evaluate (auto-await Promises)
69
+ return `
70
+ if (typeof PercyDOM !== 'undefined' && typeof PercyDOM.waitForReady === 'function') {
71
+ return PercyDOM.waitForReady(${config});
72
+ }
73
+ `;
74
+ }
75
+ var _default = exports.default = waitForReadyScript;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percy/sdk-utils",
3
- "version": "1.31.14-beta.2",
3
+ "version": "1.31.14-beta.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -54,5 +54,5 @@
54
54
  "dependencies": {
55
55
  "pac-proxy-agent": "^7.0.2"
56
56
  },
57
- "gitHead": "e4fce73023453b77cdef50aac1a9bd5eb70cd01a"
57
+ "gitHead": "b52f1d2fb6272c0b3694e1e9ff584c5622a118c7"
58
58
  }