@lens-image/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +244 -0
- package/dist/cjs/adapters/memory.d.ts +55 -0
- package/dist/cjs/adapters/memory.d.ts.map +1 -0
- package/dist/cjs/adapters/memory.js +84 -0
- package/dist/cjs/adapters/memory.js.map +1 -0
- package/dist/cjs/browser.d.ts +46 -0
- package/dist/cjs/browser.d.ts.map +1 -0
- package/dist/cjs/browser.js +79 -0
- package/dist/cjs/browser.js.map +1 -0
- package/dist/cjs/bytes.d.ts +18 -0
- package/dist/cjs/bytes.d.ts.map +1 -0
- package/dist/cjs/bytes.js +31 -0
- package/dist/cjs/bytes.js.map +1 -0
- package/dist/cjs/cache.d.ts +43 -0
- package/dist/cjs/cache.d.ts.map +1 -0
- package/dist/cjs/cache.js +77 -0
- package/dist/cjs/cache.js.map +1 -0
- package/dist/cjs/concurrency.d.ts +35 -0
- package/dist/cjs/concurrency.d.ts.map +1 -0
- package/dist/cjs/concurrency.js +82 -0
- package/dist/cjs/concurrency.js.map +1 -0
- package/dist/cjs/engines/index.d.ts +20 -0
- package/dist/cjs/engines/index.d.ts.map +1 -0
- package/dist/cjs/engines/index.js +38 -0
- package/dist/cjs/engines/index.js.map +1 -0
- package/dist/cjs/engines/passthrough.d.ts +41 -0
- package/dist/cjs/engines/passthrough.d.ts.map +1 -0
- package/dist/cjs/engines/passthrough.js +66 -0
- package/dist/cjs/engines/passthrough.js.map +1 -0
- package/dist/cjs/engines/sharp.d.ts +58 -0
- package/dist/cjs/engines/sharp.d.ts.map +1 -0
- package/dist/cjs/engines/sharp.js +243 -0
- package/dist/cjs/engines/sharp.js.map +1 -0
- package/dist/cjs/errors.d.ts +90 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +97 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/format.d.ts +33 -0
- package/dist/cjs/format.d.ts.map +1 -0
- package/dist/cjs/format.js +102 -0
- package/dist/cjs/format.js.map +1 -0
- package/dist/cjs/hash.d.ts +19 -0
- package/dist/cjs/hash.d.ts.map +1 -0
- package/dist/cjs/hash.js +43 -0
- package/dist/cjs/hash.js.map +1 -0
- package/dist/cjs/index.d.ts +56 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +110 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/naming.d.ts +48 -0
- package/dist/cjs/naming.d.ts.map +1 -0
- package/dist/cjs/naming.js +95 -0
- package/dist/cjs/naming.js.map +1 -0
- package/dist/cjs/optimizer.d.ts +89 -0
- package/dist/cjs/optimizer.d.ts.map +1 -0
- package/dist/cjs/optimizer.js +667 -0
- package/dist/cjs/optimizer.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/retry.d.ts +55 -0
- package/dist/cjs/retry.d.ts.map +1 -0
- package/dist/cjs/retry.js +129 -0
- package/dist/cjs/retry.js.map +1 -0
- package/dist/cjs/server/handler.d.ts +80 -0
- package/dist/cjs/server/handler.d.ts.map +1 -0
- package/dist/cjs/server/handler.js +155 -0
- package/dist/cjs/server/handler.js.map +1 -0
- package/dist/cjs/sniff.d.ts +37 -0
- package/dist/cjs/sniff.d.ts.map +1 -0
- package/dist/cjs/sniff.js +442 -0
- package/dist/cjs/sniff.js.map +1 -0
- package/dist/cjs/source.d.ts +45 -0
- package/dist/cjs/source.d.ts.map +1 -0
- package/dist/cjs/source.js +221 -0
- package/dist/cjs/source.js.map +1 -0
- package/dist/cjs/srcset.d.ts +66 -0
- package/dist/cjs/srcset.d.ts.map +1 -0
- package/dist/cjs/srcset.js +81 -0
- package/dist/cjs/srcset.js.map +1 -0
- package/dist/cjs/types.d.ts +441 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +12 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/validation.d.ts +38 -0
- package/dist/cjs/validation.d.ts.map +1 -0
- package/dist/cjs/validation.js +79 -0
- package/dist/cjs/validation.js.map +1 -0
- package/dist/esm/adapters/memory.d.ts +55 -0
- package/dist/esm/adapters/memory.d.ts.map +1 -0
- package/dist/esm/adapters/memory.js +80 -0
- package/dist/esm/adapters/memory.js.map +1 -0
- package/dist/esm/browser.d.ts +46 -0
- package/dist/esm/browser.d.ts.map +1 -0
- package/dist/esm/browser.js +49 -0
- package/dist/esm/browser.js.map +1 -0
- package/dist/esm/bytes.d.ts +18 -0
- package/dist/esm/bytes.d.ts.map +1 -0
- package/dist/esm/bytes.js +28 -0
- package/dist/esm/bytes.js.map +1 -0
- package/dist/esm/cache.d.ts +43 -0
- package/dist/esm/cache.d.ts.map +1 -0
- package/dist/esm/cache.js +73 -0
- package/dist/esm/cache.js.map +1 -0
- package/dist/esm/concurrency.d.ts +35 -0
- package/dist/esm/concurrency.d.ts.map +1 -0
- package/dist/esm/concurrency.js +78 -0
- package/dist/esm/concurrency.js.map +1 -0
- package/dist/esm/engines/index.d.ts +20 -0
- package/dist/esm/engines/index.d.ts.map +1 -0
- package/dist/esm/engines/index.js +30 -0
- package/dist/esm/engines/index.js.map +1 -0
- package/dist/esm/engines/passthrough.d.ts +41 -0
- package/dist/esm/engines/passthrough.d.ts.map +1 -0
- package/dist/esm/engines/passthrough.js +63 -0
- package/dist/esm/engines/passthrough.js.map +1 -0
- package/dist/esm/engines/sharp.d.ts +58 -0
- package/dist/esm/engines/sharp.d.ts.map +1 -0
- package/dist/esm/engines/sharp.js +206 -0
- package/dist/esm/engines/sharp.js.map +1 -0
- package/dist/esm/errors.d.ts +90 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +91 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/format.d.ts +33 -0
- package/dist/esm/format.d.ts.map +1 -0
- package/dist/esm/format.js +93 -0
- package/dist/esm/format.js.map +1 -0
- package/dist/esm/hash.d.ts +19 -0
- package/dist/esm/hash.d.ts.map +1 -0
- package/dist/esm/hash.js +38 -0
- package/dist/esm/hash.js.map +1 -0
- package/dist/esm/index.d.ts +56 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +54 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/naming.d.ts +48 -0
- package/dist/esm/naming.d.ts.map +1 -0
- package/dist/esm/naming.js +88 -0
- package/dist/esm/naming.js.map +1 -0
- package/dist/esm/optimizer.d.ts +89 -0
- package/dist/esm/optimizer.d.ts.map +1 -0
- package/dist/esm/optimizer.js +663 -0
- package/dist/esm/optimizer.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/retry.d.ts +55 -0
- package/dist/esm/retry.d.ts.map +1 -0
- package/dist/esm/retry.js +123 -0
- package/dist/esm/retry.js.map +1 -0
- package/dist/esm/server/handler.d.ts +80 -0
- package/dist/esm/server/handler.d.ts.map +1 -0
- package/dist/esm/server/handler.js +151 -0
- package/dist/esm/server/handler.js.map +1 -0
- package/dist/esm/sniff.d.ts +37 -0
- package/dist/esm/sniff.d.ts.map +1 -0
- package/dist/esm/sniff.js +435 -0
- package/dist/esm/sniff.js.map +1 -0
- package/dist/esm/source.d.ts +45 -0
- package/dist/esm/source.d.ts.map +1 -0
- package/dist/esm/source.js +183 -0
- package/dist/esm/source.js.map +1 -0
- package/dist/esm/srcset.d.ts +66 -0
- package/dist/esm/srcset.d.ts.map +1 -0
- package/dist/esm/srcset.js +76 -0
- package/dist/esm/srcset.js.map +1 -0
- package/dist/esm/types.d.ts +441 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +11 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/validation.d.ts +38 -0
- package/dist/esm/validation.d.ts.map +1 -0
- package/dist/esm/validation.js +74 -0
- package/dist/esm/validation.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The sharp-backed {@link ImageEngine}.
|
|
4
|
+
*
|
|
5
|
+
* ### Why this is not a dependency
|
|
6
|
+
*
|
|
7
|
+
* `@lens-image/core` declares sharp as an *optional peer*. Nothing in this file is
|
|
8
|
+
* evaluated until you actually call the engine, and the import is dynamic, so
|
|
9
|
+
* `npm install @lens-image/core` pulls in zero packages and installs zero native
|
|
10
|
+
* binaries. If you never resize an image - you only validate and re-key, say -
|
|
11
|
+
* you never need sharp at all.
|
|
12
|
+
*
|
|
13
|
+
* The moment you do need it, you run `npm install sharp` yourself, which means
|
|
14
|
+
* the native binary, its platform matrix and its release cadence are all
|
|
15
|
+
* visible in *your* lockfile rather than smuggled in under ours.
|
|
16
|
+
*/
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.createSharpEngine = createSharpEngine;
|
|
52
|
+
exports.resetSharpCache = resetSharpCache;
|
|
53
|
+
const errors_js_1 = require("./../errors.js");
|
|
54
|
+
const format_js_1 = require("./../format.js");
|
|
55
|
+
/**
|
|
56
|
+
* Formats whose capability is reported under a different key.
|
|
57
|
+
*
|
|
58
|
+
* sharp reports support per *container*, and AVIF is not one of its containers:
|
|
59
|
+
* AVIF is HEIF with AV1 compression, so `sharp.format.avif` is `undefined` even
|
|
60
|
+
* on builds that encode AVIF perfectly well. Checking only the literal name
|
|
61
|
+
* makes every AVIF request degrade to JPEG for no reason - the exact failure
|
|
62
|
+
* the fallback exists to handle, triggered by a bug rather than a real
|
|
63
|
+
* limitation.
|
|
64
|
+
*
|
|
65
|
+
* The first entry that reports an encoder wins.
|
|
66
|
+
*/
|
|
67
|
+
const CAPABILITY_KEYS = {
|
|
68
|
+
avif: ['avif', 'heif'],
|
|
69
|
+
};
|
|
70
|
+
let cached;
|
|
71
|
+
/**
|
|
72
|
+
* Resolves sharp, memoising both success and failure.
|
|
73
|
+
*
|
|
74
|
+
* The error message is the one a developer will actually read when their
|
|
75
|
+
* deploy breaks, so it says what to install rather than echoing
|
|
76
|
+
* `ERR_MODULE_NOT_FOUND`.
|
|
77
|
+
*/
|
|
78
|
+
async function loadSharp() {
|
|
79
|
+
cached ??= (async () => {
|
|
80
|
+
try {
|
|
81
|
+
// The template literal defeats bundler static analysis, so tools like
|
|
82
|
+
// webpack and esbuild do not try to resolve sharp at build time in
|
|
83
|
+
// projects that never use it.
|
|
84
|
+
const specifier = 'sharp';
|
|
85
|
+
const mod = (await Promise.resolve(`${`${specifier}`}`).then(s => __importStar(require(s))));
|
|
86
|
+
return ('default' in mod ? mod.default : mod);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw new errors_js_1.LensError('ENGINE_UNAVAILABLE', 'Image processing needs sharp, which is not installed. Run `npm install sharp`. ' +
|
|
90
|
+
'It is an optional peer dependency of @lens-image/core so that installing the core ' +
|
|
91
|
+
'library never pulls in a native binary you might not need.', { cause: error, details: { engine: 'sharp' } });
|
|
92
|
+
}
|
|
93
|
+
})();
|
|
94
|
+
return cached;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Creates an {@link ImageEngine} backed by sharp.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* const optimizer = new ImageOptimizer({
|
|
102
|
+
* engine: createSharpEngine({ threads: 1 }), // we do our own parallelism
|
|
103
|
+
* adapter,
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
function createSharpEngine(options = {}) {
|
|
108
|
+
const { cache = false, threads, pixelLimit = 100_000_000, animated = false } = options;
|
|
109
|
+
let configured = false;
|
|
110
|
+
async function sharp() {
|
|
111
|
+
const mod = await loadSharp();
|
|
112
|
+
if (!configured) {
|
|
113
|
+
configured = true;
|
|
114
|
+
mod.cache?.(cache);
|
|
115
|
+
if (threads !== undefined)
|
|
116
|
+
mod.concurrency?.(threads);
|
|
117
|
+
}
|
|
118
|
+
return mod;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
name: 'sharp',
|
|
122
|
+
async supports(format) {
|
|
123
|
+
try {
|
|
124
|
+
const mod = await sharp();
|
|
125
|
+
// Capability depends on how libvips was built - AVIF in particular is
|
|
126
|
+
// missing from some prebuilt binaries - so this asks sharp rather than
|
|
127
|
+
// assuming. See CAPABILITY_KEYS for why the name is not always literal.
|
|
128
|
+
const keys = CAPABILITY_KEYS[format] ?? [format];
|
|
129
|
+
return keys.some((key) => Boolean(mod.format[key]?.output));
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
async probe(input) {
|
|
136
|
+
const mod = await sharp();
|
|
137
|
+
try {
|
|
138
|
+
const meta = (await mod(input, { limitInputPixels: pixelLimit }).metadata());
|
|
139
|
+
return {
|
|
140
|
+
format: meta.format ?? 'unknown',
|
|
141
|
+
width: meta.width ?? 0,
|
|
142
|
+
height: meta.height ?? 0,
|
|
143
|
+
size: meta.size ?? input.byteLength,
|
|
144
|
+
hasAlpha: meta.hasAlpha ?? false,
|
|
145
|
+
isAnimated: (meta.pages ?? 1) > 1,
|
|
146
|
+
...(meta.orientation !== undefined ? { orientation: meta.orientation } : {}),
|
|
147
|
+
...(meta.space !== undefined ? { space: meta.space } : {}),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw (0, errors_js_1.wrapError)('UNSUPPORTED_INPUT', 'sharp could not read this image', error, {
|
|
152
|
+
engine: 'sharp',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
async transform(input, op) {
|
|
157
|
+
const mod = await sharp();
|
|
158
|
+
try {
|
|
159
|
+
let pipeline = mod(input, { limitInputPixels: pixelLimit, animated });
|
|
160
|
+
// Auto-orient first: rotating after a resize would resize against the
|
|
161
|
+
// wrong axis for any photo shot in portrait on a phone.
|
|
162
|
+
if (op.autoOrient)
|
|
163
|
+
pipeline = pipeline.rotate();
|
|
164
|
+
if (op.resize) {
|
|
165
|
+
pipeline = pipeline.resize({
|
|
166
|
+
...(op.resize.width !== undefined ? { width: op.resize.width } : {}),
|
|
167
|
+
...(op.resize.height !== undefined ? { height: op.resize.height } : {}),
|
|
168
|
+
fit: op.resize.fit ?? 'cover',
|
|
169
|
+
position: op.resize.position ?? 'center',
|
|
170
|
+
withoutEnlargement: op.resize.withoutEnlargement ?? true,
|
|
171
|
+
...(op.resize.background ? { background: op.resize.background } : {}),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
pipeline = pipeline.toFormat(op.format, encoderOptions(op));
|
|
175
|
+
// sharp strips metadata unless asked; `withMetadata()` keeps EXIF/ICC.
|
|
176
|
+
if (op.preserveMetadata)
|
|
177
|
+
pipeline = pipeline.withMetadata();
|
|
178
|
+
const { data, info } = await pipeline.toBuffer({ resolveWithObject: true });
|
|
179
|
+
return {
|
|
180
|
+
data,
|
|
181
|
+
format: op.format,
|
|
182
|
+
width: info.width,
|
|
183
|
+
height: info.height,
|
|
184
|
+
size: info.size ?? data.byteLength,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
throw (0, errors_js_1.wrapError)('ENCODE_FAILED', `sharp failed to encode ${op.format}`, error, { engine: 'sharp', format: op.format });
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/** Maps a {@link TransformOp} onto sharp's per-format encoder options. */
|
|
194
|
+
function encoderOptions(op) {
|
|
195
|
+
const effort = op.effort ?? (0, format_js_1.defaultEffort)(op.format);
|
|
196
|
+
const base = { quality: op.quality };
|
|
197
|
+
switch (op.format) {
|
|
198
|
+
case 'jpeg':
|
|
199
|
+
return {
|
|
200
|
+
...base,
|
|
201
|
+
progressive: op.progressive ?? true,
|
|
202
|
+
// 4:4:4 avoids the colour smearing that 4:2:0 causes on saturated reds
|
|
203
|
+
// and fine text, which is exactly what high-quality output is for.
|
|
204
|
+
chromaSubsampling: op.chromaSubsampling ?? (op.quality >= 90 ? '4:4:4' : '4:2:0'),
|
|
205
|
+
mozjpeg: true,
|
|
206
|
+
};
|
|
207
|
+
case 'png':
|
|
208
|
+
return {
|
|
209
|
+
progressive: op.progressive ?? false,
|
|
210
|
+
compressionLevel: 9,
|
|
211
|
+
// Palette quantisation is where PNG size actually comes from; without
|
|
212
|
+
// it `quality` is ignored entirely and output is often larger than input.
|
|
213
|
+
palette: true,
|
|
214
|
+
quality: op.quality,
|
|
215
|
+
effort: effort ?? 7,
|
|
216
|
+
};
|
|
217
|
+
case 'webp':
|
|
218
|
+
return {
|
|
219
|
+
...base,
|
|
220
|
+
...(op.lossless !== undefined ? { lossless: op.lossless } : {}),
|
|
221
|
+
...(effort !== undefined ? { effort } : {}),
|
|
222
|
+
smartSubsample: true,
|
|
223
|
+
};
|
|
224
|
+
case 'avif':
|
|
225
|
+
return {
|
|
226
|
+
...base,
|
|
227
|
+
...(op.lossless !== undefined ? { lossless: op.lossless } : {}),
|
|
228
|
+
...(effort !== undefined ? { effort } : {}),
|
|
229
|
+
chromaSubsampling: op.chromaSubsampling ?? '4:4:4',
|
|
230
|
+
};
|
|
231
|
+
case 'gif':
|
|
232
|
+
return { ...(effort !== undefined ? { effort } : {}) };
|
|
233
|
+
case 'tiff':
|
|
234
|
+
return { ...base, compression: 'lzw' };
|
|
235
|
+
default:
|
|
236
|
+
return base;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/** Test seam: forget the memoised sharp module. */
|
|
240
|
+
function resetSharpCache() {
|
|
241
|
+
cached = undefined;
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=sharp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sharp.js","sourceRoot":"","sources":["../../../src/engines/sharp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error taxonomy.
|
|
3
|
+
*
|
|
4
|
+
* Every error Lens throws is a {@link LensError} with a stable `code`, so you
|
|
5
|
+
* can branch on failure without string-matching messages. Messages are written
|
|
6
|
+
* for the developer reading a stack trace at 2am: they say what was expected,
|
|
7
|
+
* what happened, and what to do about it.
|
|
8
|
+
*/
|
|
9
|
+
import type { DetectedFormat, ImageFormat } from './types.js';
|
|
10
|
+
/** Stable, machine-readable failure codes. */
|
|
11
|
+
export type LensErrorCode =
|
|
12
|
+
/** The `source` value was not a shape Lens understands. */
|
|
13
|
+
'INVALID_SOURCE'
|
|
14
|
+
/** The file could not be read from disk or the network. */
|
|
15
|
+
| 'SOURCE_UNREADABLE'
|
|
16
|
+
/** Bytes were read but are not a recognisable image. */
|
|
17
|
+
| 'UNSUPPORTED_INPUT'
|
|
18
|
+
/** Input failed a `validate` rule (size, dimensions, format allowlist). */
|
|
19
|
+
| 'VALIDATION_FAILED'
|
|
20
|
+
/** No codec is available to do the work. Usually: sharp is not installed. */
|
|
21
|
+
| 'ENGINE_UNAVAILABLE'
|
|
22
|
+
/** The codec threw while encoding. */
|
|
23
|
+
| 'ENCODE_FAILED'
|
|
24
|
+
/** Every requested format failed, including the fallback. */
|
|
25
|
+
| 'ALL_FORMATS_FAILED'
|
|
26
|
+
/** The storage adapter threw, after exhausting retries. */
|
|
27
|
+
| 'UPLOAD_FAILED'
|
|
28
|
+
/** An adapter was required for the operation but none was configured. */
|
|
29
|
+
| 'ADAPTER_REQUIRED'
|
|
30
|
+
/** The adapter does not implement an optional method this call needed. */
|
|
31
|
+
| 'ADAPTER_UNSUPPORTED'
|
|
32
|
+
/** Adapter constructor received bad or missing configuration. */
|
|
33
|
+
| 'ADAPTER_MISCONFIGURED'
|
|
34
|
+
/** The caller's `AbortSignal` fired. */
|
|
35
|
+
| 'ABORTED'
|
|
36
|
+
/** Option values were contradictory or out of range. */
|
|
37
|
+
| 'INVALID_OPTIONS';
|
|
38
|
+
/** Extra context carried on a {@link LensError}. */
|
|
39
|
+
export interface LensErrorDetails {
|
|
40
|
+
readonly format?: ImageFormat;
|
|
41
|
+
readonly detected?: DetectedFormat;
|
|
42
|
+
readonly key?: string;
|
|
43
|
+
readonly adapter?: string;
|
|
44
|
+
readonly engine?: string;
|
|
45
|
+
readonly limit?: number;
|
|
46
|
+
readonly actual?: number;
|
|
47
|
+
readonly attempts?: number;
|
|
48
|
+
readonly [key: string]: unknown;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Base error for everything this library throws.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* try {
|
|
56
|
+
* await optimizer.optimize({ source: buf });
|
|
57
|
+
* } catch (err) {
|
|
58
|
+
* if (LensError.is(err, 'VALIDATION_FAILED')) return res.status(400).json({ error: err.message });
|
|
59
|
+
* throw err;
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare class LensError extends Error {
|
|
64
|
+
/** Stable failure code. Branch on this, not on `message`. */
|
|
65
|
+
readonly code: LensErrorCode;
|
|
66
|
+
/** Structured context: limits, keys, formats involved. */
|
|
67
|
+
readonly details: LensErrorDetails;
|
|
68
|
+
/** A suggested HTTP status, so route handlers do not have to map codes. */
|
|
69
|
+
readonly status: number;
|
|
70
|
+
constructor(code: LensErrorCode, message: string, options?: {
|
|
71
|
+
cause?: unknown;
|
|
72
|
+
details?: LensErrorDetails;
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Type guard. Pass a `code` to narrow further.
|
|
76
|
+
*
|
|
77
|
+
* @example `if (LensError.is(err, 'UPLOAD_FAILED')) ...`
|
|
78
|
+
*/
|
|
79
|
+
static is(error: unknown, code?: LensErrorCode): error is LensError;
|
|
80
|
+
/** JSON-safe representation, suitable for logs and API responses. */
|
|
81
|
+
toJSON(): Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
/** Throws `ABORTED` if the signal has already fired. Cheap enough to call often. */
|
|
84
|
+
export declare function throwIfAborted(signal: AbortSignal | undefined, what?: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* Wraps a non-Lens error, preserving the original as `cause`.
|
|
87
|
+
* Existing {@link LensError}s pass through untouched so codes are not lost.
|
|
88
|
+
*/
|
|
89
|
+
export declare function wrapError(code: LensErrorCode, message: string, cause: unknown, details?: LensErrorDetails): LensError;
|
|
90
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9D,8CAA8C;AAC9C,MAAM,MAAM,aAAa;AACvB,2DAA2D;AACzD,gBAAgB;AAClB,2DAA2D;GACzD,mBAAmB;AACrB,wDAAwD;GACtD,mBAAmB;AACrB,2EAA2E;GACzE,mBAAmB;AACrB,6EAA6E;GAC3E,oBAAoB;AACtB,sCAAsC;GACpC,eAAe;AACjB,6DAA6D;GAC3D,oBAAoB;AACtB,2DAA2D;GACzD,eAAe;AACjB,yEAAyE;GACvE,kBAAkB;AACpB,0EAA0E;GACxE,qBAAqB;AACvB,iEAAiE;GAC/D,uBAAuB;AACzB,wCAAwC;GACtC,SAAS;AACX,wDAAwD;GACtD,iBAAiB,CAAC;AAEtB,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAE7B,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IAEnC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGtB,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;KAAO;IAU/D;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,KAAK,IAAI,SAAS;IAKnE,qEAAqE;IACrE,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CASlC;AAkBD,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,SAAc,GAAG,IAAI,CAMxF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,gBAAgB,GACzB,SAAS,CAIX"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Error taxonomy.
|
|
4
|
+
*
|
|
5
|
+
* Every error Lens throws is a {@link LensError} with a stable `code`, so you
|
|
6
|
+
* can branch on failure without string-matching messages. Messages are written
|
|
7
|
+
* for the developer reading a stack trace at 2am: they say what was expected,
|
|
8
|
+
* what happened, and what to do about it.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.LensError = void 0;
|
|
12
|
+
exports.throwIfAborted = throwIfAborted;
|
|
13
|
+
exports.wrapError = wrapError;
|
|
14
|
+
/**
|
|
15
|
+
* Base error for everything this library throws.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* try {
|
|
20
|
+
* await optimizer.optimize({ source: buf });
|
|
21
|
+
* } catch (err) {
|
|
22
|
+
* if (LensError.is(err, 'VALIDATION_FAILED')) return res.status(400).json({ error: err.message });
|
|
23
|
+
* throw err;
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
class LensError extends Error {
|
|
28
|
+
/** Stable failure code. Branch on this, not on `message`. */
|
|
29
|
+
code;
|
|
30
|
+
/** Structured context: limits, keys, formats involved. */
|
|
31
|
+
details;
|
|
32
|
+
/** A suggested HTTP status, so route handlers do not have to map codes. */
|
|
33
|
+
status;
|
|
34
|
+
constructor(code, message, options = {}) {
|
|
35
|
+
super(message, options.cause !== undefined ? { cause: options.cause } : undefined);
|
|
36
|
+
this.name = 'LensError';
|
|
37
|
+
this.code = code;
|
|
38
|
+
this.details = options.details ?? {};
|
|
39
|
+
this.status = STATUS_BY_CODE[code] ?? 500;
|
|
40
|
+
Error.captureStackTrace?.(this, LensError);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Type guard. Pass a `code` to narrow further.
|
|
44
|
+
*
|
|
45
|
+
* @example `if (LensError.is(err, 'UPLOAD_FAILED')) ...`
|
|
46
|
+
*/
|
|
47
|
+
static is(error, code) {
|
|
48
|
+
if (!(error instanceof LensError))
|
|
49
|
+
return false;
|
|
50
|
+
return code === undefined || error.code === code;
|
|
51
|
+
}
|
|
52
|
+
/** JSON-safe representation, suitable for logs and API responses. */
|
|
53
|
+
toJSON() {
|
|
54
|
+
return {
|
|
55
|
+
name: this.name,
|
|
56
|
+
code: this.code,
|
|
57
|
+
message: this.message,
|
|
58
|
+
status: this.status,
|
|
59
|
+
details: this.details,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.LensError = LensError;
|
|
64
|
+
const STATUS_BY_CODE = {
|
|
65
|
+
INVALID_SOURCE: 400,
|
|
66
|
+
SOURCE_UNREADABLE: 400,
|
|
67
|
+
UNSUPPORTED_INPUT: 415,
|
|
68
|
+
VALIDATION_FAILED: 422,
|
|
69
|
+
INVALID_OPTIONS: 400,
|
|
70
|
+
ABORTED: 499,
|
|
71
|
+
ENGINE_UNAVAILABLE: 500,
|
|
72
|
+
ENCODE_FAILED: 500,
|
|
73
|
+
ALL_FORMATS_FAILED: 500,
|
|
74
|
+
UPLOAD_FAILED: 502,
|
|
75
|
+
ADAPTER_REQUIRED: 500,
|
|
76
|
+
ADAPTER_UNSUPPORTED: 501,
|
|
77
|
+
ADAPTER_MISCONFIGURED: 500,
|
|
78
|
+
};
|
|
79
|
+
/** Throws `ABORTED` if the signal has already fired. Cheap enough to call often. */
|
|
80
|
+
function throwIfAborted(signal, what = 'operation') {
|
|
81
|
+
if (signal?.aborted) {
|
|
82
|
+
throw new LensError('ABORTED', `Lens ${what} was aborted by the caller's AbortSignal.`, {
|
|
83
|
+
cause: signal.reason,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Wraps a non-Lens error, preserving the original as `cause`.
|
|
89
|
+
* Existing {@link LensError}s pass through untouched so codes are not lost.
|
|
90
|
+
*/
|
|
91
|
+
function wrapError(code, message, cause, details) {
|
|
92
|
+
if (LensError.is(cause))
|
|
93
|
+
return cause;
|
|
94
|
+
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
95
|
+
return new LensError(code, `${message} (${reason})`, { cause, details });
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAyHH,wCAMC;AAMD,8BASC;AAhGD;;;;;;;;;;;;GAYG;AACH,MAAa,SAAU,SAAQ,KAAK;IAClC,6DAA6D;IACpD,IAAI,CAAgB;IAE7B,0DAA0D;IACjD,OAAO,CAAmB;IAEnC,2EAA2E;IAClE,MAAM,CAAS;IAExB,YACE,IAAmB,EACnB,OAAe,EACf,UAA2D,EAAE;QAE7D,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;QAC1C,KAAK,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,KAAc,EAAE,IAAoB;QAC5C,IAAI,CAAC,CAAC,KAAK,YAAY,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QAChD,OAAO,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;IACnD,CAAC;IAED,qEAAqE;IACrE,MAAM;QACJ,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;CACF;AA3CD,8BA2CC;AAED,MAAM,cAAc,GAA2C;IAC7D,cAAc,EAAE,GAAG;IACnB,iBAAiB,EAAE,GAAG;IACtB,iBAAiB,EAAE,GAAG;IACtB,iBAAiB,EAAE,GAAG;IACtB,eAAe,EAAE,GAAG;IACpB,OAAO,EAAE,GAAG;IACZ,kBAAkB,EAAE,GAAG;IACvB,aAAa,EAAE,GAAG;IAClB,kBAAkB,EAAE,GAAG;IACvB,aAAa,EAAE,GAAG;IAClB,gBAAgB,EAAE,GAAG;IACrB,mBAAmB,EAAE,GAAG;IACxB,qBAAqB,EAAE,GAAG;CAC3B,CAAC;AAEF,oFAAoF;AACpF,SAAgB,cAAc,CAAC,MAA+B,EAAE,IAAI,GAAG,WAAW;IAChF,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,SAAS,CAAC,SAAS,EAAE,QAAQ,IAAI,2CAA2C,EAAE;YACtF,KAAK,EAAE,MAAM,CAAC,MAAM;SACrB,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,SAAS,CACvB,IAAmB,EACnB,OAAe,EACf,KAAc,EACd,OAA0B;IAE1B,IAAI,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtE,OAAO,IAAI,SAAS,CAAC,IAAI,EAAE,GAAG,OAAO,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Format normalisation and per-format encoding defaults. */
|
|
2
|
+
import type { ImageFormat, ImageFormatInput } from './types.js';
|
|
3
|
+
/** Every format Lens can encode to. */
|
|
4
|
+
export declare const ENCODABLE_FORMATS: readonly ImageFormat[];
|
|
5
|
+
/**
|
|
6
|
+
* Maps a user-supplied format name onto its canonical form.
|
|
7
|
+
*
|
|
8
|
+
* `'jpg'` and `'JPEG'` both become `'jpeg'` so results are keyed consistently
|
|
9
|
+
* no matter how the caller spelled it.
|
|
10
|
+
*
|
|
11
|
+
* @throws {LensError} `INVALID_OPTIONS` for an unknown name.
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizeFormat(input: ImageFormatInput | string): ImageFormat;
|
|
14
|
+
/** Normalises a list, dropping duplicates while preserving the caller's order. */
|
|
15
|
+
export declare function normalizeFormats(inputs: readonly (ImageFormatInput | string)[]): readonly ImageFormat[];
|
|
16
|
+
/** True when the format stores an alpha channel. */
|
|
17
|
+
export declare function supportsAlpha(format: ImageFormat): boolean;
|
|
18
|
+
/** True when `quality` has any effect on the encode. */
|
|
19
|
+
export declare function isLossy(format: ImageFormat): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Sensible per-format encoder defaults.
|
|
22
|
+
*
|
|
23
|
+
* AVIF gets a lower quality number than JPEG on purpose: the scales are not
|
|
24
|
+
* comparable, and AVIF at q80 is wastefully large for the same perceived
|
|
25
|
+
* result. Callers who pass an explicit quality always win over this.
|
|
26
|
+
*/
|
|
27
|
+
export declare function defaultQuality(format: ImageFormat): number;
|
|
28
|
+
/**
|
|
29
|
+
* Default encoder effort. AVIF is slow enough that the top setting is a
|
|
30
|
+
* production hazard, so we sit mid-scale.
|
|
31
|
+
*/
|
|
32
|
+
export declare function defaultEffort(format: ImageFormat): number | undefined;
|
|
33
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/format.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAG7D,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAchE,uCAAuC;AACvC,eAAO,MAAM,iBAAiB,EAAE,SAAS,WAAW,EAOnD,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,GAAG,WAAW,CAW7E;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,CAAC,gBAAgB,GAAG,MAAM,CAAC,EAAE,GAC7C,SAAS,WAAW,EAAE,CAWxB;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAE1D;AAED,wDAAwD;AACxD,wBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAW1D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CASrE"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Format normalisation and per-format encoding defaults. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ENCODABLE_FORMATS = void 0;
|
|
5
|
+
exports.normalizeFormat = normalizeFormat;
|
|
6
|
+
exports.normalizeFormats = normalizeFormats;
|
|
7
|
+
exports.supportsAlpha = supportsAlpha;
|
|
8
|
+
exports.isLossy = isLossy;
|
|
9
|
+
exports.defaultQuality = defaultQuality;
|
|
10
|
+
exports.defaultEffort = defaultEffort;
|
|
11
|
+
const errors_js_1 = require("./errors.js");
|
|
12
|
+
const ALIASES = {
|
|
13
|
+
jpg: 'jpeg',
|
|
14
|
+
jpeg: 'jpeg',
|
|
15
|
+
jpe: 'jpeg',
|
|
16
|
+
png: 'png',
|
|
17
|
+
webp: 'webp',
|
|
18
|
+
avif: 'avif',
|
|
19
|
+
gif: 'gif',
|
|
20
|
+
tif: 'tiff',
|
|
21
|
+
tiff: 'tiff',
|
|
22
|
+
};
|
|
23
|
+
/** Every format Lens can encode to. */
|
|
24
|
+
exports.ENCODABLE_FORMATS = [
|
|
25
|
+
'jpeg',
|
|
26
|
+
'png',
|
|
27
|
+
'webp',
|
|
28
|
+
'avif',
|
|
29
|
+
'gif',
|
|
30
|
+
'tiff',
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Maps a user-supplied format name onto its canonical form.
|
|
34
|
+
*
|
|
35
|
+
* `'jpg'` and `'JPEG'` both become `'jpeg'` so results are keyed consistently
|
|
36
|
+
* no matter how the caller spelled it.
|
|
37
|
+
*
|
|
38
|
+
* @throws {LensError} `INVALID_OPTIONS` for an unknown name.
|
|
39
|
+
*/
|
|
40
|
+
function normalizeFormat(input) {
|
|
41
|
+
const key = String(input).trim().toLowerCase().replace(/^\./, '');
|
|
42
|
+
const format = ALIASES[key];
|
|
43
|
+
if (!format) {
|
|
44
|
+
throw new errors_js_1.LensError('INVALID_OPTIONS', `Unknown output format "${input}". Supported: ${exports.ENCODABLE_FORMATS.join(', ')} (and the alias "jpg").`, { details: { actual: input } });
|
|
45
|
+
}
|
|
46
|
+
return format;
|
|
47
|
+
}
|
|
48
|
+
/** Normalises a list, dropping duplicates while preserving the caller's order. */
|
|
49
|
+
function normalizeFormats(inputs) {
|
|
50
|
+
const seen = new Set();
|
|
51
|
+
const out = [];
|
|
52
|
+
for (const input of inputs) {
|
|
53
|
+
const format = normalizeFormat(input);
|
|
54
|
+
if (!seen.has(format)) {
|
|
55
|
+
seen.add(format);
|
|
56
|
+
out.push(format);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** True when the format stores an alpha channel. */
|
|
62
|
+
function supportsAlpha(format) {
|
|
63
|
+
return format !== 'jpeg';
|
|
64
|
+
}
|
|
65
|
+
/** True when `quality` has any effect on the encode. */
|
|
66
|
+
function isLossy(format) {
|
|
67
|
+
return format === 'jpeg' || format === 'webp' || format === 'avif';
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Sensible per-format encoder defaults.
|
|
71
|
+
*
|
|
72
|
+
* AVIF gets a lower quality number than JPEG on purpose: the scales are not
|
|
73
|
+
* comparable, and AVIF at q80 is wastefully large for the same perceived
|
|
74
|
+
* result. Callers who pass an explicit quality always win over this.
|
|
75
|
+
*/
|
|
76
|
+
function defaultQuality(format) {
|
|
77
|
+
switch (format) {
|
|
78
|
+
case 'avif':
|
|
79
|
+
return 60;
|
|
80
|
+
case 'webp':
|
|
81
|
+
return 80;
|
|
82
|
+
case 'jpeg':
|
|
83
|
+
return 82;
|
|
84
|
+
default:
|
|
85
|
+
return 80;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Default encoder effort. AVIF is slow enough that the top setting is a
|
|
90
|
+
* production hazard, so we sit mid-scale.
|
|
91
|
+
*/
|
|
92
|
+
function defaultEffort(format) {
|
|
93
|
+
switch (format) {
|
|
94
|
+
case 'avif':
|
|
95
|
+
return 4;
|
|
96
|
+
case 'webp':
|
|
97
|
+
return 4;
|
|
98
|
+
default:
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/format.ts"],"names":[],"mappings":";AAAA,6DAA6D;;;AAmC7D,0CAWC;AAGD,4CAaC;AAGD,sCAEC;AAGD,0BAEC;AASD,wCAWC;AAMD,sCASC;AAzGD,2CAAwC;AAGxC,MAAM,OAAO,GAAgC;IAC3C,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,uCAAuC;AAC1B,QAAA,iBAAiB,GAA2B;IACvD,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;CACP,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,eAAe,CAAC,KAAgC;IAC9D,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,qBAAS,CACjB,iBAAiB,EACjB,0BAA0B,KAAK,iBAAiB,yBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB,EACrG,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,KAA0B,EAAE,EAAE,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kFAAkF;AAClF,SAAgB,gBAAgB,CAC9B,MAA8C;IAE9C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAe,CAAC;IACpC,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACjB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,oDAAoD;AACpD,SAAgB,aAAa,CAAC,MAAmB;IAC/C,OAAO,MAAM,KAAK,MAAM,CAAC;AAC3B,CAAC;AAED,wDAAwD;AACxD,SAAgB,OAAO,CAAC,MAAmB;IACzC,OAAO,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,MAAM,CAAC;AACrE,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,MAAmB;IAChD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,EAAE,CAAC;QACZ;YACE,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa,CAAC,MAAmB;IAC/C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,CAAC,CAAC;QACX,KAAK,MAAM;YACT,OAAO,CAAC,CAAC;QACX;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Content hashing, via `node:crypto`. Used for cache keys, ETags and filenames. */
|
|
2
|
+
/** Full lowercase hex SHA-256 of some bytes. */
|
|
3
|
+
export declare function sha256(data: Uint8Array): string;
|
|
4
|
+
/**
|
|
5
|
+
* Short hash for use in URLs and filenames.
|
|
6
|
+
*
|
|
7
|
+
* 10 hex characters is 40 bits. For content-addressed asset names that is a
|
|
8
|
+
* ~1-in-a-million collision chance at a million distinct images, which is the
|
|
9
|
+
* same trade-off webpack and friends make for chunk hashes.
|
|
10
|
+
*/
|
|
11
|
+
export declare function shortHash(data: Uint8Array | string, length?: number): string;
|
|
12
|
+
/**
|
|
13
|
+
* Stable hash of an arbitrary options object.
|
|
14
|
+
*
|
|
15
|
+
* Object keys are sorted so `{ a, b }` and `{ b, a }` produce the same cache
|
|
16
|
+
* key - otherwise property order would silently fragment the cache.
|
|
17
|
+
*/
|
|
18
|
+
export declare function hashOptions(value: unknown): string;
|
|
19
|
+
//# sourceMappingURL=hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/hash.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAIpF,gDAAgD;AAChD,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAGxE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAElD"}
|
package/dist/cjs/hash.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Content hashing, via `node:crypto`. Used for cache keys, ETags and filenames. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.sha256 = sha256;
|
|
5
|
+
exports.shortHash = shortHash;
|
|
6
|
+
exports.hashOptions = hashOptions;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
/** Full lowercase hex SHA-256 of some bytes. */
|
|
9
|
+
function sha256(data) {
|
|
10
|
+
return (0, node_crypto_1.createHash)('sha256').update(data).digest('hex');
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Short hash for use in URLs and filenames.
|
|
14
|
+
*
|
|
15
|
+
* 10 hex characters is 40 bits. For content-addressed asset names that is a
|
|
16
|
+
* ~1-in-a-million collision chance at a million distinct images, which is the
|
|
17
|
+
* same trade-off webpack and friends make for chunk hashes.
|
|
18
|
+
*/
|
|
19
|
+
function shortHash(data, length = 10) {
|
|
20
|
+
const hash = typeof data === 'string' ? (0, node_crypto_1.createHash)('sha256').update(data).digest('hex') : sha256(data);
|
|
21
|
+
return hash.slice(0, length);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Stable hash of an arbitrary options object.
|
|
25
|
+
*
|
|
26
|
+
* Object keys are sorted so `{ a, b }` and `{ b, a }` produce the same cache
|
|
27
|
+
* key - otherwise property order would silently fragment the cache.
|
|
28
|
+
*/
|
|
29
|
+
function hashOptions(value) {
|
|
30
|
+
return (0, node_crypto_1.createHash)('sha256').update(stableStringify(value)).digest('hex').slice(0, 16);
|
|
31
|
+
}
|
|
32
|
+
function stableStringify(value) {
|
|
33
|
+
if (value === null || typeof value !== 'object')
|
|
34
|
+
return JSON.stringify(value) ?? 'null';
|
|
35
|
+
if (Array.isArray(value))
|
|
36
|
+
return `[${value.map(stableStringify).join(',')}]`;
|
|
37
|
+
const entries = Object.entries(value)
|
|
38
|
+
.filter(([, v]) => v !== undefined)
|
|
39
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
40
|
+
.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`);
|
|
41
|
+
return `{${entries.join(',')}}`;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=hash.js.map
|