ipx 1.2.0 → 1.3.1
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/README.md +43 -12
- package/bin/ipx.mjs +1 -1
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.mts +2 -0
- package/dist/cli.d.ts +1 -1
- package/dist/index.cjs +26 -6
- package/dist/index.d.cts +144 -0
- package/dist/index.d.mts +144 -0
- package/dist/index.d.ts +6 -36
- package/dist/index.mjs +26 -6
- package/package.json +25 -21
package/README.md
CHANGED
|
@@ -5,31 +5,60 @@
|
|
|
5
5
|
|
|
6
6
|
High performance, secure and easy to use image proxy based on [sharp](https://github.com/lovell/sharp) and [libvips](https://github.com/libvips/libvips).
|
|
7
7
|
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
### Quick Start
|
|
8
|
+
## Using CLI
|
|
11
9
|
|
|
12
10
|
You can use `ipx` command to start server using:
|
|
13
11
|
|
|
14
12
|
```bash
|
|
15
|
-
|
|
13
|
+
npx ipx@latest
|
|
16
14
|
```
|
|
17
15
|
|
|
18
16
|
The default server directory is the current working directory.
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
## Programatic API
|
|
19
|
+
|
|
20
|
+
You can use IPX as a middleware or directly use IPX interface.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
```ts
|
|
23
|
+
import { createIPX, createIPXMiddleware } from "ipx";
|
|
24
|
+
|
|
25
|
+
const ipx = createIPX({ domains: ["unjs.io"] });
|
|
26
|
+
|
|
27
|
+
// (req, res) => void
|
|
28
|
+
const ipxMiddleware = createIPXMiddleware(ipx);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Example**: Using with [unjs/h3](https://github.com/unjs/h3):
|
|
23
32
|
|
|
24
33
|
```js
|
|
25
34
|
import { createIPX, createIPXMiddleware } from "ipx";
|
|
35
|
+
import { listen } from "listhen";
|
|
36
|
+
import { createApp, fromNodeMiddleware, toNodeListener } from "h3";
|
|
37
|
+
|
|
38
|
+
const ipx = createIPX({});
|
|
39
|
+
const ipxMiddleware = createIPXMiddleware(ipx);
|
|
40
|
+
|
|
41
|
+
const app = createApp().use("/", fromNodeMiddleware(ipxMiddleware));
|
|
42
|
+
|
|
43
|
+
listen(toNodeListener(app));
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Example:** Using [express](https://expressjs.com):
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import { createIPX, createIPXMiddleware } from "ipx";
|
|
50
|
+
import { listen } from "listhen";
|
|
51
|
+
import express from "express";
|
|
52
|
+
|
|
53
|
+
const ipx = createIPX({});
|
|
54
|
+
const ipxMiddleware = createIPXMiddleware(ipx);
|
|
55
|
+
|
|
56
|
+
const app = express().use("/", ipxMiddleware);
|
|
26
57
|
|
|
27
|
-
|
|
28
|
-
const app = express();
|
|
29
|
-
app.use("/image", createIPXMiddleware(ipx));
|
|
58
|
+
listen(app);
|
|
30
59
|
```
|
|
31
60
|
|
|
32
|
-
|
|
61
|
+
## Examples
|
|
33
62
|
|
|
34
63
|
Get original image:
|
|
35
64
|
|
|
@@ -47,17 +76,19 @@ Resize to `200x200px` using `embed` method and change format to `webp`:
|
|
|
47
76
|
|
|
48
77
|
`/embed,f_webp,s_200x200/static/buffalo.png`
|
|
49
78
|
|
|
50
|
-
|
|
79
|
+
## Modifiers
|
|
51
80
|
|
|
52
81
|
| Property | Docs | Example | Comments |
|
|
53
82
|
| -------------- | :-------------------------------------------------------------- | :--------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
54
83
|
| width / w | [Docs](https://sharp.pixelplumbing.com/api-resize#resize) | `/width_200/buffalo.png` |
|
|
55
84
|
| height / h | [Docs](https://sharp.pixelplumbing.com/api-resize#resize) | `/height_200/buffalo.png` |
|
|
56
85
|
| resize / s | [Docs](https://sharp.pixelplumbing.com/api-resize#resize) | `/s_200x200/buffalo.png` |
|
|
86
|
+
| kernel | [Docs](https://sharp.pixelplumbing.com/api-resize#resize) | `/s_200x200,kernel_nearest/buffalo.png` | Supported kernel: `nearest`, `cubic`, `mitchell`, `lanczos2` and `lanczos3` (default). |
|
|
57
87
|
| fit | [Docs](https://sharp.pixelplumbing.com/api-resize#resize) | `/s_200x200,fit_outside/buffalo.png` | Sets `fit` option for `resize`. |
|
|
58
88
|
| position / pos | [Docs](https://sharp.pixelplumbing.com/api-resize#resize) | `/s_200x200,pos_top/buffalo.png` | Sets `position` option for `resize`. |
|
|
59
89
|
| trim | [Docs](https://sharp.pixelplumbing.com/api-resize#trim) | `/trim_100/buffalo.png` |
|
|
60
90
|
| extend | [Docs](https://sharp.pixelplumbing.com/api-resize#extend) | `/extend_{top}_{right}_{bottom}_{left}/buffalo.png` | Extend / pad / extrude one or more edges of the image with either the provided background colour or pixels derived from the image. |
|
|
91
|
+
| background / b | \_ | `/r_45,b_00ff00/buffalo.png` |
|
|
61
92
|
| extract | [Docs](https://sharp.pixelplumbing.com/api-resize#extract) | `/extract_{left}_{top}_{width}_{height}/buffalo.png` | Extract/crop a region of the image. |
|
|
62
93
|
| format / f | [Docs](https://sharp.pixelplumbing.com/api-output#toformat) | `/format_webp/buffalo.png` | Supported format: `jpg`, `jpeg`, `png`, `webp`, `avif`, `gif`, `heif`, `tiff` and `auto` (experimental only with middleware) |
|
|
63
94
|
| quality / q | \_ | `/quality_50/buffalo.png` | Accepted values: 0 to 100 |
|
|
@@ -76,7 +107,7 @@ Resize to `200x200px` using `embed` method and change format to `webp`:
|
|
|
76
107
|
| grayscale | [Docs](https://sharp.pixelplumbing.com/api-colour#grayscale) | `/grayscale/buffalo.png` |
|
|
77
108
|
| animated | - | `/animated/buffalo.gif` | Experimental |
|
|
78
109
|
|
|
79
|
-
|
|
110
|
+
## Config
|
|
80
111
|
|
|
81
112
|
Config can be customized using `IPX_*` environment variables.
|
|
82
113
|
|
package/bin/ipx.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import "../dist/cli.mjs";
|
package/dist/cli.d.cts
ADDED
package/dist/cli.d.mts
ADDED
package/dist/cli.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
|
|
2
|
-
export {
|
|
2
|
+
export { }
|
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ const Handlers = {
|
|
|
38
38
|
get grayscale () { return grayscale; },
|
|
39
39
|
get h () { return h; },
|
|
40
40
|
get height () { return height; },
|
|
41
|
+
get kernel () { return kernel; },
|
|
41
42
|
get median () { return median; },
|
|
42
43
|
get modulate () { return modulate; },
|
|
43
44
|
get negate () { return negate; },
|
|
@@ -57,6 +58,12 @@ const Handlers = {
|
|
|
57
58
|
get width () { return width; }
|
|
58
59
|
};
|
|
59
60
|
|
|
61
|
+
var __defProp = Object.defineProperty;
|
|
62
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
63
|
+
var __publicField = (obj, key, value) => {
|
|
64
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
65
|
+
return value;
|
|
66
|
+
};
|
|
60
67
|
function getEnv(name, defaultValue) {
|
|
61
68
|
return destr__default(process.env[name]) ?? defaultValue;
|
|
62
69
|
}
|
|
@@ -71,6 +78,11 @@ function cachedPromise(function_) {
|
|
|
71
78
|
};
|
|
72
79
|
}
|
|
73
80
|
class IPXError extends Error {
|
|
81
|
+
constructor() {
|
|
82
|
+
super(...arguments);
|
|
83
|
+
__publicField(this, "statusCode");
|
|
84
|
+
__publicField(this, "statusMessage");
|
|
85
|
+
}
|
|
74
86
|
}
|
|
75
87
|
function createError(statusMessage, statusCode, trace) {
|
|
76
88
|
const error = new IPXError(statusMessage + (trace ? ` (${trace})` : ""));
|
|
@@ -242,6 +254,12 @@ const enlarge = {
|
|
|
242
254
|
context.enlarge = true;
|
|
243
255
|
}
|
|
244
256
|
};
|
|
257
|
+
const kernel = {
|
|
258
|
+
args: [VArg],
|
|
259
|
+
apply: (context, _pipe, kernel2) => {
|
|
260
|
+
context.kernel = kernel2;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
245
263
|
const width = {
|
|
246
264
|
args: [VArg],
|
|
247
265
|
apply: (context, pipe, width2) => {
|
|
@@ -279,7 +297,8 @@ const resize = {
|
|
|
279
297
|
return pipe.resize(width2, height2, {
|
|
280
298
|
fit: context.fit,
|
|
281
299
|
position: context.position,
|
|
282
|
-
background: context.background
|
|
300
|
+
background: context.background,
|
|
301
|
+
kernel: context.kernel
|
|
283
302
|
});
|
|
284
303
|
}
|
|
285
304
|
};
|
|
@@ -419,7 +438,8 @@ const SUPPORTED_FORMATS = /* @__PURE__ */ new Set([
|
|
|
419
438
|
"avif",
|
|
420
439
|
"tiff",
|
|
421
440
|
"heif",
|
|
422
|
-
"gif"
|
|
441
|
+
"gif",
|
|
442
|
+
"heic"
|
|
423
443
|
]);
|
|
424
444
|
function createIPX(userOptions) {
|
|
425
445
|
const defaults = {
|
|
@@ -487,7 +507,7 @@ function createIPX(userOptions) {
|
|
|
487
507
|
const Sharp = await import('sharp').then(
|
|
488
508
|
(r) => r.default || r
|
|
489
509
|
);
|
|
490
|
-
let sharp = Sharp(data, { animated });
|
|
510
|
+
let sharp = Sharp(data, { animated, ...options.sharp });
|
|
491
511
|
Object.assign(sharp.options, options.sharp);
|
|
492
512
|
const handlers = Object.entries(modifiers).map(([name, arguments_]) => ({
|
|
493
513
|
handler: getHandler(name),
|
|
@@ -587,7 +607,7 @@ async function _handleRequest(request, ipx) {
|
|
|
587
607
|
}
|
|
588
608
|
res.headers["Content-Security-Policy"] = "default-src 'none'";
|
|
589
609
|
res.body = data;
|
|
590
|
-
return
|
|
610
|
+
return sanitizeReponse(res);
|
|
591
611
|
}
|
|
592
612
|
function handleRequest(request, ipx) {
|
|
593
613
|
return _handleRequest(request, ipx).catch((error) => {
|
|
@@ -596,7 +616,7 @@ function handleRequest(request, ipx) {
|
|
|
596
616
|
if (process.env.NODE_ENV !== "production" && statusCode === 500) {
|
|
597
617
|
console.error(error);
|
|
598
618
|
}
|
|
599
|
-
return
|
|
619
|
+
return sanitizeReponse({
|
|
600
620
|
statusCode,
|
|
601
621
|
statusMessage,
|
|
602
622
|
body: "IPX Error: " + error,
|
|
@@ -639,7 +659,7 @@ function autoDetectFormat(acceptHeader, animated) {
|
|
|
639
659
|
]);
|
|
640
660
|
return acceptMime?.split("/")[1] || "jpeg";
|
|
641
661
|
}
|
|
642
|
-
function
|
|
662
|
+
function sanitizeReponse(res) {
|
|
643
663
|
return {
|
|
644
664
|
statusCode: res.statusCode || 200,
|
|
645
665
|
statusMessage: res.statusMessage ? safeString(res.statusMessage) : "OK",
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Sharp, Color, KernelEnum, SharpOptions } from 'sharp';
|
|
2
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
|
+
|
|
4
|
+
interface ImageMeta {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
type: string;
|
|
8
|
+
mimeType: string;
|
|
9
|
+
}
|
|
10
|
+
interface SourceData {
|
|
11
|
+
mtime?: Date;
|
|
12
|
+
maxAge?: number;
|
|
13
|
+
getData: () => Promise<Buffer>;
|
|
14
|
+
}
|
|
15
|
+
type Source = (source: string, requestOptions?: any) => Promise<SourceData>;
|
|
16
|
+
type SourceFactory<T = Record<string, any>> = (options: T) => Source;
|
|
17
|
+
interface HandlerContext {
|
|
18
|
+
quality?: number;
|
|
19
|
+
fit?: "contain" | "cover" | "fill" | "inside" | "outside";
|
|
20
|
+
position?: number | string;
|
|
21
|
+
background?: Color;
|
|
22
|
+
enlarge?: boolean;
|
|
23
|
+
kernel?: keyof KernelEnum;
|
|
24
|
+
meta: ImageMeta;
|
|
25
|
+
}
|
|
26
|
+
interface Handler {
|
|
27
|
+
args: ((argument: string) => any)[];
|
|
28
|
+
order?: number;
|
|
29
|
+
apply: (context: HandlerContext, pipe: Sharp, ...arguments_: any[]) => any;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare const quality: Handler;
|
|
33
|
+
declare const fit: Handler;
|
|
34
|
+
declare const position: Handler;
|
|
35
|
+
declare const background: Handler;
|
|
36
|
+
declare const enlarge: Handler;
|
|
37
|
+
declare const kernel: Handler;
|
|
38
|
+
declare const width: Handler;
|
|
39
|
+
declare const height: Handler;
|
|
40
|
+
declare const resize: Handler;
|
|
41
|
+
declare const trim: Handler;
|
|
42
|
+
declare const extend: Handler;
|
|
43
|
+
declare const extract: Handler;
|
|
44
|
+
declare const rotate: Handler;
|
|
45
|
+
declare const flip: Handler;
|
|
46
|
+
declare const flop: Handler;
|
|
47
|
+
declare const sharpen: Handler;
|
|
48
|
+
declare const median: Handler;
|
|
49
|
+
declare const blur: Handler;
|
|
50
|
+
declare const flatten: Handler;
|
|
51
|
+
declare const gamma: Handler;
|
|
52
|
+
declare const negate: Handler;
|
|
53
|
+
declare const normalize: Handler;
|
|
54
|
+
declare const threshold: Handler;
|
|
55
|
+
declare const modulate: Handler;
|
|
56
|
+
declare const tint: Handler;
|
|
57
|
+
declare const grayscale: Handler;
|
|
58
|
+
declare const crop: Handler;
|
|
59
|
+
declare const q: Handler;
|
|
60
|
+
declare const b: Handler;
|
|
61
|
+
declare const w: Handler;
|
|
62
|
+
declare const h: Handler;
|
|
63
|
+
declare const s: Handler;
|
|
64
|
+
declare const pos: Handler;
|
|
65
|
+
|
|
66
|
+
declare const Handlers_b: typeof b;
|
|
67
|
+
declare const Handlers_background: typeof background;
|
|
68
|
+
declare const Handlers_blur: typeof blur;
|
|
69
|
+
declare const Handlers_crop: typeof crop;
|
|
70
|
+
declare const Handlers_enlarge: typeof enlarge;
|
|
71
|
+
declare const Handlers_extend: typeof extend;
|
|
72
|
+
declare const Handlers_extract: typeof extract;
|
|
73
|
+
declare const Handlers_fit: typeof fit;
|
|
74
|
+
declare const Handlers_flatten: typeof flatten;
|
|
75
|
+
declare const Handlers_flip: typeof flip;
|
|
76
|
+
declare const Handlers_flop: typeof flop;
|
|
77
|
+
declare const Handlers_gamma: typeof gamma;
|
|
78
|
+
declare const Handlers_grayscale: typeof grayscale;
|
|
79
|
+
declare const Handlers_h: typeof h;
|
|
80
|
+
declare const Handlers_height: typeof height;
|
|
81
|
+
declare const Handlers_kernel: typeof kernel;
|
|
82
|
+
declare const Handlers_median: typeof median;
|
|
83
|
+
declare const Handlers_modulate: typeof modulate;
|
|
84
|
+
declare const Handlers_negate: typeof negate;
|
|
85
|
+
declare const Handlers_normalize: typeof normalize;
|
|
86
|
+
declare const Handlers_pos: typeof pos;
|
|
87
|
+
declare const Handlers_position: typeof position;
|
|
88
|
+
declare const Handlers_q: typeof q;
|
|
89
|
+
declare const Handlers_quality: typeof quality;
|
|
90
|
+
declare const Handlers_resize: typeof resize;
|
|
91
|
+
declare const Handlers_rotate: typeof rotate;
|
|
92
|
+
declare const Handlers_s: typeof s;
|
|
93
|
+
declare const Handlers_sharpen: typeof sharpen;
|
|
94
|
+
declare const Handlers_threshold: typeof threshold;
|
|
95
|
+
declare const Handlers_tint: typeof tint;
|
|
96
|
+
declare const Handlers_trim: typeof trim;
|
|
97
|
+
declare const Handlers_w: typeof w;
|
|
98
|
+
declare const Handlers_width: typeof width;
|
|
99
|
+
declare namespace Handlers {
|
|
100
|
+
export { Handlers_b as b, Handlers_background as background, Handlers_blur as blur, Handlers_crop as crop, Handlers_enlarge as enlarge, Handlers_extend as extend, Handlers_extract as extract, Handlers_fit as fit, Handlers_flatten as flatten, Handlers_flip as flip, Handlers_flop as flop, Handlers_gamma as gamma, Handlers_grayscale as grayscale, Handlers_h as h, Handlers_height as height, Handlers_kernel as kernel, Handlers_median as median, Handlers_modulate as modulate, Handlers_negate as negate, Handlers_normalize as normalize, Handlers_pos as pos, Handlers_position as position, Handlers_q as q, Handlers_quality as quality, Handlers_resize as resize, Handlers_rotate as rotate, Handlers_s as s, Handlers_sharpen as sharpen, Handlers_threshold as threshold, Handlers_tint as tint, Handlers_trim as trim, Handlers_w as w, Handlers_width as width };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type HandlerName = keyof typeof Handlers;
|
|
104
|
+
|
|
105
|
+
interface IPXCTX {
|
|
106
|
+
sources: Record<string, Source>;
|
|
107
|
+
}
|
|
108
|
+
type IPX = (id: string, modifiers?: Partial<Record<HandlerName | "f" | "format" | "a" | "animated", string>>, requestOptions?: any) => {
|
|
109
|
+
src: () => Promise<SourceData>;
|
|
110
|
+
data: () => Promise<{
|
|
111
|
+
data: Buffer;
|
|
112
|
+
meta: ImageMeta;
|
|
113
|
+
format: string;
|
|
114
|
+
}>;
|
|
115
|
+
};
|
|
116
|
+
interface IPXOptions {
|
|
117
|
+
dir?: false | string;
|
|
118
|
+
maxAge?: number;
|
|
119
|
+
domains?: false | string[];
|
|
120
|
+
alias: Record<string, string>;
|
|
121
|
+
fetchOptions: RequestInit;
|
|
122
|
+
sharp?: SharpOptions;
|
|
123
|
+
}
|
|
124
|
+
declare function createIPX(userOptions: Partial<IPXOptions>): IPX;
|
|
125
|
+
|
|
126
|
+
interface IPXHRequest {
|
|
127
|
+
url: string;
|
|
128
|
+
headers?: Record<string, string>;
|
|
129
|
+
options?: any;
|
|
130
|
+
}
|
|
131
|
+
interface IPXHResponse {
|
|
132
|
+
statusCode: number;
|
|
133
|
+
statusMessage: string;
|
|
134
|
+
headers: Record<string, string>;
|
|
135
|
+
body: any;
|
|
136
|
+
error?: any;
|
|
137
|
+
}
|
|
138
|
+
interface MiddlewareOptions {
|
|
139
|
+
fallthrough?: boolean;
|
|
140
|
+
}
|
|
141
|
+
declare function handleRequest(request: IPXHRequest, ipx: IPX): Promise<IPXHResponse>;
|
|
142
|
+
declare function createIPXMiddleware(ipx: IPX, options?: Partial<MiddlewareOptions>): (request: IncomingMessage, res: ServerResponse, next?: ((err?: any) => void) | undefined) => Promise<void>;
|
|
143
|
+
|
|
144
|
+
export { type IPX, type IPXCTX, type IPXHRequest, type IPXHResponse, type IPXOptions, type MiddlewareOptions, type Source, type SourceData, type SourceFactory, createIPX, createIPXMiddleware, handleRequest };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Sharp, Color, KernelEnum, SharpOptions } from 'sharp';
|
|
2
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
|
+
|
|
4
|
+
interface ImageMeta {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
type: string;
|
|
8
|
+
mimeType: string;
|
|
9
|
+
}
|
|
10
|
+
interface SourceData {
|
|
11
|
+
mtime?: Date;
|
|
12
|
+
maxAge?: number;
|
|
13
|
+
getData: () => Promise<Buffer>;
|
|
14
|
+
}
|
|
15
|
+
type Source = (source: string, requestOptions?: any) => Promise<SourceData>;
|
|
16
|
+
type SourceFactory<T = Record<string, any>> = (options: T) => Source;
|
|
17
|
+
interface HandlerContext {
|
|
18
|
+
quality?: number;
|
|
19
|
+
fit?: "contain" | "cover" | "fill" | "inside" | "outside";
|
|
20
|
+
position?: number | string;
|
|
21
|
+
background?: Color;
|
|
22
|
+
enlarge?: boolean;
|
|
23
|
+
kernel?: keyof KernelEnum;
|
|
24
|
+
meta: ImageMeta;
|
|
25
|
+
}
|
|
26
|
+
interface Handler {
|
|
27
|
+
args: ((argument: string) => any)[];
|
|
28
|
+
order?: number;
|
|
29
|
+
apply: (context: HandlerContext, pipe: Sharp, ...arguments_: any[]) => any;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare const quality: Handler;
|
|
33
|
+
declare const fit: Handler;
|
|
34
|
+
declare const position: Handler;
|
|
35
|
+
declare const background: Handler;
|
|
36
|
+
declare const enlarge: Handler;
|
|
37
|
+
declare const kernel: Handler;
|
|
38
|
+
declare const width: Handler;
|
|
39
|
+
declare const height: Handler;
|
|
40
|
+
declare const resize: Handler;
|
|
41
|
+
declare const trim: Handler;
|
|
42
|
+
declare const extend: Handler;
|
|
43
|
+
declare const extract: Handler;
|
|
44
|
+
declare const rotate: Handler;
|
|
45
|
+
declare const flip: Handler;
|
|
46
|
+
declare const flop: Handler;
|
|
47
|
+
declare const sharpen: Handler;
|
|
48
|
+
declare const median: Handler;
|
|
49
|
+
declare const blur: Handler;
|
|
50
|
+
declare const flatten: Handler;
|
|
51
|
+
declare const gamma: Handler;
|
|
52
|
+
declare const negate: Handler;
|
|
53
|
+
declare const normalize: Handler;
|
|
54
|
+
declare const threshold: Handler;
|
|
55
|
+
declare const modulate: Handler;
|
|
56
|
+
declare const tint: Handler;
|
|
57
|
+
declare const grayscale: Handler;
|
|
58
|
+
declare const crop: Handler;
|
|
59
|
+
declare const q: Handler;
|
|
60
|
+
declare const b: Handler;
|
|
61
|
+
declare const w: Handler;
|
|
62
|
+
declare const h: Handler;
|
|
63
|
+
declare const s: Handler;
|
|
64
|
+
declare const pos: Handler;
|
|
65
|
+
|
|
66
|
+
declare const Handlers_b: typeof b;
|
|
67
|
+
declare const Handlers_background: typeof background;
|
|
68
|
+
declare const Handlers_blur: typeof blur;
|
|
69
|
+
declare const Handlers_crop: typeof crop;
|
|
70
|
+
declare const Handlers_enlarge: typeof enlarge;
|
|
71
|
+
declare const Handlers_extend: typeof extend;
|
|
72
|
+
declare const Handlers_extract: typeof extract;
|
|
73
|
+
declare const Handlers_fit: typeof fit;
|
|
74
|
+
declare const Handlers_flatten: typeof flatten;
|
|
75
|
+
declare const Handlers_flip: typeof flip;
|
|
76
|
+
declare const Handlers_flop: typeof flop;
|
|
77
|
+
declare const Handlers_gamma: typeof gamma;
|
|
78
|
+
declare const Handlers_grayscale: typeof grayscale;
|
|
79
|
+
declare const Handlers_h: typeof h;
|
|
80
|
+
declare const Handlers_height: typeof height;
|
|
81
|
+
declare const Handlers_kernel: typeof kernel;
|
|
82
|
+
declare const Handlers_median: typeof median;
|
|
83
|
+
declare const Handlers_modulate: typeof modulate;
|
|
84
|
+
declare const Handlers_negate: typeof negate;
|
|
85
|
+
declare const Handlers_normalize: typeof normalize;
|
|
86
|
+
declare const Handlers_pos: typeof pos;
|
|
87
|
+
declare const Handlers_position: typeof position;
|
|
88
|
+
declare const Handlers_q: typeof q;
|
|
89
|
+
declare const Handlers_quality: typeof quality;
|
|
90
|
+
declare const Handlers_resize: typeof resize;
|
|
91
|
+
declare const Handlers_rotate: typeof rotate;
|
|
92
|
+
declare const Handlers_s: typeof s;
|
|
93
|
+
declare const Handlers_sharpen: typeof sharpen;
|
|
94
|
+
declare const Handlers_threshold: typeof threshold;
|
|
95
|
+
declare const Handlers_tint: typeof tint;
|
|
96
|
+
declare const Handlers_trim: typeof trim;
|
|
97
|
+
declare const Handlers_w: typeof w;
|
|
98
|
+
declare const Handlers_width: typeof width;
|
|
99
|
+
declare namespace Handlers {
|
|
100
|
+
export { Handlers_b as b, Handlers_background as background, Handlers_blur as blur, Handlers_crop as crop, Handlers_enlarge as enlarge, Handlers_extend as extend, Handlers_extract as extract, Handlers_fit as fit, Handlers_flatten as flatten, Handlers_flip as flip, Handlers_flop as flop, Handlers_gamma as gamma, Handlers_grayscale as grayscale, Handlers_h as h, Handlers_height as height, Handlers_kernel as kernel, Handlers_median as median, Handlers_modulate as modulate, Handlers_negate as negate, Handlers_normalize as normalize, Handlers_pos as pos, Handlers_position as position, Handlers_q as q, Handlers_quality as quality, Handlers_resize as resize, Handlers_rotate as rotate, Handlers_s as s, Handlers_sharpen as sharpen, Handlers_threshold as threshold, Handlers_tint as tint, Handlers_trim as trim, Handlers_w as w, Handlers_width as width };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type HandlerName = keyof typeof Handlers;
|
|
104
|
+
|
|
105
|
+
interface IPXCTX {
|
|
106
|
+
sources: Record<string, Source>;
|
|
107
|
+
}
|
|
108
|
+
type IPX = (id: string, modifiers?: Partial<Record<HandlerName | "f" | "format" | "a" | "animated", string>>, requestOptions?: any) => {
|
|
109
|
+
src: () => Promise<SourceData>;
|
|
110
|
+
data: () => Promise<{
|
|
111
|
+
data: Buffer;
|
|
112
|
+
meta: ImageMeta;
|
|
113
|
+
format: string;
|
|
114
|
+
}>;
|
|
115
|
+
};
|
|
116
|
+
interface IPXOptions {
|
|
117
|
+
dir?: false | string;
|
|
118
|
+
maxAge?: number;
|
|
119
|
+
domains?: false | string[];
|
|
120
|
+
alias: Record<string, string>;
|
|
121
|
+
fetchOptions: RequestInit;
|
|
122
|
+
sharp?: SharpOptions;
|
|
123
|
+
}
|
|
124
|
+
declare function createIPX(userOptions: Partial<IPXOptions>): IPX;
|
|
125
|
+
|
|
126
|
+
interface IPXHRequest {
|
|
127
|
+
url: string;
|
|
128
|
+
headers?: Record<string, string>;
|
|
129
|
+
options?: any;
|
|
130
|
+
}
|
|
131
|
+
interface IPXHResponse {
|
|
132
|
+
statusCode: number;
|
|
133
|
+
statusMessage: string;
|
|
134
|
+
headers: Record<string, string>;
|
|
135
|
+
body: any;
|
|
136
|
+
error?: any;
|
|
137
|
+
}
|
|
138
|
+
interface MiddlewareOptions {
|
|
139
|
+
fallthrough?: boolean;
|
|
140
|
+
}
|
|
141
|
+
declare function handleRequest(request: IPXHRequest, ipx: IPX): Promise<IPXHResponse>;
|
|
142
|
+
declare function createIPXMiddleware(ipx: IPX, options?: Partial<MiddlewareOptions>): (request: IncomingMessage, res: ServerResponse, next?: ((err?: any) => void) | undefined) => Promise<void>;
|
|
143
|
+
|
|
144
|
+
export { type IPX, type IPXCTX, type IPXHRequest, type IPXHResponse, type IPXOptions, type MiddlewareOptions, type Source, type SourceData, type SourceFactory, createIPX, createIPXMiddleware, handleRequest };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Sharp, Color, SharpOptions } from 'sharp';
|
|
1
|
+
import { Sharp, Color, KernelEnum, SharpOptions } from 'sharp';
|
|
2
2
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
3
|
|
|
4
4
|
interface ImageMeta {
|
|
@@ -20,6 +20,7 @@ interface HandlerContext {
|
|
|
20
20
|
position?: number | string;
|
|
21
21
|
background?: Color;
|
|
22
22
|
enlarge?: boolean;
|
|
23
|
+
kernel?: keyof KernelEnum;
|
|
23
24
|
meta: ImageMeta;
|
|
24
25
|
}
|
|
25
26
|
interface Handler {
|
|
@@ -33,6 +34,7 @@ declare const fit: Handler;
|
|
|
33
34
|
declare const position: Handler;
|
|
34
35
|
declare const background: Handler;
|
|
35
36
|
declare const enlarge: Handler;
|
|
37
|
+
declare const kernel: Handler;
|
|
36
38
|
declare const width: Handler;
|
|
37
39
|
declare const height: Handler;
|
|
38
40
|
declare const resize: Handler;
|
|
@@ -76,6 +78,7 @@ declare const Handlers_gamma: typeof gamma;
|
|
|
76
78
|
declare const Handlers_grayscale: typeof grayscale;
|
|
77
79
|
declare const Handlers_h: typeof h;
|
|
78
80
|
declare const Handlers_height: typeof height;
|
|
81
|
+
declare const Handlers_kernel: typeof kernel;
|
|
79
82
|
declare const Handlers_median: typeof median;
|
|
80
83
|
declare const Handlers_modulate: typeof modulate;
|
|
81
84
|
declare const Handlers_negate: typeof negate;
|
|
@@ -94,40 +97,7 @@ declare const Handlers_trim: typeof trim;
|
|
|
94
97
|
declare const Handlers_w: typeof w;
|
|
95
98
|
declare const Handlers_width: typeof width;
|
|
96
99
|
declare namespace Handlers {
|
|
97
|
-
export {
|
|
98
|
-
Handlers_b as b,
|
|
99
|
-
Handlers_background as background,
|
|
100
|
-
Handlers_blur as blur,
|
|
101
|
-
Handlers_crop as crop,
|
|
102
|
-
Handlers_enlarge as enlarge,
|
|
103
|
-
Handlers_extend as extend,
|
|
104
|
-
Handlers_extract as extract,
|
|
105
|
-
Handlers_fit as fit,
|
|
106
|
-
Handlers_flatten as flatten,
|
|
107
|
-
Handlers_flip as flip,
|
|
108
|
-
Handlers_flop as flop,
|
|
109
|
-
Handlers_gamma as gamma,
|
|
110
|
-
Handlers_grayscale as grayscale,
|
|
111
|
-
Handlers_h as h,
|
|
112
|
-
Handlers_height as height,
|
|
113
|
-
Handlers_median as median,
|
|
114
|
-
Handlers_modulate as modulate,
|
|
115
|
-
Handlers_negate as negate,
|
|
116
|
-
Handlers_normalize as normalize,
|
|
117
|
-
Handlers_pos as pos,
|
|
118
|
-
Handlers_position as position,
|
|
119
|
-
Handlers_q as q,
|
|
120
|
-
Handlers_quality as quality,
|
|
121
|
-
Handlers_resize as resize,
|
|
122
|
-
Handlers_rotate as rotate,
|
|
123
|
-
Handlers_s as s,
|
|
124
|
-
Handlers_sharpen as sharpen,
|
|
125
|
-
Handlers_threshold as threshold,
|
|
126
|
-
Handlers_tint as tint,
|
|
127
|
-
Handlers_trim as trim,
|
|
128
|
-
Handlers_w as w,
|
|
129
|
-
Handlers_width as width,
|
|
130
|
-
};
|
|
100
|
+
export { Handlers_b as b, Handlers_background as background, Handlers_blur as blur, Handlers_crop as crop, Handlers_enlarge as enlarge, Handlers_extend as extend, Handlers_extract as extract, Handlers_fit as fit, Handlers_flatten as flatten, Handlers_flip as flip, Handlers_flop as flop, Handlers_gamma as gamma, Handlers_grayscale as grayscale, Handlers_h as h, Handlers_height as height, Handlers_kernel as kernel, Handlers_median as median, Handlers_modulate as modulate, Handlers_negate as negate, Handlers_normalize as normalize, Handlers_pos as pos, Handlers_position as position, Handlers_q as q, Handlers_quality as quality, Handlers_resize as resize, Handlers_rotate as rotate, Handlers_s as s, Handlers_sharpen as sharpen, Handlers_threshold as threshold, Handlers_tint as tint, Handlers_trim as trim, Handlers_w as w, Handlers_width as width };
|
|
131
101
|
}
|
|
132
102
|
|
|
133
103
|
type HandlerName = keyof typeof Handlers;
|
|
@@ -171,4 +141,4 @@ interface MiddlewareOptions {
|
|
|
171
141
|
declare function handleRequest(request: IPXHRequest, ipx: IPX): Promise<IPXHResponse>;
|
|
172
142
|
declare function createIPXMiddleware(ipx: IPX, options?: Partial<MiddlewareOptions>): (request: IncomingMessage, res: ServerResponse, next?: ((err?: any) => void) | undefined) => Promise<void>;
|
|
173
143
|
|
|
174
|
-
export { IPX, IPXCTX, IPXHRequest, IPXHResponse, IPXOptions, MiddlewareOptions, Source, SourceData, SourceFactory, createIPX, createIPXMiddleware, handleRequest };
|
|
144
|
+
export { type IPX, type IPXCTX, type IPXHRequest, type IPXHResponse, type IPXOptions, type MiddlewareOptions, type Source, type SourceData, type SourceFactory, createIPX, createIPXMiddleware, handleRequest };
|
package/dist/index.mjs
CHANGED
|
@@ -28,6 +28,7 @@ const Handlers = {
|
|
|
28
28
|
get grayscale () { return grayscale; },
|
|
29
29
|
get h () { return h; },
|
|
30
30
|
get height () { return height; },
|
|
31
|
+
get kernel () { return kernel; },
|
|
31
32
|
get median () { return median; },
|
|
32
33
|
get modulate () { return modulate; },
|
|
33
34
|
get negate () { return negate; },
|
|
@@ -47,6 +48,12 @@ const Handlers = {
|
|
|
47
48
|
get width () { return width; }
|
|
48
49
|
};
|
|
49
50
|
|
|
51
|
+
var __defProp = Object.defineProperty;
|
|
52
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
53
|
+
var __publicField = (obj, key, value) => {
|
|
54
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
55
|
+
return value;
|
|
56
|
+
};
|
|
50
57
|
function getEnv(name, defaultValue) {
|
|
51
58
|
return destr(process.env[name]) ?? defaultValue;
|
|
52
59
|
}
|
|
@@ -61,6 +68,11 @@ function cachedPromise(function_) {
|
|
|
61
68
|
};
|
|
62
69
|
}
|
|
63
70
|
class IPXError extends Error {
|
|
71
|
+
constructor() {
|
|
72
|
+
super(...arguments);
|
|
73
|
+
__publicField(this, "statusCode");
|
|
74
|
+
__publicField(this, "statusMessage");
|
|
75
|
+
}
|
|
64
76
|
}
|
|
65
77
|
function createError(statusMessage, statusCode, trace) {
|
|
66
78
|
const error = new IPXError(statusMessage + (trace ? ` (${trace})` : ""));
|
|
@@ -232,6 +244,12 @@ const enlarge = {
|
|
|
232
244
|
context.enlarge = true;
|
|
233
245
|
}
|
|
234
246
|
};
|
|
247
|
+
const kernel = {
|
|
248
|
+
args: [VArg],
|
|
249
|
+
apply: (context, _pipe, kernel2) => {
|
|
250
|
+
context.kernel = kernel2;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
235
253
|
const width = {
|
|
236
254
|
args: [VArg],
|
|
237
255
|
apply: (context, pipe, width2) => {
|
|
@@ -269,7 +287,8 @@ const resize = {
|
|
|
269
287
|
return pipe.resize(width2, height2, {
|
|
270
288
|
fit: context.fit,
|
|
271
289
|
position: context.position,
|
|
272
|
-
background: context.background
|
|
290
|
+
background: context.background,
|
|
291
|
+
kernel: context.kernel
|
|
273
292
|
});
|
|
274
293
|
}
|
|
275
294
|
};
|
|
@@ -409,7 +428,8 @@ const SUPPORTED_FORMATS = /* @__PURE__ */ new Set([
|
|
|
409
428
|
"avif",
|
|
410
429
|
"tiff",
|
|
411
430
|
"heif",
|
|
412
|
-
"gif"
|
|
431
|
+
"gif",
|
|
432
|
+
"heic"
|
|
413
433
|
]);
|
|
414
434
|
function createIPX(userOptions) {
|
|
415
435
|
const defaults = {
|
|
@@ -477,7 +497,7 @@ function createIPX(userOptions) {
|
|
|
477
497
|
const Sharp = await import('sharp').then(
|
|
478
498
|
(r) => r.default || r
|
|
479
499
|
);
|
|
480
|
-
let sharp = Sharp(data, { animated });
|
|
500
|
+
let sharp = Sharp(data, { animated, ...options.sharp });
|
|
481
501
|
Object.assign(sharp.options, options.sharp);
|
|
482
502
|
const handlers = Object.entries(modifiers).map(([name, arguments_]) => ({
|
|
483
503
|
handler: getHandler(name),
|
|
@@ -577,7 +597,7 @@ async function _handleRequest(request, ipx) {
|
|
|
577
597
|
}
|
|
578
598
|
res.headers["Content-Security-Policy"] = "default-src 'none'";
|
|
579
599
|
res.body = data;
|
|
580
|
-
return
|
|
600
|
+
return sanitizeReponse(res);
|
|
581
601
|
}
|
|
582
602
|
function handleRequest(request, ipx) {
|
|
583
603
|
return _handleRequest(request, ipx).catch((error) => {
|
|
@@ -586,7 +606,7 @@ function handleRequest(request, ipx) {
|
|
|
586
606
|
if (process.env.NODE_ENV !== "production" && statusCode === 500) {
|
|
587
607
|
console.error(error);
|
|
588
608
|
}
|
|
589
|
-
return
|
|
609
|
+
return sanitizeReponse({
|
|
590
610
|
statusCode,
|
|
591
611
|
statusMessage,
|
|
592
612
|
body: "IPX Error: " + error,
|
|
@@ -629,7 +649,7 @@ function autoDetectFormat(acceptHeader, animated) {
|
|
|
629
649
|
]);
|
|
630
650
|
return acceptMime?.split("/")[1] || "jpeg";
|
|
631
651
|
}
|
|
632
|
-
function
|
|
652
|
+
function sanitizeReponse(res) {
|
|
633
653
|
return {
|
|
634
654
|
statusCode: res.statusCode || 200,
|
|
635
655
|
statusMessage: res.statusMessage ? safeString(res.statusMessage) : "OK",
|
package/package.json
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ipx",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"repository": "unjs/ipx",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
-
"
|
|
9
|
-
|
|
8
|
+
"import": {
|
|
9
|
+
"types": "./dist/index.d.mts",
|
|
10
|
+
"default": "./dist/index.mjs"
|
|
11
|
+
},
|
|
12
|
+
"require": {
|
|
13
|
+
"types": "./dist/index.d.cts",
|
|
14
|
+
"default": "./dist/index.cjs"
|
|
15
|
+
}
|
|
10
16
|
}
|
|
11
17
|
},
|
|
12
18
|
"main": "./dist/index.cjs",
|
|
@@ -19,7 +25,7 @@
|
|
|
19
25
|
],
|
|
20
26
|
"scripts": {
|
|
21
27
|
"build": "unbuild",
|
|
22
|
-
"dev": "
|
|
28
|
+
"dev": "listhen -w playground",
|
|
23
29
|
"lint": "eslint --ext .ts . && prettier -c src test",
|
|
24
30
|
"lint:fix": "eslint --ext .ts . --fix && prettier -w src test",
|
|
25
31
|
"prepack": "pnpm build",
|
|
@@ -29,33 +35,31 @@
|
|
|
29
35
|
},
|
|
30
36
|
"dependencies": {
|
|
31
37
|
"@fastify/accept-negotiator": "^1.1.0",
|
|
32
|
-
"consola": "^3.
|
|
38
|
+
"consola": "^3.2.3",
|
|
33
39
|
"defu": "^6.1.2",
|
|
34
|
-
"destr": "^
|
|
40
|
+
"destr": "^2.0.1",
|
|
35
41
|
"etag": "^1.8.1",
|
|
36
42
|
"image-meta": "^0.1.1",
|
|
37
|
-
"listhen": "^1.
|
|
38
|
-
"node-fetch-native": "^1.
|
|
43
|
+
"listhen": "^1.5.5",
|
|
44
|
+
"node-fetch-native": "^1.4.0",
|
|
39
45
|
"pathe": "^1.1.1",
|
|
40
|
-
"sharp": "^0.32.
|
|
41
|
-
"ufo": "^1.1
|
|
46
|
+
"sharp": "^0.32.6",
|
|
47
|
+
"ufo": "^1.3.1",
|
|
42
48
|
"xss": "^1.0.14"
|
|
43
49
|
},
|
|
44
50
|
"devDependencies": {
|
|
45
51
|
"@types/etag": "^1.8.1",
|
|
46
52
|
"@types/is-valid-path": "^0.1.0",
|
|
47
|
-
"@vitest/coverage-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"eslint": "^8.42.0",
|
|
53
|
+
"@vitest/coverage-v8": "^0.34.6",
|
|
54
|
+
"changelogen": "^0.5.5",
|
|
55
|
+
"eslint": "^8.50.0",
|
|
51
56
|
"eslint-config-unjs": "^0.2.1",
|
|
52
|
-
"jiti": "^1.
|
|
53
|
-
"
|
|
54
|
-
"prettier": "^2.8.8",
|
|
57
|
+
"jiti": "^1.20.0",
|
|
58
|
+
"prettier": "^3.0.3",
|
|
55
59
|
"serve-handler": "^6.1.5",
|
|
56
|
-
"typescript": "^5.
|
|
57
|
-
"unbuild": "^
|
|
58
|
-
"vitest": "^0.
|
|
60
|
+
"typescript": "^5.2.2",
|
|
61
|
+
"unbuild": "^2.0.0",
|
|
62
|
+
"vitest": "^0.34.6"
|
|
59
63
|
},
|
|
60
|
-
"packageManager": "pnpm@8.
|
|
64
|
+
"packageManager": "pnpm@8.7.1"
|
|
61
65
|
}
|