@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,441 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public type surface of `@lens-image/core`.
|
|
3
|
+
*
|
|
4
|
+
* Everything in this file is an interface or a plain data shape - there is no
|
|
5
|
+
* runtime code here, so adapter and engine authors can depend on these types
|
|
6
|
+
* without pulling in any of the implementation.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Canonical image formats Lens understands.
|
|
12
|
+
*
|
|
13
|
+
* Note that `jpg` is not a member: it is accepted everywhere as an *input*
|
|
14
|
+
* alias and normalised to `jpeg`. Results are always keyed by the canonical
|
|
15
|
+
* name so `result.formats.jpeg` is the only place you have to look.
|
|
16
|
+
*
|
|
17
|
+
* @see {@link normalizeFormat}
|
|
18
|
+
*/
|
|
19
|
+
export type ImageFormat = 'jpeg' | 'png' | 'webp' | 'avif' | 'gif' | 'tiff';
|
|
20
|
+
/** Anything accepted where a {@link ImageFormat} is expected. */
|
|
21
|
+
export type ImageFormatInput = ImageFormat | 'jpg' | 'tif';
|
|
22
|
+
/**
|
|
23
|
+
* Formats Lens can detect but never encodes to. Useful for validation
|
|
24
|
+
* (`allowedFormats`) and for reporting what was actually uploaded.
|
|
25
|
+
*/
|
|
26
|
+
export type DetectedFormat = ImageFormat | 'svg' | 'bmp' | 'ico' | 'heic' | 'unknown';
|
|
27
|
+
/**
|
|
28
|
+
* Anything you can hand to {@link ImageOptimizer.optimize} as `source`.
|
|
29
|
+
*
|
|
30
|
+
* - `string` - an absolute or relative filesystem path.
|
|
31
|
+
* - `Uint8Array` / `Buffer` - raw bytes already in memory.
|
|
32
|
+
* - `URL` - a `file:` URL, or an `http(s):` URL when `allowRemote` is enabled.
|
|
33
|
+
* - `AsyncIterable<Uint8Array>` - a Node stream, a web stream, a multipart part.
|
|
34
|
+
* - `{ data, filename }` - bytes plus the original filename, which is used for
|
|
35
|
+
* output naming when it would otherwise be a content hash.
|
|
36
|
+
*/
|
|
37
|
+
export type ImageSource = string | URL | Uint8Array | AsyncIterable<Uint8Array> | {
|
|
38
|
+
data: Uint8Array | AsyncIterable<Uint8Array>;
|
|
39
|
+
filename?: string;
|
|
40
|
+
contentType?: string;
|
|
41
|
+
};
|
|
42
|
+
/** What Lens knows about an image before it touches a codec. */
|
|
43
|
+
export interface ImageMetadata {
|
|
44
|
+
/** Detected container format. */
|
|
45
|
+
readonly format: DetectedFormat;
|
|
46
|
+
/** Pixel width, or `0` when the format carries no readable dimensions. */
|
|
47
|
+
readonly width: number;
|
|
48
|
+
/** Pixel height, or `0` when the format carries no readable dimensions. */
|
|
49
|
+
readonly height: number;
|
|
50
|
+
/** Byte length of the encoded image. */
|
|
51
|
+
readonly size: number;
|
|
52
|
+
/** True when the source declares an alpha channel. */
|
|
53
|
+
readonly hasAlpha?: boolean;
|
|
54
|
+
/** True for animated GIF / WebP. Animated sources skip resizing by default. */
|
|
55
|
+
readonly isAnimated?: boolean;
|
|
56
|
+
/** EXIF orientation (1-8) when present. */
|
|
57
|
+
readonly orientation?: number;
|
|
58
|
+
/** Colour space reported by the codec, when the engine can supply it. */
|
|
59
|
+
readonly space?: string;
|
|
60
|
+
}
|
|
61
|
+
/** How a resize should fill the requested box. Mirrors the familiar CSS names. */
|
|
62
|
+
export type FitMode = 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
|
|
63
|
+
/** Gravity used when `fit: 'cover'` has to crop. */
|
|
64
|
+
export type Position = 'center' | 'top' | 'right' | 'bottom' | 'left' | 'entropy' | 'attention';
|
|
65
|
+
/** A single resize instruction. At least one of `width` / `height` is required. */
|
|
66
|
+
export interface ResizeSpec {
|
|
67
|
+
readonly width?: number;
|
|
68
|
+
readonly height?: number;
|
|
69
|
+
/** Default `'cover'`. */
|
|
70
|
+
readonly fit?: FitMode;
|
|
71
|
+
/** Default `'center'`. */
|
|
72
|
+
readonly position?: Position;
|
|
73
|
+
/** Never scale an image above its intrinsic size. Default `true`. */
|
|
74
|
+
readonly withoutEnlargement?: boolean;
|
|
75
|
+
/** Flat background for `contain` letterboxing, as `#rrggbb` or `#rrggbbaa`. */
|
|
76
|
+
readonly background?: string;
|
|
77
|
+
}
|
|
78
|
+
/** A fully resolved instruction handed to an {@link ImageEngine}. */
|
|
79
|
+
export interface TransformOp {
|
|
80
|
+
/** Omitted for a straight re-encode at native size. */
|
|
81
|
+
readonly resize?: ResizeSpec;
|
|
82
|
+
/** Target output format. */
|
|
83
|
+
readonly format: ImageFormat;
|
|
84
|
+
/** 1-100. Ignored by lossless formats. */
|
|
85
|
+
readonly quality: number;
|
|
86
|
+
/** Keep EXIF / ICC / XMP in the output. Default `false`. */
|
|
87
|
+
readonly preserveMetadata: boolean;
|
|
88
|
+
/** Apply EXIF orientation and drop the tag. Default `true`. */
|
|
89
|
+
readonly autoOrient: boolean;
|
|
90
|
+
/** Encode losslessly where the format supports it (webp, avif). */
|
|
91
|
+
readonly lossless?: boolean;
|
|
92
|
+
/** Progressive / interlaced encode where supported (jpeg, png). */
|
|
93
|
+
readonly progressive?: boolean;
|
|
94
|
+
/** Encoder effort, 0-9. Higher is slower and smaller. */
|
|
95
|
+
readonly effort?: number;
|
|
96
|
+
/** Chroma subsampling override, e.g. `'4:4:4'`. */
|
|
97
|
+
readonly chromaSubsampling?: string;
|
|
98
|
+
}
|
|
99
|
+
/** The bytes an engine produced, plus what they turned out to be. */
|
|
100
|
+
export interface EncodedImage {
|
|
101
|
+
readonly data: Uint8Array;
|
|
102
|
+
readonly format: ImageFormat;
|
|
103
|
+
readonly width: number;
|
|
104
|
+
readonly height: number;
|
|
105
|
+
readonly size: number;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A codec backend. Implement this to swap sharp for squoosh, an ImageMagick
|
|
109
|
+
* shell-out, a WASM codec, or a stub in tests.
|
|
110
|
+
*
|
|
111
|
+
* Engines are expected to be stateless and safe to call concurrently.
|
|
112
|
+
*/
|
|
113
|
+
export interface ImageEngine {
|
|
114
|
+
/** Short identifier, surfaced in errors and results (e.g. `'sharp'`). */
|
|
115
|
+
readonly name: string;
|
|
116
|
+
/**
|
|
117
|
+
* Whether this engine can *encode* the given format. Lens calls this before
|
|
118
|
+
* planning work so it can degrade gracefully instead of failing mid-run.
|
|
119
|
+
*/
|
|
120
|
+
supports(format: ImageFormat): boolean | Promise<boolean>;
|
|
121
|
+
/**
|
|
122
|
+
* Read dimensions and metadata. Engines may return richer data than the
|
|
123
|
+
* built-in header sniffer, and Lens prefers the engine's answer when present.
|
|
124
|
+
*/
|
|
125
|
+
probe(input: Uint8Array): Promise<ImageMetadata>;
|
|
126
|
+
/** Resize and/or re-encode. Must not mutate `input`. */
|
|
127
|
+
transform(input: Uint8Array, op: TransformOp): Promise<EncodedImage>;
|
|
128
|
+
}
|
|
129
|
+
/** One object about to be written to storage. */
|
|
130
|
+
export interface StorageFile {
|
|
131
|
+
/** Storage key / relative path, already templated. No leading slash. */
|
|
132
|
+
readonly key: string;
|
|
133
|
+
readonly data: Uint8Array;
|
|
134
|
+
/** MIME type, e.g. `image/webp`. */
|
|
135
|
+
readonly contentType: string;
|
|
136
|
+
/** Suggested `Cache-Control`. Adapters may override from their own config. */
|
|
137
|
+
readonly cacheControl?: string;
|
|
138
|
+
/** Arbitrary key/value metadata. Adapters map this to their native concept. */
|
|
139
|
+
readonly metadata?: Readonly<Record<string, string>>;
|
|
140
|
+
/** Hex content hash of `data`, handy for ETags and dedupe. */
|
|
141
|
+
readonly checksum?: string;
|
|
142
|
+
}
|
|
143
|
+
/** Context passed alongside every upload so adapters can log or route. */
|
|
144
|
+
export interface StorageContext {
|
|
145
|
+
/** Abort signal propagated from `optimize({ signal })`. */
|
|
146
|
+
readonly signal?: AbortSignal;
|
|
147
|
+
/** Which attempt this is, starting at 1. Set by the retry wrapper. */
|
|
148
|
+
readonly attempt: number;
|
|
149
|
+
/** The optimize run this upload belongs to. */
|
|
150
|
+
readonly runId: string;
|
|
151
|
+
}
|
|
152
|
+
/** What an adapter reports back after a successful write. */
|
|
153
|
+
export interface StorageObject {
|
|
154
|
+
/** The key actually written - adapters may prefix or rewrite it. */
|
|
155
|
+
readonly key: string;
|
|
156
|
+
/** Publicly reachable URL, or a best-effort local URL. */
|
|
157
|
+
readonly url: string;
|
|
158
|
+
/** Bytes written. */
|
|
159
|
+
readonly size: number;
|
|
160
|
+
readonly etag?: string;
|
|
161
|
+
/** Adapter-specific extras (S3 versionId, Cloudinary public_id, ...). */
|
|
162
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* A storage backend.
|
|
166
|
+
*
|
|
167
|
+
* Only {@link StorageAdapter.upload} is required. Implementing `exists` unlocks
|
|
168
|
+
* cache short-circuiting; implementing `remove` unlocks
|
|
169
|
+
* {@link ImageOptimizer.delete}.
|
|
170
|
+
*
|
|
171
|
+
* @example A minimal in-memory adapter
|
|
172
|
+
* ```ts
|
|
173
|
+
* const files = new Map<string, Uint8Array>();
|
|
174
|
+
*
|
|
175
|
+
* const adapter: StorageAdapter = {
|
|
176
|
+
* name: 'memory',
|
|
177
|
+
* async upload(file) {
|
|
178
|
+
* files.set(file.key, file.data);
|
|
179
|
+
* return { key: file.key, url: `memory://${file.key}`, size: file.data.byteLength };
|
|
180
|
+
* },
|
|
181
|
+
* };
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export interface StorageAdapter {
|
|
185
|
+
/** Short identifier, surfaced in errors (e.g. `'s3'`). */
|
|
186
|
+
readonly name: string;
|
|
187
|
+
/** Write one object. Should throw on failure; Lens handles the retries. */
|
|
188
|
+
upload(file: StorageFile, ctx: StorageContext): Promise<StorageObject>;
|
|
189
|
+
/** Cheap existence probe. Enables `cache: 'storage'`. */
|
|
190
|
+
exists?(key: string, ctx?: Partial<StorageContext>): Promise<boolean>;
|
|
191
|
+
/** Delete one object. Enables {@link ImageOptimizer.delete}. */
|
|
192
|
+
remove?(key: string, ctx?: Partial<StorageContext>): Promise<void>;
|
|
193
|
+
/** Public URL for a key without performing a write. */
|
|
194
|
+
getUrl?(key: string): string;
|
|
195
|
+
/** Release sockets, flush buffers. Called by {@link ImageOptimizer.dispose}. */
|
|
196
|
+
dispose?(): Promise<void> | void;
|
|
197
|
+
}
|
|
198
|
+
/** One requested output size. */
|
|
199
|
+
export interface SizeSpec extends ResizeSpec {
|
|
200
|
+
/**
|
|
201
|
+
* Name used in the output key and in `formats[f].urls`. Defaults to
|
|
202
|
+
* `"<width>w"`, or `"<height>h"` when only a height is given.
|
|
203
|
+
*/
|
|
204
|
+
readonly label?: string;
|
|
205
|
+
/** Per-size quality override. */
|
|
206
|
+
readonly quality?: number;
|
|
207
|
+
}
|
|
208
|
+
/** Validation limits applied before any pixels are decoded. */
|
|
209
|
+
export interface ValidationOptions {
|
|
210
|
+
/** Reject sources larger than this many bytes. Default 25 MiB. */
|
|
211
|
+
readonly maxBytes?: number;
|
|
212
|
+
/** Reject sources whose `width * height` exceeds this. Default 100 megapixels. */
|
|
213
|
+
readonly maxPixels?: number;
|
|
214
|
+
/** Allowed input formats. Default: every format the engine can decode. */
|
|
215
|
+
readonly allowedFormats?: readonly DetectedFormat[];
|
|
216
|
+
/** Reject images narrower than this. */
|
|
217
|
+
readonly minWidth?: number;
|
|
218
|
+
/** Reject images shorter than this. */
|
|
219
|
+
readonly minHeight?: number;
|
|
220
|
+
}
|
|
221
|
+
/** Retry policy for adapter writes. */
|
|
222
|
+
export interface RetryOptions {
|
|
223
|
+
/** Total attempts including the first. Default 3. Set to 1 to disable. */
|
|
224
|
+
readonly attempts?: number;
|
|
225
|
+
/** Delay before the second attempt, in ms. Default 200. */
|
|
226
|
+
readonly baseDelayMs?: number;
|
|
227
|
+
/** Ceiling for the exponential backoff, in ms. Default 5000. */
|
|
228
|
+
readonly maxDelayMs?: number;
|
|
229
|
+
/**
|
|
230
|
+
* Decide whether an error is worth retrying. Default: retry network-ish and
|
|
231
|
+
* 5xx errors, never 4xx.
|
|
232
|
+
*/
|
|
233
|
+
readonly isRetryable?: (error: unknown) => boolean;
|
|
234
|
+
/** Called before each sleep. Useful for logging and tests. */
|
|
235
|
+
readonly onRetry?: (info: {
|
|
236
|
+
attempt: number;
|
|
237
|
+
delayMs: number;
|
|
238
|
+
error: unknown;
|
|
239
|
+
}) => void;
|
|
240
|
+
}
|
|
241
|
+
/** Where processed-output bookkeeping lives. */
|
|
242
|
+
export interface CacheStore {
|
|
243
|
+
get(key: string): Promise<OptimizeResult | undefined> | OptimizeResult | undefined;
|
|
244
|
+
set(key: string, value: OptimizeResult): Promise<void> | void;
|
|
245
|
+
delete?(key: string): Promise<void> | void;
|
|
246
|
+
}
|
|
247
|
+
/** Tokens available to a key template or key function. */
|
|
248
|
+
export interface KeyContext {
|
|
249
|
+
/** Source basename without extension, slugified. */
|
|
250
|
+
readonly name: string;
|
|
251
|
+
/** Short content hash of the source bytes. */
|
|
252
|
+
readonly hash: string;
|
|
253
|
+
/** Full content hash of the source bytes. */
|
|
254
|
+
readonly fullHash: string;
|
|
255
|
+
readonly format: ImageFormat;
|
|
256
|
+
/** File extension without the dot - `jpg` for `jpeg`. */
|
|
257
|
+
readonly ext: string;
|
|
258
|
+
readonly width: number;
|
|
259
|
+
readonly height: number;
|
|
260
|
+
readonly quality: number;
|
|
261
|
+
/** Size label, e.g. `1200w` or `thumb`. */
|
|
262
|
+
readonly label: string;
|
|
263
|
+
}
|
|
264
|
+
/** Everything `new ImageOptimizer(...)` accepts. */
|
|
265
|
+
export interface ImageOptimizerOptions {
|
|
266
|
+
/**
|
|
267
|
+
* Where output goes. Omit to run in "process only" mode: results carry bytes
|
|
268
|
+
* in `variant.data` and no URLs.
|
|
269
|
+
*/
|
|
270
|
+
readonly adapter?: StorageAdapter;
|
|
271
|
+
/**
|
|
272
|
+
* Codec backend. Defaults to sharp when it is installed, otherwise a
|
|
273
|
+
* passthrough engine that can re-key and validate but not resize.
|
|
274
|
+
*/
|
|
275
|
+
readonly engine?: ImageEngine;
|
|
276
|
+
/** Default quality for every output. 1-100. Default 80. */
|
|
277
|
+
readonly quality?: number;
|
|
278
|
+
/** Default formats when a call does not specify any. Default `['webp']`. */
|
|
279
|
+
readonly formats?: readonly ImageFormatInput[];
|
|
280
|
+
/** Default sizes when a call does not specify any. Default: original size. */
|
|
281
|
+
readonly sizes?: readonly SizeSpec[];
|
|
282
|
+
/**
|
|
283
|
+
* Format to fall back to when a requested format cannot be produced.
|
|
284
|
+
* Default `'jpeg'`. Set to `null` to disable fallback entirely.
|
|
285
|
+
*/
|
|
286
|
+
readonly fallbackFormat?: ImageFormatInput | null;
|
|
287
|
+
/**
|
|
288
|
+
* Output key template, or a function. Tokens: `{name} {hash} {fullHash}
|
|
289
|
+
* {format} {ext} {width} {height} {quality} {label}`.
|
|
290
|
+
*
|
|
291
|
+
* Default: `'{hash}/{name}-{label}.{ext}'`.
|
|
292
|
+
*/
|
|
293
|
+
readonly key?: string | ((ctx: KeyContext) => string);
|
|
294
|
+
/** Prepended to every key. A trailing slash is added if missing. */
|
|
295
|
+
readonly prefix?: string;
|
|
296
|
+
/** Keep EXIF / ICC / XMP. Default `false` - metadata is stripped. */
|
|
297
|
+
readonly preserveMetadata?: boolean;
|
|
298
|
+
/** Apply EXIF orientation before resizing. Default `true`. */
|
|
299
|
+
readonly autoOrient?: boolean;
|
|
300
|
+
/** How many encode+upload pipelines run at once. Default 4. */
|
|
301
|
+
readonly concurrency?: number;
|
|
302
|
+
/** Validation limits. */
|
|
303
|
+
readonly validate?: ValidationOptions | false;
|
|
304
|
+
/** Retry policy for adapter writes. */
|
|
305
|
+
readonly retry?: RetryOptions;
|
|
306
|
+
/**
|
|
307
|
+
* Result caching.
|
|
308
|
+
* - `false` (default) - always reprocess.
|
|
309
|
+
* - `'memory'` - process-lifetime LRU keyed by source hash + options.
|
|
310
|
+
* - `'storage'` - `'memory'`, plus skip work when `adapter.exists` says the
|
|
311
|
+
* keys are already there.
|
|
312
|
+
* - a {@link CacheStore} - bring your own (Redis, SQLite, ...).
|
|
313
|
+
*/
|
|
314
|
+
readonly cache?: false | 'memory' | 'storage' | CacheStore;
|
|
315
|
+
/** Entries kept by the built-in memory cache. Default 500. */
|
|
316
|
+
readonly cacheSize?: number;
|
|
317
|
+
/** `Cache-Control` applied to every upload. Default `public, max-age=31536000, immutable`. */
|
|
318
|
+
readonly cacheControl?: string;
|
|
319
|
+
/** Allow `http(s):` sources. Off by default - it is an SSRF surface. */
|
|
320
|
+
readonly allowRemote?: boolean;
|
|
321
|
+
/** Called for every non-fatal degradation. Default: silent. */
|
|
322
|
+
readonly onWarning?: (warning: LensWarning) => void;
|
|
323
|
+
}
|
|
324
|
+
/** Per-call options. Anything omitted falls back to the constructor value. */
|
|
325
|
+
export interface OptimizeOptions extends Pick<ImageOptimizerOptions, 'quality' | 'formats' | 'sizes' | 'fallbackFormat' | 'key' | 'prefix' | 'preserveMetadata' | 'autoOrient' | 'concurrency' | 'validate' | 'retry' | 'cacheControl' | 'onWarning'> {
|
|
326
|
+
/** The image to process. */
|
|
327
|
+
readonly source: ImageSource;
|
|
328
|
+
/** Overrides the filename derived from `source`. */
|
|
329
|
+
readonly filename?: string;
|
|
330
|
+
/**
|
|
331
|
+
* Also emit a small square-ish preview.
|
|
332
|
+
* `true` means 256px wide in the first requested format.
|
|
333
|
+
*/
|
|
334
|
+
readonly thumbnail?: boolean | ThumbnailSpec;
|
|
335
|
+
/** Metadata attached to every uploaded object. */
|
|
336
|
+
readonly metadata?: Readonly<Record<string, string>>;
|
|
337
|
+
/** Keep encoded bytes on each variant. Default `true` without an adapter. */
|
|
338
|
+
readonly keepData?: boolean;
|
|
339
|
+
/** Cancel in-flight encodes and uploads. */
|
|
340
|
+
readonly signal?: AbortSignal;
|
|
341
|
+
/** Skip the cache for this call only. */
|
|
342
|
+
readonly force?: boolean;
|
|
343
|
+
}
|
|
344
|
+
/** Thumbnail configuration. */
|
|
345
|
+
export interface ThumbnailSpec extends ResizeSpec {
|
|
346
|
+
/** Default 256. */
|
|
347
|
+
readonly width?: number;
|
|
348
|
+
readonly height?: number;
|
|
349
|
+
/** Defaults to the first requested output format. */
|
|
350
|
+
readonly format?: ImageFormatInput;
|
|
351
|
+
/** Defaults to the run quality. */
|
|
352
|
+
readonly quality?: number;
|
|
353
|
+
/** Default `'thumb'`. */
|
|
354
|
+
readonly label?: string;
|
|
355
|
+
}
|
|
356
|
+
/** One generated file. */
|
|
357
|
+
export interface Variant {
|
|
358
|
+
readonly format: ImageFormat;
|
|
359
|
+
readonly label: string;
|
|
360
|
+
readonly width: number;
|
|
361
|
+
readonly height: number;
|
|
362
|
+
/** Bytes of the encoded output. */
|
|
363
|
+
readonly size: number;
|
|
364
|
+
readonly quality: number;
|
|
365
|
+
/** Storage key, or the templated key when running without an adapter. */
|
|
366
|
+
readonly key: string;
|
|
367
|
+
/** Public URL. Empty string when running without an adapter. */
|
|
368
|
+
readonly url: string;
|
|
369
|
+
readonly contentType: string;
|
|
370
|
+
/** Hex content hash of the encoded bytes. */
|
|
371
|
+
readonly checksum: string;
|
|
372
|
+
/** Present when `keepData` is on, or when there is no adapter. */
|
|
373
|
+
readonly data?: Uint8Array;
|
|
374
|
+
/** True when this variant was produced by the fallback format. */
|
|
375
|
+
readonly isFallback?: boolean;
|
|
376
|
+
/** True for the variant generated by the `thumbnail` option. */
|
|
377
|
+
readonly isThumbnail?: boolean;
|
|
378
|
+
/** ETag reported by the adapter, when it supplies one. */
|
|
379
|
+
readonly etag?: string;
|
|
380
|
+
/** Adapter extras. */
|
|
381
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
382
|
+
}
|
|
383
|
+
/** All variants of one format, grouped for convenient template access. */
|
|
384
|
+
export interface FormatResult {
|
|
385
|
+
readonly format: ImageFormat;
|
|
386
|
+
/** `{ '1200w': 'https://...', '600w': 'https://...' }` */
|
|
387
|
+
readonly urls: Readonly<Record<string, string>>;
|
|
388
|
+
readonly variants: readonly Variant[];
|
|
389
|
+
/** Total bytes across every variant of this format. */
|
|
390
|
+
readonly size: number;
|
|
391
|
+
/** Ready-to-use `srcset` attribute value. Empty when URLs are unavailable. */
|
|
392
|
+
readonly srcset: string;
|
|
393
|
+
/** The widest variant - a sensible `src` fallback. */
|
|
394
|
+
readonly largest: Variant;
|
|
395
|
+
/** The narrowest variant. */
|
|
396
|
+
readonly smallest: Variant;
|
|
397
|
+
}
|
|
398
|
+
/** A non-fatal degradation. */
|
|
399
|
+
export interface LensWarning {
|
|
400
|
+
/** Machine-readable reason, e.g. `'format_unsupported'`. */
|
|
401
|
+
readonly code: string;
|
|
402
|
+
readonly message: string;
|
|
403
|
+
/** Format the warning relates to, when applicable. */
|
|
404
|
+
readonly format?: ImageFormat;
|
|
405
|
+
readonly label?: string;
|
|
406
|
+
/** The underlying error, when the warning came from a thrown exception. */
|
|
407
|
+
readonly cause?: unknown;
|
|
408
|
+
}
|
|
409
|
+
/** What {@link ImageOptimizer.optimize} resolves to. */
|
|
410
|
+
export interface OptimizeResult {
|
|
411
|
+
/** Stable id for this source + options combination. Also the cache key. */
|
|
412
|
+
readonly id: string;
|
|
413
|
+
/** Unique per call, even on a cache hit. Correlates logs. */
|
|
414
|
+
readonly runId: string;
|
|
415
|
+
/** What the input turned out to be. */
|
|
416
|
+
readonly source: ImageMetadata & {
|
|
417
|
+
readonly filename: string;
|
|
418
|
+
readonly checksum: string;
|
|
419
|
+
};
|
|
420
|
+
/** Grouped by canonical format name: `result.formats.webp.urls['600w']`. */
|
|
421
|
+
readonly formats: Readonly<Partial<Record<ImageFormat, FormatResult>>>;
|
|
422
|
+
/** Every variant, in plan order. */
|
|
423
|
+
readonly variants: readonly Variant[];
|
|
424
|
+
/** Present when `thumbnail` was requested and succeeded. */
|
|
425
|
+
readonly thumbnail?: Variant;
|
|
426
|
+
/** Non-fatal degradations - unsupported formats, fallbacks taken. */
|
|
427
|
+
readonly warnings: readonly LensWarning[];
|
|
428
|
+
/** Total output bytes across every variant. */
|
|
429
|
+
readonly totalSize: number;
|
|
430
|
+
/** `1 - totalSize / source.size`, clamped to 0. Negative savings report 0. */
|
|
431
|
+
readonly savings: number;
|
|
432
|
+
/** Wall-clock duration in ms. */
|
|
433
|
+
readonly durationMs: number;
|
|
434
|
+
/** True when the result came from cache rather than fresh work. */
|
|
435
|
+
readonly cached: boolean;
|
|
436
|
+
/** Engine that produced the output. */
|
|
437
|
+
readonly engine: string;
|
|
438
|
+
/** Adapter that stored it, or `null` in process-only mode. */
|
|
439
|
+
readonly adapter: string | null;
|
|
440
|
+
}
|
|
441
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public type surface of `@lens-image/core`.
|
|
3
|
+
*
|
|
4
|
+
* Everything in this file is an interface or a plain data shape - there is no
|
|
5
|
+
* runtime code here, so adapter and engine authors can depend on these types
|
|
6
|
+
* without pulling in any of the implementation.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input validation, run against the sniffed header before any decode happens.
|
|
3
|
+
*/
|
|
4
|
+
import type { DetectedFormat, ImageMetadata, ValidationOptions } from './types.js';
|
|
5
|
+
/** 25 MiB. Large enough for a phone photo, small enough to bound memory. */
|
|
6
|
+
export declare const DEFAULT_MAX_BYTES: number;
|
|
7
|
+
/**
|
|
8
|
+
* 100 megapixels. A 10,000 x 10,000 image is already 400 MB decoded at
|
|
9
|
+
* 4 bytes/pixel, so this is the line between "big photo" and "denial of service".
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_MAX_PIXELS = 100000000;
|
|
12
|
+
/** Formats accepted as input unless the caller narrows the list. */
|
|
13
|
+
export declare const DEFAULT_ALLOWED_FORMATS: readonly DetectedFormat[];
|
|
14
|
+
/** A fully-resolved validation policy. */
|
|
15
|
+
export interface ResolvedValidation {
|
|
16
|
+
readonly maxBytes: number;
|
|
17
|
+
readonly maxPixels: number;
|
|
18
|
+
readonly allowedFormats: readonly DetectedFormat[];
|
|
19
|
+
readonly minWidth: number;
|
|
20
|
+
readonly minHeight: number;
|
|
21
|
+
}
|
|
22
|
+
/** Fills in defaults for anything the caller left out. */
|
|
23
|
+
export declare function resolveValidation(options: ValidationOptions | false | undefined): ResolvedValidation | null;
|
|
24
|
+
/**
|
|
25
|
+
* Applies a resolved policy to sniffed metadata.
|
|
26
|
+
*
|
|
27
|
+
* @throws {LensError} `VALIDATION_FAILED` or `UNSUPPORTED_INPUT`, with the limit
|
|
28
|
+
* and the actual value on `error.details` so callers can build a useful
|
|
29
|
+
* response without re-deriving them.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const policy = resolveValidation({ maxBytes: 5_000_000, allowedFormats: ['jpeg', 'png'] });
|
|
34
|
+
* validateImage(sniff(bytes), policy, 'avatar.png');
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function validateImage(meta: ImageMetadata, policy: ResolvedValidation | null, filename?: string): void;
|
|
38
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEnF,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB,QAAmB,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,YAAc,CAAC;AAE9C,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,EAAE,SAAS,cAAc,EAO5D,CAAC;AAEF,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,SAAS,cAAc,EAAE,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,KAAK,GAAG,SAAS,GAAG,kBAAkB,GAAG,IAAI,CAS3G;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,kBAAkB,GAAG,IAAI,EACjC,QAAQ,SAAU,GACjB,IAAI,CAoDN"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input validation, run against the sniffed header before any decode happens.
|
|
3
|
+
*/
|
|
4
|
+
import { LensError } from './errors.js';
|
|
5
|
+
import { formatBytes } from './bytes.js';
|
|
6
|
+
/** 25 MiB. Large enough for a phone photo, small enough to bound memory. */
|
|
7
|
+
export const DEFAULT_MAX_BYTES = 25 * 1024 * 1024;
|
|
8
|
+
/**
|
|
9
|
+
* 100 megapixels. A 10,000 x 10,000 image is already 400 MB decoded at
|
|
10
|
+
* 4 bytes/pixel, so this is the line between "big photo" and "denial of service".
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_MAX_PIXELS = 100_000_000;
|
|
13
|
+
/** Formats accepted as input unless the caller narrows the list. */
|
|
14
|
+
export const DEFAULT_ALLOWED_FORMATS = [
|
|
15
|
+
'jpeg',
|
|
16
|
+
'png',
|
|
17
|
+
'webp',
|
|
18
|
+
'avif',
|
|
19
|
+
'gif',
|
|
20
|
+
'tiff',
|
|
21
|
+
];
|
|
22
|
+
/** Fills in defaults for anything the caller left out. */
|
|
23
|
+
export function resolveValidation(options) {
|
|
24
|
+
if (options === false)
|
|
25
|
+
return null;
|
|
26
|
+
return {
|
|
27
|
+
maxBytes: options?.maxBytes ?? DEFAULT_MAX_BYTES,
|
|
28
|
+
maxPixels: options?.maxPixels ?? DEFAULT_MAX_PIXELS,
|
|
29
|
+
allowedFormats: options?.allowedFormats ?? DEFAULT_ALLOWED_FORMATS,
|
|
30
|
+
minWidth: options?.minWidth ?? 0,
|
|
31
|
+
minHeight: options?.minHeight ?? 0,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Applies a resolved policy to sniffed metadata.
|
|
36
|
+
*
|
|
37
|
+
* @throws {LensError} `VALIDATION_FAILED` or `UNSUPPORTED_INPUT`, with the limit
|
|
38
|
+
* and the actual value on `error.details` so callers can build a useful
|
|
39
|
+
* response without re-deriving them.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* const policy = resolveValidation({ maxBytes: 5_000_000, allowedFormats: ['jpeg', 'png'] });
|
|
44
|
+
* validateImage(sniff(bytes), policy, 'avatar.png');
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function validateImage(meta, policy, filename = 'image') {
|
|
48
|
+
if (!policy)
|
|
49
|
+
return;
|
|
50
|
+
if (meta.format === 'unknown') {
|
|
51
|
+
throw new LensError('UNSUPPORTED_INPUT', `"${filename}" is not a recognisable image. The first bytes match no known image container.`, { details: { detected: 'unknown' } });
|
|
52
|
+
}
|
|
53
|
+
if (!policy.allowedFormats.includes(meta.format)) {
|
|
54
|
+
throw new LensError('VALIDATION_FAILED', `"${filename}" is ${meta.format}, which is not in the allowed list (${policy.allowedFormats.join(', ')}).`, { details: { detected: meta.format, allowed: policy.allowedFormats } });
|
|
55
|
+
}
|
|
56
|
+
if (meta.size > policy.maxBytes) {
|
|
57
|
+
throw new LensError('VALIDATION_FAILED', `"${filename}" is ${formatBytes(meta.size)}, over the ${formatBytes(policy.maxBytes)} limit.`, { details: { limit: policy.maxBytes, actual: meta.size } });
|
|
58
|
+
}
|
|
59
|
+
const pixels = meta.width * meta.height;
|
|
60
|
+
if (pixels > policy.maxPixels) {
|
|
61
|
+
throw new LensError('VALIDATION_FAILED', `"${filename}" is ${meta.width}x${meta.height} (${formatMegapixels(pixels)}), over the ` +
|
|
62
|
+
`${formatMegapixels(policy.maxPixels)} limit. This guard exists to stop decompression bombs.`, { details: { limit: policy.maxPixels, actual: pixels } });
|
|
63
|
+
}
|
|
64
|
+
if (policy.minWidth > 0 && meta.width > 0 && meta.width < policy.minWidth) {
|
|
65
|
+
throw new LensError('VALIDATION_FAILED', `"${filename}" is ${meta.width}px wide, under the ${policy.minWidth}px minimum.`, { details: { limit: policy.minWidth, actual: meta.width } });
|
|
66
|
+
}
|
|
67
|
+
if (policy.minHeight > 0 && meta.height > 0 && meta.height < policy.minHeight) {
|
|
68
|
+
throw new LensError('VALIDATION_FAILED', `"${filename}" is ${meta.height}px tall, under the ${policy.minHeight}px minimum.`, { details: { limit: policy.minHeight, actual: meta.height } });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function formatMegapixels(pixels) {
|
|
72
|
+
return `${(pixels / 1_000_000).toFixed(1)}MP`;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,4EAA4E;AAC5E,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAElD;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAC;AAE9C,oEAAoE;AACpE,MAAM,CAAC,MAAM,uBAAuB,GAA8B;IAChE,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;CACP,CAAC;AAWF,0DAA0D;AAC1D,MAAM,UAAU,iBAAiB,CAAC,OAA8C;IAC9E,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO;QACL,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,iBAAiB;QAChD,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,kBAAkB;QACnD,cAAc,EAAE,OAAO,EAAE,cAAc,IAAI,uBAAuB;QAClE,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,CAAC;QAChC,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,CAAC;KACnC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAmB,EACnB,MAAiC,EACjC,QAAQ,GAAG,OAAO;IAElB,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CACjB,mBAAmB,EACnB,IAAI,QAAQ,gFAAgF,EAC5F,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CACrC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,SAAS,CACjB,mBAAmB,EACnB,IAAI,QAAQ,QAAQ,IAAI,CAAC,MAAM,uCAAuC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAC1G,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE,EAAE,CACvE,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CACjB,mBAAmB,EACnB,IAAI,QAAQ,QAAQ,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAC7F,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAC3D,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;IACxC,IAAI,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CACjB,mBAAmB,EACnB,IAAI,QAAQ,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,gBAAgB,CAAC,MAAM,CAAC,cAAc;YACtF,GAAG,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,wDAAwD,EAC/F,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CACzD,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC1E,MAAM,IAAI,SAAS,CACjB,mBAAmB,EACnB,IAAI,QAAQ,QAAQ,IAAI,CAAC,KAAK,sBAAsB,MAAM,CAAC,QAAQ,aAAa,EAChF,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAC5D,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAC9E,MAAM,IAAI,SAAS,CACjB,mBAAmB,EACnB,IAAI,QAAQ,QAAQ,IAAI,CAAC,MAAM,sBAAsB,MAAM,CAAC,SAAS,aAAa,EAClF,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAC9D,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAc;IACtC,OAAO,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC"}
|