ipx 4.0.0-alpha.1 → 4.0.0-beta.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 +495 -78
- package/dist/THIRD-PARTY-LICENSES.md +593 -0
- package/dist/_chunks/libs/@fastify/accept-negotiator.mjs +71 -1
- package/dist/_chunks/libs/boolbase.mjs +12 -1
- package/dist/_chunks/libs/crossws.d.mts +1 -0
- package/dist/_chunks/libs/css-select.mjs +4136 -3
- package/dist/_chunks/libs/css-tree.mjs +31045 -51
- package/dist/_chunks/libs/csso.mjs +1821 -3
- package/dist/_chunks/libs/etag.mjs +25 -1
- package/dist/_chunks/libs/h3.d.mts +3 -0
- package/dist/_chunks/libs/h3.mjs +309 -2
- package/dist/_chunks/libs/image-meta.d.mts +8 -0
- package/dist/_chunks/libs/image-meta.mjs +557 -2
- package/dist/_chunks/libs/sax.mjs +837 -10
- package/dist/_chunks/libs/svgo.mjs +5883 -11
- package/dist/_chunks/libs/ufo.mjs +34 -1
- package/dist/_chunks/node-fs.mjs +1031 -245
- package/dist/_chunks/rolldown-runtime.mjs +24 -28
- package/dist/_chunks/svgo-node.mjs +2 -10
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +3 -13
- package/dist/index.d.mts +185 -30
- package/dist/index.mjs +3 -19
- package/package.json +24 -21
|
@@ -1,37 +1,35 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
|
|
3
|
-
//#region rolldown:runtime
|
|
4
2
|
var __create = Object.create;
|
|
5
3
|
var __defProp = Object.defineProperty;
|
|
6
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
9
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
enumerable: true
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
if (symbols) {
|
|
20
|
-
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
8
|
+
var __esmMin = (fn, res, err) => () => {
|
|
9
|
+
if (err) throw err[0];
|
|
10
|
+
try {
|
|
11
|
+
return fn && (res = fn(fn = 0)), res;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw err = [e], e;
|
|
21
14
|
}
|
|
15
|
+
};
|
|
16
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
17
|
+
var __exportAll = (all, no_symbols) => {
|
|
18
|
+
let target = {};
|
|
19
|
+
for (var name in all) __defProp(target, name, {
|
|
20
|
+
get: all[name],
|
|
21
|
+
enumerable: true
|
|
22
|
+
});
|
|
23
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
22
24
|
return target;
|
|
23
25
|
};
|
|
24
26
|
var __copyProps = (to, from, except, desc) => {
|
|
25
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
27
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
28
|
+
key = keys[i];
|
|
29
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
30
|
+
get: ((k) => from[k]).bind(null, key),
|
|
31
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
32
|
+
});
|
|
35
33
|
}
|
|
36
34
|
return to;
|
|
37
35
|
};
|
|
@@ -39,8 +37,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
39
37
|
value: mod,
|
|
40
38
|
enumerable: true
|
|
41
39
|
}) : target, mod));
|
|
42
|
-
var
|
|
43
|
-
var __require = /*
|
|
44
|
-
|
|
45
|
-
//#endregion
|
|
46
|
-
export { __toESM as a, __toDynamicImportESM as i, __export as n, __require as r, __commonJSMin as t };
|
|
40
|
+
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
41
|
+
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
42
|
+
export { __commonJSMin, __esmMin, __exportAll, __require, __toCommonJS, __toESM };
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import "./libs/css-select.mjs";
|
|
3
|
-
import "./libs/boolbase.mjs";
|
|
4
|
-
import "./libs/css-tree.mjs";
|
|
5
|
-
import "./libs/csso.mjs";
|
|
6
|
-
import "./libs/sax.mjs";
|
|
7
|
-
import { t as require_svgo_node } from "./libs/svgo.mjs";
|
|
8
|
-
|
|
1
|
+
import { require_svgo_node } from "./libs/svgo.mjs";
|
|
9
2
|
export default require_svgo_node();
|
|
10
|
-
|
|
11
|
-
export { };
|
|
3
|
+
export {};
|
package/dist/cli.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {}
|
package/dist/cli.mjs
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./_chunks/
|
|
3
|
-
import { a as serveIPX, n as ipxHttpStorage, o as createIPX, t as ipxFSStorage } from "./_chunks/node-fs.mjs";
|
|
4
|
-
import "./_chunks/libs/etag.mjs";
|
|
5
|
-
import "./_chunks/libs/@fastify/accept-negotiator.mjs";
|
|
2
|
+
import { createIPX, ipxFSStorage, ipxHttpStorage, serveIPX } from "./_chunks/node-fs.mjs";
|
|
6
3
|
import { parseArgs } from "node:util";
|
|
7
|
-
|
|
8
|
-
//#region package.json
|
|
9
4
|
var name = "ipx";
|
|
10
|
-
var version = "4.0.0-
|
|
11
|
-
|
|
12
|
-
//#endregion
|
|
13
|
-
//#region src/cli.ts
|
|
5
|
+
var version = "4.0.0-beta.0";
|
|
14
6
|
const { positionals, values } = parseArgs({
|
|
15
7
|
allowPositionals: true,
|
|
16
8
|
options: {
|
|
@@ -74,6 +66,4 @@ Options:
|
|
|
74
66
|
-v, --version Show version
|
|
75
67
|
`);
|
|
76
68
|
}
|
|
77
|
-
|
|
78
|
-
//#endregion
|
|
79
|
-
export { };
|
|
69
|
+
export {};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { ImageMeta } from "./_chunks/libs/image-meta.mjs";
|
|
2
|
+
import { HTTPError } from "./_chunks/libs/h3.mjs";
|
|
1
3
|
import { NodeHttpHandler, Server, ServerOptions } from "srvx";
|
|
2
4
|
import { Color, KernelEnum, Sharp, SharpOptions } from "sharp";
|
|
3
|
-
import { ImageMeta } from "image-meta";
|
|
4
5
|
import { Config } from "svgo";
|
|
5
6
|
import { Driver, Storage } from "unstorage";
|
|
6
|
-
|
|
7
|
-
//#region src/types.d.ts
|
|
8
7
|
interface HandlerContext {
|
|
9
8
|
/**
|
|
10
9
|
* Optional quality setting for the output image, affects compression in certain formats.
|
|
@@ -36,6 +35,30 @@ interface HandlerContext {
|
|
|
36
35
|
* @optional
|
|
37
36
|
*/
|
|
38
37
|
kernel?: keyof KernelEnum;
|
|
38
|
+
/**
|
|
39
|
+
* The maximum width and height of the output image, or `false` when
|
|
40
|
+
* unlimited. Set from the `maxOutputDimension` IPX option.
|
|
41
|
+
* @optional
|
|
42
|
+
*/
|
|
43
|
+
maxOutputDimension?: number | false;
|
|
44
|
+
/**
|
|
45
|
+
* Dimensions the image is expected to have once the resize modifiers
|
|
46
|
+
* (`resize`, `width`, `height`) have been applied, recorded by those
|
|
47
|
+
* handlers after their own clamping.
|
|
48
|
+
*
|
|
49
|
+
* libvips resizes before it extends, whatever order the modifiers appear in
|
|
50
|
+
* the URL, so `extend` budgets its edges against these rather than against
|
|
51
|
+
* {@link meta}: budgeting against the source lets the two clamps stack and
|
|
52
|
+
* the canvas end up at twice `maxOutputDimension` on each axis.
|
|
53
|
+
*
|
|
54
|
+
* Undefined when no resize modifier was applied (or when nothing could be
|
|
55
|
+
* projected from it), in which case `extend` falls back to {@link meta}.
|
|
56
|
+
* @optional
|
|
57
|
+
*/
|
|
58
|
+
outputDimensions?: {
|
|
59
|
+
width?: number;
|
|
60
|
+
height?: number;
|
|
61
|
+
};
|
|
39
62
|
/**
|
|
40
63
|
* Metadata about the image being processed.
|
|
41
64
|
*/
|
|
@@ -96,8 +119,6 @@ interface IPXStorage {
|
|
|
96
119
|
*/
|
|
97
120
|
getData: (id: string, opts?: IPXStorageOptions) => MaybePromise<Buffer | ArrayBuffer | undefined>;
|
|
98
121
|
}
|
|
99
|
-
//#endregion
|
|
100
|
-
//#region src/ipx.d.ts
|
|
101
122
|
type IPXSourceMeta = {
|
|
102
123
|
/**
|
|
103
124
|
* The modification time of the source. Used for cache validation.
|
|
@@ -110,6 +131,7 @@ type IPXSourceMeta = {
|
|
|
110
131
|
*/
|
|
111
132
|
maxAge?: number;
|
|
112
133
|
};
|
|
134
|
+
type FlagModifier = true | "true" | "";
|
|
113
135
|
type FormatModifier = "jpeg" | "jpg" | "png" | "webp" | "avif" | "gif" | "heif" | "tiff" | "auto" | (string & {});
|
|
114
136
|
interface IPXModifiers {
|
|
115
137
|
format: FormatModifier;
|
|
@@ -123,28 +145,39 @@ interface IPXModifiers {
|
|
|
123
145
|
b: string;
|
|
124
146
|
position: string;
|
|
125
147
|
pos: string;
|
|
126
|
-
enlarge:
|
|
148
|
+
enlarge: FlagModifier;
|
|
127
149
|
kernel: "nearest" | "cubic" | "mitchell" | "lanczos2" | "lanczos3" | (string & {});
|
|
128
150
|
trim: number | string;
|
|
129
151
|
extend: string;
|
|
130
152
|
extract: string;
|
|
131
153
|
crop: string;
|
|
132
154
|
rotate: number | string;
|
|
133
|
-
|
|
134
|
-
|
|
155
|
+
autoorient: FlagModifier;
|
|
156
|
+
flip: FlagModifier;
|
|
157
|
+
flop: FlagModifier;
|
|
135
158
|
sharpen: number | string;
|
|
136
159
|
median: number | string;
|
|
137
160
|
blur: number | string;
|
|
138
|
-
|
|
161
|
+
dilate: number | string;
|
|
162
|
+
erode: number | string;
|
|
163
|
+
clahe: number | string;
|
|
164
|
+
flatten: FlagModifier;
|
|
165
|
+
unflatten: FlagModifier;
|
|
139
166
|
gamma: string;
|
|
140
|
-
negate:
|
|
141
|
-
normalize:
|
|
167
|
+
negate: FlagModifier | string;
|
|
168
|
+
normalize: FlagModifier | string;
|
|
142
169
|
threshold: number | string;
|
|
170
|
+
linear: string;
|
|
143
171
|
modulate: string;
|
|
172
|
+
brightness: number | string;
|
|
173
|
+
saturation: number | string;
|
|
174
|
+
hue: number | string;
|
|
175
|
+
lightness: number | string;
|
|
176
|
+
opacity: number | string;
|
|
144
177
|
tint: number | string;
|
|
145
|
-
grayscale:
|
|
146
|
-
animated:
|
|
147
|
-
a:
|
|
178
|
+
grayscale: FlagModifier;
|
|
179
|
+
animated: FlagModifier;
|
|
180
|
+
a: FlagModifier;
|
|
148
181
|
width: string | number;
|
|
149
182
|
w: string | number;
|
|
150
183
|
height: string | number;
|
|
@@ -181,6 +214,26 @@ type IPXOptions = {
|
|
|
181
214
|
* @optional
|
|
182
215
|
*/
|
|
183
216
|
maxAge?: number;
|
|
217
|
+
/**
|
|
218
|
+
* Maximum width and height (in pixels) of the output image.
|
|
219
|
+
*
|
|
220
|
+
* Modifiers are user input and sharp's `limitInputPixels` only bounds the
|
|
221
|
+
* *input*, so without this limit a request such as
|
|
222
|
+
* `/enlarge,s_20000x20000/img.jpg` or `/extend_10000_10000_10000_10000/img.jpg`
|
|
223
|
+
* makes sharp allocate a multi-gigabyte output buffer from a tiny source
|
|
224
|
+
* image, which is an easy way to exhaust the server memory.
|
|
225
|
+
*
|
|
226
|
+
* Requested `width`, `height`, `resize` dimensions are clamped to this value
|
|
227
|
+
* (preserving the requested aspect ratio) and `extend` edges are clamped so
|
|
228
|
+
* that the extended canvas stays within it.
|
|
229
|
+
*
|
|
230
|
+
* Set to `false` to disable the limit (only safe when modifiers come from a
|
|
231
|
+
* trusted source).
|
|
232
|
+
*
|
|
233
|
+
* @default 8192
|
|
234
|
+
* @optional
|
|
235
|
+
*/
|
|
236
|
+
maxOutputDimension?: number | false;
|
|
184
237
|
/**
|
|
185
238
|
* A mapping of URL aliases to their corresponding URLs, used to simplify resource identifiers.
|
|
186
239
|
* @optional
|
|
@@ -201,10 +254,28 @@ type IPXOptions = {
|
|
|
201
254
|
*/
|
|
202
255
|
httpStorage?: IPXStorage;
|
|
203
256
|
/**
|
|
204
|
-
*
|
|
257
|
+
* Options for SVG images, which are processed by SVGO instead of Sharp.
|
|
205
258
|
* @optional
|
|
206
259
|
*/
|
|
207
|
-
|
|
260
|
+
svg?: {
|
|
261
|
+
/**
|
|
262
|
+
* Configuration for the SVGO library used to optimize SVG images.
|
|
263
|
+
*
|
|
264
|
+
* SVGO's `preset-default` is applied unless custom `plugins` are configured.
|
|
265
|
+
* Set to `false` to disable optimization. Sanitization is applied either way.
|
|
266
|
+
* @optional
|
|
267
|
+
*/
|
|
268
|
+
optimize?: false | Config;
|
|
269
|
+
/**
|
|
270
|
+
* Disable SVG sanitization.
|
|
271
|
+
*
|
|
272
|
+
* Sanitized SVG images cannot execute scripts. Only disable this if all sources
|
|
273
|
+
* are fully trusted, as it allows serving SVG images with XSS payloads.
|
|
274
|
+
* @default false
|
|
275
|
+
* @optional
|
|
276
|
+
*/
|
|
277
|
+
unsafeSkipSanitize?: boolean;
|
|
278
|
+
};
|
|
208
279
|
};
|
|
209
280
|
/**
|
|
210
281
|
* Creates an IPX image processing instance with the specified options.
|
|
@@ -213,17 +284,63 @@ type IPXOptions = {
|
|
|
213
284
|
* @throws {Error} If critical options such as storage are missing or incorrectly configured.
|
|
214
285
|
*/
|
|
215
286
|
declare function createIPX(userOptions: IPXOptions): IPX;
|
|
216
|
-
//#endregion
|
|
217
|
-
//#region src/server.d.ts
|
|
218
287
|
type FetchHandler = (request: Request | string | URL) => Response | Promise<Response>;
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
288
|
+
interface IPXHandlerOptions {
|
|
289
|
+
/**
|
|
290
|
+
* Custom URL parser to extract the resource id and modifiers from the request URL.
|
|
291
|
+
* Can be async.
|
|
292
|
+
*
|
|
293
|
+
* Receives the raw (absolute, still percent-encoded) request URL, so parsers can
|
|
294
|
+
* decode it themselves without going through h3's normalization.
|
|
295
|
+
*
|
|
296
|
+
* Defaults to {@link parseIPXURL} which handles URLs in the form `/<modifiers>/<id>`.
|
|
297
|
+
*
|
|
298
|
+
* Returned values are escaped (control characters) by the handler, so custom parsers
|
|
299
|
+
* do not need to escape them. This is not an access check: exactly as with the default
|
|
300
|
+
* parser, what the resulting `id` is allowed to resolve to is enforced by the storage
|
|
301
|
+
* layer. Throw an `HTTPError` to reject a request with a specific status code.
|
|
302
|
+
*
|
|
303
|
+
* @optional
|
|
304
|
+
*/
|
|
305
|
+
parseURL?: IPXURLParser;
|
|
306
|
+
}
|
|
307
|
+
declare function createIPXFetchHandler(ipx: IPX, opts?: IPXHandlerOptions): FetchHandler;
|
|
308
|
+
declare function createIPXNodeHandler(ipx: IPX, opts?: IPXHandlerOptions): NodeHttpHandler;
|
|
309
|
+
declare function serveIPX(ipx: IPX, opts?: Omit<ServerOptions, "fetch"> & IPXHandlerOptions): Server;
|
|
310
|
+
interface IPXParsedURL {
|
|
311
|
+
/**
|
|
312
|
+
* The identifier of the source image (path or URL, depending on the storage).
|
|
313
|
+
*/
|
|
314
|
+
id: string;
|
|
315
|
+
/**
|
|
316
|
+
* Modifiers to apply, keyed by modifier name. See {@link IPXModifiers}.
|
|
317
|
+
*
|
|
318
|
+
* Values are coerced to strings. Use `""` (or `undefined`) for valueless
|
|
319
|
+
* modifiers such as `grayscale`.
|
|
320
|
+
*/
|
|
321
|
+
modifiers: Record<string, string | number | boolean | undefined>;
|
|
322
|
+
}
|
|
323
|
+
type IPXURLParser = (url: string) => IPXParsedURL | Promise<IPXParsedURL>;
|
|
324
|
+
/**
|
|
325
|
+
* Default IPX URL parser, handling URLs in the form `/<modifiers>/<id>`.
|
|
326
|
+
*
|
|
327
|
+
* Use `_` as the modifiers segment to apply none (`/_/image.png`).
|
|
328
|
+
*
|
|
329
|
+
* @param {string} url - The raw (absolute) request URL.
|
|
330
|
+
* @returns {IPXParsedURL} The parsed resource id and modifiers. See {@link IPXParsedURL}.
|
|
331
|
+
* @throws {HTTPError} If the modifiers segment is missing.
|
|
332
|
+
*/
|
|
333
|
+
declare function parseIPXURL(url: string): IPXParsedURL;
|
|
224
334
|
type HTTPStorageOptions = {
|
|
225
335
|
/**
|
|
226
336
|
* Custom options for fetch operations, such as headers or method overrides.
|
|
337
|
+
*
|
|
338
|
+
* Redirects are followed manually (one hop at a time) so that each redirect target
|
|
339
|
+
* can be re-validated against the {@link HTTPStorageOptions.domains} allowlist
|
|
340
|
+
* (and {@link HTTPStorageOptions.blockPrivateIPs} when enabled).
|
|
341
|
+
* Explicitly setting `redirect` here opts out of this protection: the value is passed
|
|
342
|
+
* to `fetch` as-is and redirect targets are **not** validated (a redirect to an
|
|
343
|
+
* internal address is then possible: SSRF).
|
|
227
344
|
* @optional
|
|
228
345
|
*/
|
|
229
346
|
fetchOptions?: RequestInit;
|
|
@@ -234,6 +351,11 @@ type HTTPStorageOptions = {
|
|
|
234
351
|
maxAge?: number;
|
|
235
352
|
/**
|
|
236
353
|
* Whitelist of domains from which resource fetching is allowed. Can be a single string or an array of strings.
|
|
354
|
+
*
|
|
355
|
+
* Only `http:` and `https:` URLs are allowed. Redirects are followed only within this
|
|
356
|
+
* allowlist (up to 3 hops): a redirect to a host that is not listed is rejected with
|
|
357
|
+
* `403 IPX_FORBIDDEN_HOST`, so an allowlisted host cannot bounce IPX to an internal
|
|
358
|
+
* address. Hosts that redirect to a CDN must have the CDN hostname listed here too.
|
|
237
359
|
* @optional
|
|
238
360
|
*/
|
|
239
361
|
domains?: string | string[];
|
|
@@ -247,6 +369,22 @@ type HTTPStorageOptions = {
|
|
|
247
369
|
* @optional
|
|
248
370
|
*/
|
|
249
371
|
ignoreCacheControl?: boolean;
|
|
372
|
+
/**
|
|
373
|
+
* If set to true, reject URLs whose host is (or resolves to) a non-public IP address
|
|
374
|
+
* with `403 IPX_FORBIDDEN_IP`. Checked for the requested URL and for every redirect hop.
|
|
375
|
+
*
|
|
376
|
+
* This is **defense in depth**, not the primary access control: the
|
|
377
|
+
* {@link HTTPStorageOptions.domains} allowlist is. It only helps when an allowlisted
|
|
378
|
+
* (or, with `allowAllDomains`, arbitrary) hostname points at loopback, link-local
|
|
379
|
+
* (`169.254.169.254`, the cloud metadata service), RFC1918, CGNAT, unique-local or
|
|
380
|
+
* otherwise non-public space.
|
|
381
|
+
*
|
|
382
|
+
* Disabled by default because many legitimate deployments fetch from in-cluster origins
|
|
383
|
+
* (internal object storage, sidecars, `localhost` during development), which this blocks.
|
|
384
|
+
* @optional
|
|
385
|
+
* @default false
|
|
386
|
+
*/
|
|
387
|
+
blockPrivateIPs?: boolean;
|
|
250
388
|
};
|
|
251
389
|
/**
|
|
252
390
|
* Creates an HTTP storage handler for IPX that fetches image data from external URLs.
|
|
@@ -257,8 +395,6 @@ type HTTPStorageOptions = {
|
|
|
257
395
|
* @throws {H3Error} If validation of the requested URL fails due to a missing hostname or denied host access. See {@link H3Error}.
|
|
258
396
|
*/
|
|
259
397
|
declare function ipxHttpStorage(_options?: HTTPStorageOptions): IPXStorage;
|
|
260
|
-
//#endregion
|
|
261
|
-
//#region src/storage/node-fs.d.ts
|
|
262
398
|
type NodeFSSOptions = {
|
|
263
399
|
/**
|
|
264
400
|
* The directory or list of directories from which to serve files. If not specified, the current directory is used by default.
|
|
@@ -266,10 +402,32 @@ type NodeFSSOptions = {
|
|
|
266
402
|
*/
|
|
267
403
|
dir?: string | string[];
|
|
268
404
|
/**
|
|
269
|
-
*
|
|
405
|
+
* `max-age`, in seconds, reported for files served from this storage. Used for the
|
|
406
|
+
* `cache-control` header. Falls back to the IPX-wide `maxAge` (default 60) when unset.
|
|
407
|
+
*
|
|
408
|
+
* `0` is meaningful and is passed through as-is — it disables caching rather than
|
|
409
|
+
* falling back to the default.
|
|
270
410
|
* @optional
|
|
271
411
|
*/
|
|
272
412
|
maxAge?: number;
|
|
413
|
+
/**
|
|
414
|
+
* If set to true, a symlink inside {@link NodeFSSOptions.dir} may resolve to a file outside
|
|
415
|
+
* of it. By default such files are rejected with `403 IPX_FORBIDDEN_SYMLINK`, since the
|
|
416
|
+
* lexical `../` check alone says nothing about where a path physically ends up.
|
|
417
|
+
*
|
|
418
|
+
* Symlinks that stay inside `dir` are always followed, whatever this is set to.
|
|
419
|
+
*
|
|
420
|
+
* This is **defense in depth**, not a fix for a remotely reachable hole: planting a symlink
|
|
421
|
+
* in the served directory already requires a symlink-create or arbitrary-write primitive
|
|
422
|
+
* there, and the served filesystem is assumed to be trusted. Comparable static file servers
|
|
423
|
+
* (`express.static`, nginx with `disable_symlinks off`) follow symlinks by default too.
|
|
424
|
+
*
|
|
425
|
+
* Enable it for the deployments where symlinking assets into the served directory is
|
|
426
|
+
* deliberate — monorepo `public/` layouts, CI artifact linking, Docker layer tricks.
|
|
427
|
+
* @optional
|
|
428
|
+
* @default false
|
|
429
|
+
*/
|
|
430
|
+
allowSymlinksOutsideDir?: boolean;
|
|
273
431
|
};
|
|
274
432
|
/**
|
|
275
433
|
* Creates a file system storage handler for IPX that allows images to be served from local directories specified in the options.
|
|
@@ -280,8 +438,6 @@ type NodeFSSOptions = {
|
|
|
280
438
|
* @throws {H3Error} If there is a problem accessing the file system module or resolving/reading files. See {@link H3Error}.
|
|
281
439
|
*/
|
|
282
440
|
declare function ipxFSStorage(_options?: NodeFSSOptions): IPXStorage;
|
|
283
|
-
//#endregion
|
|
284
|
-
//#region src/storage/unstorage.d.ts
|
|
285
441
|
type UnstorageIPXStorageOptions = {
|
|
286
442
|
/**
|
|
287
443
|
* Optional prefix to be placed in front of each storage key, which can help to name or categorise stored items.
|
|
@@ -299,5 +455,4 @@ type UnstorageIPXStorageOptions = {
|
|
|
299
455
|
* @throws {H3Error} If there is a problem retrieving or converting the storage data, detailed error information is thrown. See {@link H3Error}.
|
|
300
456
|
*/
|
|
301
457
|
declare function unstorageToIPXStorage(storage: Storage | Driver, _options?: UnstorageIPXStorageOptions | string): IPXStorage;
|
|
302
|
-
|
|
303
|
-
export { type HTTPStorageOptions, type Handler, type HandlerContext, type IPX, type IPXModifiers, type IPXOptions, type IPXStorage, type IPXStorageMeta, type IPXStorageOptions, type NodeFSSOptions, type UnstorageIPXStorageOptions, createIPX, createIPXFetchHandler, createIPXNodeHandler, ipxFSStorage, ipxHttpStorage, serveIPX, unstorageToIPXStorage };
|
|
458
|
+
export { HTTPError, type HTTPStorageOptions, type Handler, type HandlerContext, type IPX, type IPXHandlerOptions, type IPXModifiers, type IPXOptions, type IPXParsedURL, type IPXStorage, type IPXStorageMeta, type IPXStorageOptions, type IPXURLParser, type NodeFSSOptions, type UnstorageIPXStorageOptions, createIPX, createIPXFetchHandler, createIPXNodeHandler, ipxFSStorage, ipxHttpStorage, parseIPXURL, serveIPX, unstorageToIPXStorage };
|
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
import "./_chunks/
|
|
2
|
-
import {
|
|
3
|
-
import { a as serveIPX, i as createIPXNodeHandler, n as ipxHttpStorage, o as createIPX, r as createIPXFetchHandler, t as ipxFSStorage } from "./_chunks/node-fs.mjs";
|
|
4
|
-
import "./_chunks/libs/etag.mjs";
|
|
5
|
-
import "./_chunks/libs/@fastify/accept-negotiator.mjs";
|
|
6
|
-
|
|
7
|
-
//#region src/storage/unstorage.ts
|
|
8
|
-
/**
|
|
9
|
-
* Adapts an Unstorage driver or storage system to comply with the IPXStorage interface required by IPX.
|
|
10
|
-
* This allows various Unstorage-compatible storage systems to be used to manage image data with IPX.
|
|
11
|
-
*
|
|
12
|
-
* @param {Storage | Driver} storage - The Unstorage driver or storage instance to adapt. See {@link Storage} and {@link Driver}.
|
|
13
|
-
* @param {UnstorageIPXStorageOptions | string} [_options={}] - Configuration options for the adapter, which can be a simple string prefix or an options object. See {@link UnstorageIPXStorageOptions}.
|
|
14
|
-
* @returns {IPXStorage}. An IPXStorage compliant object that implements the necessary methods to interact with the provided unstorage driver or storage system. See {@link IPXStorage}.
|
|
15
|
-
* @throws {H3Error} If there is a problem retrieving or converting the storage data, detailed error information is thrown. See {@link H3Error}.
|
|
16
|
-
*/
|
|
1
|
+
import { HTTPError } from "./_chunks/libs/h3.mjs";
|
|
2
|
+
import { createIPX, createIPXFetchHandler, createIPXNodeHandler, ipxFSStorage, ipxHttpStorage, parseIPXURL, serveIPX } from "./_chunks/node-fs.mjs";
|
|
17
3
|
function unstorageToIPXStorage(storage, _options = {}) {
|
|
18
4
|
const options = typeof _options === "string" ? { prefix: _options } : _options;
|
|
19
5
|
const resolveKey = (id) => options.prefix ? `${options.prefix}:${id}` : id;
|
|
@@ -43,6 +29,4 @@ function unstorageToIPXStorage(storage, _options = {}) {
|
|
|
43
29
|
}
|
|
44
30
|
};
|
|
45
31
|
}
|
|
46
|
-
|
|
47
|
-
//#endregion
|
|
48
|
-
export { createIPX, createIPXFetchHandler, createIPXNodeHandler, ipxFSStorage, ipxHttpStorage, serveIPX, unstorageToIPXStorage };
|
|
32
|
+
export { HTTPError, createIPX, createIPXFetchHandler, createIPXNodeHandler, ipxFSStorage, ipxHttpStorage, parseIPXURL, serveIPX, unstorageToIPXStorage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ipx",
|
|
3
|
-
"version": "4.0.0-
|
|
3
|
+
"version": "4.0.0-beta.1",
|
|
4
4
|
"description": "High performance, secure and easy-to-use image optimizer.",
|
|
5
5
|
"repository": "unjs/ipx",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,40 +19,40 @@
|
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "obuild",
|
|
22
|
+
"gen:operations": "node ./scripts/gen-operations.ts",
|
|
22
23
|
"ipx": "node ./src/cli.ts",
|
|
23
|
-
"lint": "eslint . && prettier -c src test",
|
|
24
|
-
"lint:fix": "automd && eslint . --fix && prettier -w src test",
|
|
24
|
+
"lint": "eslint . && prettier -c src test scripts automd.config.ts",
|
|
25
|
+
"lint:fix": "automd && eslint . --fix && prettier -w src test scripts automd.config.ts",
|
|
25
26
|
"prepack": "pnpm build",
|
|
26
|
-
"release": "pnpm test && pnpm build && changelogen --release --prerelease --publish --
|
|
27
|
+
"release": "pnpm test && pnpm build && changelogen --release --prerelease --push && npm publish --tag latest",
|
|
27
28
|
"start": "node bin/ipx.js",
|
|
28
29
|
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
|
|
29
30
|
"test:types": "tsc --noEmit"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"srvx": "^0.9.7"
|
|
33
|
+
"sharp": "^0.35.3",
|
|
34
|
+
"srvx": "^0.12.4"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@fastify/accept-negotiator": "^2.0.1",
|
|
38
38
|
"@types/etag": "^1.8.4",
|
|
39
39
|
"@types/is-valid-path": "^0.1.2",
|
|
40
|
-
"@vitest/coverage-v8": "^4.
|
|
41
|
-
"automd": "^0.4.
|
|
40
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
41
|
+
"automd": "^0.4.3",
|
|
42
42
|
"changelogen": "^0.6.2",
|
|
43
|
-
"eslint": "^
|
|
44
|
-
"eslint-config-unjs": "^0.
|
|
43
|
+
"eslint": "^10.8.0",
|
|
44
|
+
"eslint-config-unjs": "^0.6.2",
|
|
45
45
|
"etag": "^1.8.1",
|
|
46
|
-
"h3": "
|
|
46
|
+
"h3": "2.0.1-rc.26",
|
|
47
47
|
"image-meta": "^0.2.2",
|
|
48
|
-
"obuild": "^0.4.
|
|
49
|
-
"oxc-minify": "
|
|
50
|
-
"prettier": "^3.
|
|
51
|
-
"svgo": "^4.0.
|
|
52
|
-
"typescript": "^
|
|
53
|
-
"ufo": "^1.6.
|
|
54
|
-
"unstorage": "^1.17.
|
|
55
|
-
"vitest": "^4.
|
|
48
|
+
"obuild": "^0.4.38",
|
|
49
|
+
"oxc-minify": ">=0.141.0",
|
|
50
|
+
"prettier": "^3.9.6",
|
|
51
|
+
"svgo": "^4.0.2",
|
|
52
|
+
"typescript": "^6",
|
|
53
|
+
"ufo": "^1.6.4",
|
|
54
|
+
"unstorage": "^1.17.5",
|
|
55
|
+
"vitest": "^4.1.10"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"unstorage": "*"
|
|
@@ -62,5 +62,8 @@
|
|
|
62
62
|
"optional": true
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
|
-
"
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": "^20.16.0 || >=22.3.0"
|
|
67
|
+
},
|
|
68
|
+
"packageManager": "pnpm@11.17.0"
|
|
66
69
|
}
|