@afixt/screenshot-utils 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/LICENSE +13 -0
- package/README.md +132 -0
- package/bin/afixt-screenshot +14 -0
- package/dist/index.js +2797 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2795 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +164 -0
- package/src/adapters/cdp.js +116 -0
- package/src/adapters/index.js +17 -0
- package/src/adapters/playwright.js +150 -0
- package/src/adapters/puppeteer.js +128 -0
- package/src/capture/element.js +257 -0
- package/src/capture/index.js +17 -0
- package/src/capture/long-page.js +267 -0
- package/src/capture/page.js +207 -0
- package/src/capture/responsive.js +94 -0
- package/src/capture/settle.js +182 -0
- package/src/capture/viewport.js +21 -0
- package/src/cli/index.js +266 -0
- package/src/compose/annotate.js +283 -0
- package/src/compose/diff.js +173 -0
- package/src/compose/heatmap.js +159 -0
- package/src/compose/index.js +8 -0
- package/src/compose/theme.js +45 -0
- package/src/errors/adapter.js +65 -0
- package/src/errors/base.js +48 -0
- package/src/errors/capture.js +175 -0
- package/src/errors/compose.js +78 -0
- package/src/errors/index.js +75 -0
- package/src/errors/optional.js +37 -0
- package/src/errors/redaction.js +42 -0
- package/src/errors/tile.js +61 -0
- package/src/errors/transform.js +78 -0
- package/src/index.js +69 -0
- package/src/redact/index.js +6 -0
- package/src/redact/policy.js +67 -0
- package/src/redact/redact.js +268 -0
- package/src/tile/dzi.js +268 -0
- package/src/tile/index.js +5 -0
- package/src/transform/convert.js +54 -0
- package/src/transform/crop.js +251 -0
- package/src/transform/index.js +8 -0
- package/src/transform/normalize.js +83 -0
- package/src/transform/resize.js +99 -0
- package/src/types/index.d.ts +432 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ScreenshotUtilsError } = require('./base.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base for errors arising during composition (annotate, heatmap, diff, composite).
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
class ComposeError extends ScreenshotUtilsError {
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} message
|
|
13
|
+
* @param {object} [options]
|
|
14
|
+
*/
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super(message, options);
|
|
17
|
+
this.code = 'COMPOSE_ERROR';
|
|
18
|
+
this.retriable = false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `diff()` was called with two images whose dimensions don't match.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
class DimensionMismatchError extends ComposeError {
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} message
|
|
30
|
+
* @param {object} [options]
|
|
31
|
+
*/
|
|
32
|
+
constructor(message, options) {
|
|
33
|
+
super(message, options);
|
|
34
|
+
this.code = 'DIMENSION_MISMATCH';
|
|
35
|
+
this.retriable = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* An annotation theme is missing a required key or has invalid values.
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
class ThemeError extends ComposeError {
|
|
45
|
+
/**
|
|
46
|
+
* @param {string} message
|
|
47
|
+
* @param {object} [options]
|
|
48
|
+
*/
|
|
49
|
+
constructor(message, options) {
|
|
50
|
+
super(message, options);
|
|
51
|
+
this.code = 'THEME_ERROR';
|
|
52
|
+
this.retriable = false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A heatmap point is malformed (e.g., missing x/y, negative weight, NaN).
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
class HeatmapPointError extends ComposeError {
|
|
62
|
+
/**
|
|
63
|
+
* @param {string} message
|
|
64
|
+
* @param {object} [options]
|
|
65
|
+
*/
|
|
66
|
+
constructor(message, options) {
|
|
67
|
+
super(message, options);
|
|
68
|
+
this.code = 'HEATMAP_POINT';
|
|
69
|
+
this.retriable = false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = {
|
|
74
|
+
ComposeError,
|
|
75
|
+
DimensionMismatchError,
|
|
76
|
+
ThemeError,
|
|
77
|
+
HeatmapPointError,
|
|
78
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Barrel for the public error hierarchy. Import from here, not from the
|
|
5
|
+
* individual files — the indirection keeps instanceof chains stable when
|
|
6
|
+
* the package is consumed via either CJS or ESM.
|
|
7
|
+
*
|
|
8
|
+
* @module screenshot-utils/errors
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { ScreenshotUtilsError } = require('./base.js');
|
|
12
|
+
const {
|
|
13
|
+
CaptureError,
|
|
14
|
+
BrowserUnavailableError,
|
|
15
|
+
PageTooTallError,
|
|
16
|
+
ElementNotFoundError,
|
|
17
|
+
ElementNotVisibleError,
|
|
18
|
+
ElementMismatchError,
|
|
19
|
+
ElementTooLargeError,
|
|
20
|
+
StabilityTimeoutError,
|
|
21
|
+
CaptureTimeoutError,
|
|
22
|
+
} = require('./capture.js');
|
|
23
|
+
const {
|
|
24
|
+
TransformError,
|
|
25
|
+
InvalidRectError,
|
|
26
|
+
UnsupportedFormatError,
|
|
27
|
+
BufferCorruptError,
|
|
28
|
+
} = require('./transform.js');
|
|
29
|
+
const {
|
|
30
|
+
ComposeError,
|
|
31
|
+
DimensionMismatchError,
|
|
32
|
+
ThemeError,
|
|
33
|
+
HeatmapPointError,
|
|
34
|
+
} = require('./compose.js');
|
|
35
|
+
const { TileError, TileSizeError, TileWriteError } = require('./tile.js');
|
|
36
|
+
const { RedactionError, PolicyError } = require('./redaction.js');
|
|
37
|
+
const { AdapterError, AdapterContractError, BrowserApiError } = require('./adapter.js');
|
|
38
|
+
const { OptionalDependencyMissingError } = require('./optional.js');
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
ScreenshotUtilsError,
|
|
42
|
+
// capture
|
|
43
|
+
CaptureError,
|
|
44
|
+
BrowserUnavailableError,
|
|
45
|
+
PageTooTallError,
|
|
46
|
+
ElementNotFoundError,
|
|
47
|
+
ElementNotVisibleError,
|
|
48
|
+
ElementMismatchError,
|
|
49
|
+
ElementTooLargeError,
|
|
50
|
+
StabilityTimeoutError,
|
|
51
|
+
CaptureTimeoutError,
|
|
52
|
+
// transform
|
|
53
|
+
TransformError,
|
|
54
|
+
InvalidRectError,
|
|
55
|
+
UnsupportedFormatError,
|
|
56
|
+
BufferCorruptError,
|
|
57
|
+
// compose
|
|
58
|
+
ComposeError,
|
|
59
|
+
DimensionMismatchError,
|
|
60
|
+
ThemeError,
|
|
61
|
+
HeatmapPointError,
|
|
62
|
+
// tile
|
|
63
|
+
TileError,
|
|
64
|
+
TileSizeError,
|
|
65
|
+
TileWriteError,
|
|
66
|
+
// redaction
|
|
67
|
+
RedactionError,
|
|
68
|
+
PolicyError,
|
|
69
|
+
// adapter
|
|
70
|
+
AdapterError,
|
|
71
|
+
AdapterContractError,
|
|
72
|
+
BrowserApiError,
|
|
73
|
+
// optional peers
|
|
74
|
+
OptionalDependencyMissingError,
|
|
75
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ScreenshotUtilsError } = require('./base.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An operation needs an optional peer dependency that isn't installed
|
|
7
|
+
* (e.g., calling `diff()` without `pixelmatch`). The error message MUST
|
|
8
|
+
* include the install command for the missing package.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
class OptionalDependencyMissingError extends ScreenshotUtilsError {
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} message
|
|
15
|
+
* @param {object} [options]
|
|
16
|
+
* @param {string} [options.packageName] The npm package the caller must install.
|
|
17
|
+
* @param {string} [options.installCommand] Suggested install command (default: derived).
|
|
18
|
+
*/
|
|
19
|
+
constructor(message, options = {}) {
|
|
20
|
+
const { packageName, installCommand, ...rest } = options;
|
|
21
|
+
super(message, rest);
|
|
22
|
+
this.code = 'OPTIONAL_DEPENDENCY_MISSING';
|
|
23
|
+
this.retriable = false;
|
|
24
|
+
if (packageName !== undefined) {
|
|
25
|
+
this.packageName = packageName;
|
|
26
|
+
}
|
|
27
|
+
if (installCommand !== undefined) {
|
|
28
|
+
this.installCommand = installCommand;
|
|
29
|
+
} else if (packageName !== undefined) {
|
|
30
|
+
this.installCommand = `npm install ${packageName}`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
OptionalDependencyMissingError,
|
|
37
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ScreenshotUtilsError } = require('./base.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base for errors arising during redaction (blur / mask / pixelate, PII policies).
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
class RedactionError extends ScreenshotUtilsError {
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} message
|
|
13
|
+
* @param {object} [options]
|
|
14
|
+
*/
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super(message, options);
|
|
17
|
+
this.code = 'REDACTION_ERROR';
|
|
18
|
+
this.retriable = false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A PII policy object is malformed or references unknown rule keys.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
class PolicyError extends RedactionError {
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} message
|
|
30
|
+
* @param {object} [options]
|
|
31
|
+
*/
|
|
32
|
+
constructor(message, options) {
|
|
33
|
+
super(message, options);
|
|
34
|
+
this.code = 'POLICY_ERROR';
|
|
35
|
+
this.retriable = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
RedactionError,
|
|
41
|
+
PolicyError,
|
|
42
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ScreenshotUtilsError } = require('./base.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base for errors arising during DZI tile generation.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
class TileError extends ScreenshotUtilsError {
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} message
|
|
13
|
+
* @param {object} [options]
|
|
14
|
+
*/
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super(message, options);
|
|
17
|
+
this.code = 'TILE_ERROR';
|
|
18
|
+
this.retriable = false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `tileSize` is invalid (must be 256 or 512 per spec § 8.4.1).
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
class TileSizeError extends TileError {
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} message
|
|
30
|
+
* @param {object} [options]
|
|
31
|
+
*/
|
|
32
|
+
constructor(message, options) {
|
|
33
|
+
super(message, options);
|
|
34
|
+
this.code = 'TILE_SIZE';
|
|
35
|
+
this.retriable = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Writing tiles to the output directory failed (only in `output: 'directory'` mode).
|
|
41
|
+
* Retriable because the underlying cause is usually transient (disk full, permissions race).
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
class TileWriteError extends TileError {
|
|
46
|
+
/**
|
|
47
|
+
* @param {string} message
|
|
48
|
+
* @param {object} [options]
|
|
49
|
+
*/
|
|
50
|
+
constructor(message, options) {
|
|
51
|
+
super(message, options);
|
|
52
|
+
this.code = 'TILE_WRITE';
|
|
53
|
+
this.retriable = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = {
|
|
58
|
+
TileError,
|
|
59
|
+
TileSizeError,
|
|
60
|
+
TileWriteError,
|
|
61
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ScreenshotUtilsError } = require('./base.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base for errors arising during image-buffer transforms (crop, resize, convert, normalize).
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
class TransformError extends ScreenshotUtilsError {
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} message
|
|
13
|
+
* @param {object} [options]
|
|
14
|
+
*/
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super(message, options);
|
|
17
|
+
this.code = 'TRANSFORM_ERROR';
|
|
18
|
+
this.retriable = false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A rect is malformed or lies outside the source image bounds.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
class InvalidRectError extends TransformError {
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} message
|
|
30
|
+
* @param {object} [options]
|
|
31
|
+
*/
|
|
32
|
+
constructor(message, options) {
|
|
33
|
+
super(message, options);
|
|
34
|
+
this.code = 'INVALID_RECT';
|
|
35
|
+
this.retriable = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The requested output format is not supported (e.g., AVIF in v1.0).
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
class UnsupportedFormatError extends TransformError {
|
|
45
|
+
/**
|
|
46
|
+
* @param {string} message
|
|
47
|
+
* @param {object} [options]
|
|
48
|
+
*/
|
|
49
|
+
constructor(message, options) {
|
|
50
|
+
super(message, options);
|
|
51
|
+
this.code = 'UNSUPPORTED_FORMAT';
|
|
52
|
+
this.retriable = false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Sharp could not decode the input buffer (truncated, wrong format, corrupt).
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
class BufferCorruptError extends TransformError {
|
|
62
|
+
/**
|
|
63
|
+
* @param {string} message
|
|
64
|
+
* @param {object} [options]
|
|
65
|
+
*/
|
|
66
|
+
constructor(message, options) {
|
|
67
|
+
super(message, options);
|
|
68
|
+
this.code = 'BUFFER_CORRUPT';
|
|
69
|
+
this.retriable = false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = {
|
|
74
|
+
TransformError,
|
|
75
|
+
InvalidRectError,
|
|
76
|
+
UnsupportedFormatError,
|
|
77
|
+
BufferCorruptError,
|
|
78
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Public entrypoint for `@afixt/screenshot-utils`.
|
|
5
|
+
*
|
|
6
|
+
* This is the only semver-protected surface. Deep imports
|
|
7
|
+
* (e.g. `require('@afixt/screenshot-utils/src/...')`) are internal and
|
|
8
|
+
* may change without a major version bump.
|
|
9
|
+
*
|
|
10
|
+
* @module screenshot-utils
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const pkg = require('../package.json');
|
|
14
|
+
const errors = require('./errors/index.js');
|
|
15
|
+
const adapters = require('./adapters/index.js');
|
|
16
|
+
const capture = require('./capture/index.js');
|
|
17
|
+
const transform = require('./transform/index.js');
|
|
18
|
+
const tile = require('./tile/index.js');
|
|
19
|
+
const compose = require('./compose/index.js');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Library defaults. Per-call options shallow-merge over this object.
|
|
23
|
+
* Frozen — never mutate at runtime.
|
|
24
|
+
*
|
|
25
|
+
* Mirrors `spec.md` § 11.1 exactly.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
* @type {Readonly<import('./types/index.d.ts').ScreenshotUtilsDefaults>}
|
|
29
|
+
*/
|
|
30
|
+
const defaults = Object.freeze({
|
|
31
|
+
format: 'png',
|
|
32
|
+
quality: 90,
|
|
33
|
+
fullPage: true,
|
|
34
|
+
timeout: 30_000,
|
|
35
|
+
padding: 10,
|
|
36
|
+
stripHeight: null,
|
|
37
|
+
tileSize: 256,
|
|
38
|
+
tileOverlap: 1,
|
|
39
|
+
tileFormat: 'webp',
|
|
40
|
+
tileQuality: 80,
|
|
41
|
+
waitForStable: Object.freeze({
|
|
42
|
+
fonts: true,
|
|
43
|
+
images: true,
|
|
44
|
+
animations: 'reduce',
|
|
45
|
+
maxWait: 5000,
|
|
46
|
+
idleMs: 200,
|
|
47
|
+
}),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Resolved package version from package.json. Useful for diagnostic logging
|
|
52
|
+
* by consumers; never use for feature gating (consumers should pin the range
|
|
53
|
+
* they need via semver).
|
|
54
|
+
*
|
|
55
|
+
* @public
|
|
56
|
+
* @type {string}
|
|
57
|
+
*/
|
|
58
|
+
const version = pkg.version;
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
defaults,
|
|
62
|
+
version,
|
|
63
|
+
...errors,
|
|
64
|
+
...adapters,
|
|
65
|
+
...capture,
|
|
66
|
+
...transform,
|
|
67
|
+
...tile,
|
|
68
|
+
...compose,
|
|
69
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { PolicyError } = require('../errors/index.js');
|
|
4
|
+
const { redact } = require('./redact.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default PII policy bundled with the package. Consumers tighten it per
|
|
8
|
+
* their privacy posture; this is the conservative starting point per
|
|
9
|
+
* `spec.md` § 8.5.2.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
* @type {Readonly<import('../types/index.d.ts').PiiPolicy>}
|
|
13
|
+
*/
|
|
14
|
+
const defaultPiiPolicy = Object.freeze({
|
|
15
|
+
inputTypes: Object.freeze(['email', 'password', 'tel', 'ssn-pattern']),
|
|
16
|
+
customSelectors: Object.freeze(['[data-pii="true"]', '[data-sensitive]']),
|
|
17
|
+
mode: 'blur',
|
|
18
|
+
radius: 12,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Apply a PII policy to a screenshot using a pre-collected list of element
|
|
23
|
+
* rects + classification metadata.
|
|
24
|
+
*
|
|
25
|
+
* Implements `spec.md` § 8.5.2. The function does NOT inspect a DOM
|
|
26
|
+
* directly — callers run a page-context evaluator that produces the
|
|
27
|
+
* `regions` array (an array of `{ rect, classification? }` objects) and
|
|
28
|
+
* pass it here. This keeps the package DOM-agnostic.
|
|
29
|
+
*
|
|
30
|
+
* @public
|
|
31
|
+
* @param {Buffer} input
|
|
32
|
+
* @param {Array<{rect: import('../types/index.d.ts').Rect, classification?: string}>} regions
|
|
33
|
+
* @param {import('../types/index.d.ts').PiiPolicy} [policy]
|
|
34
|
+
* @returns {Promise<Buffer>}
|
|
35
|
+
*/
|
|
36
|
+
async function applyPiiPolicy(input, regions, policy = defaultPiiPolicy) {
|
|
37
|
+
if (!policy || typeof policy !== 'object') {
|
|
38
|
+
throw new PolicyError('policy must be an object', {
|
|
39
|
+
context: { received: typeof policy },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (typeof policy.mode !== 'string') {
|
|
43
|
+
throw new PolicyError('policy.mode is required', { context: { policy } });
|
|
44
|
+
}
|
|
45
|
+
if (!Array.isArray(regions)) {
|
|
46
|
+
throw new PolicyError('regions must be an array', {
|
|
47
|
+
context: { received: typeof regions },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const redactRegions = regions.map(r => ({
|
|
52
|
+
rect: r.rect,
|
|
53
|
+
mode: policy.mode,
|
|
54
|
+
...(policy.radius !== undefined && policy.mode === 'blur' ? { radius: policy.radius } : {}),
|
|
55
|
+
...(policy.cellSize !== undefined && policy.mode === 'pixelate'
|
|
56
|
+
? { cellSize: policy.cellSize }
|
|
57
|
+
: {}),
|
|
58
|
+
...(policy.color !== undefined && policy.mode === 'mask' ? { color: policy.color } : {}),
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
return redact(input, redactRegions, {
|
|
62
|
+
default: policy.mode,
|
|
63
|
+
defaultRadius: policy.radius ?? 8,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = { applyPiiPolicy, defaultPiiPolicy };
|