image-renditions 0.1.0 → 0.3.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/README.md +193 -42
- package/dist/catalog-D11xkViN.d.mts +130 -0
- package/dist/fs.d.mts +2 -2
- package/dist/fs.mjs +1 -1
- package/dist/h3.d.mts +3 -3
- package/dist/h3.mjs +1 -1
- package/dist/{handler-BHMwNZnI.mjs → handler-D5toFJ55.mjs} +12 -10
- package/dist/{handler-BFV_vIr4.d.mts → handler-RAQFWtrg.d.mts} +41 -21
- package/dist/hash-CHipV1N6.mjs +16 -0
- package/dist/img-attrs-BoCAHpl5.mjs +14 -0
- package/dist/index.d.mts +4 -6
- package/dist/index.mjs +63 -19
- package/dist/nuxt/runtime.d.mts +37 -11
- package/dist/nuxt/runtime.mjs +67 -16
- package/dist/nuxt.d.mts +11 -1
- package/dist/nuxt.mjs +18 -3
- package/dist/processor-DvyPs-OZ.d.mts +22 -0
- package/dist/{recipe-Je9DxqO1.d.mts → recipe-BT8D60Qb.d.mts} +11 -5
- package/dist/{recipe-DmOhQJWE.mjs → recipe-BavgOq0b.mjs} +7 -6
- package/dist/s3.d.mts +8 -34
- package/dist/s3.mjs +8 -7
- package/dist/scopes-C1kzqQHz.mjs +22 -0
- package/dist/server.d.mts +3 -3
- package/dist/server.mjs +37 -14
- package/dist/sharp.d.mts +16 -4
- package/dist/sharp.mjs +86 -24
- package/dist/{stores-DFDRMZcC.d.mts → stores-P-TUmax4.d.mts} +1 -1
- package/dist/{url-BIvAw2BR.mjs → url-C6PtYIEf.mjs} +11 -15
- package/dist/{url-BByyAbmB.d.mts → url-DoJdUx9J.d.mts} +2 -10
- package/package.json +5 -1
- package/dist/catalog-CSnosQ1L.d.mts +0 -64
- package/dist/processor-_xuwB7Aa.d.mts +0 -14
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import { i as formatExtensions
|
|
1
|
+
import { i as formatExtensions } from "./recipe-BavgOq0b.mjs";
|
|
2
2
|
import { n as isSafePath, r as isSafeScope, t as encodePath } from "./path-hNFUjCbA.mjs";
|
|
3
|
-
import { sha256 } from "@noble/hashes/sha2.js";
|
|
4
|
-
import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
5
|
-
//#region src/hash.ts
|
|
6
|
-
/** Length of a recipe hash in hex digits, which keeps 128 bits of SHA-256. */
|
|
7
|
-
const RECIPE_HASH_LENGTH = 32;
|
|
8
|
-
/** Identifies a recipe by the truncated SHA-256 of its canonical serialization. */
|
|
9
|
-
function hashRecipe(recipe) {
|
|
10
|
-
return bytesToHex(sha256(utf8ToBytes(serializeRecipe(recipe)))).slice(0, 32);
|
|
11
|
-
}
|
|
12
|
-
//#endregion
|
|
13
3
|
//#region src/url.ts
|
|
14
4
|
/** Version segment of the rendition URL format this library builds and parses. */
|
|
15
5
|
const URL_FORMAT_VERSION = "v1";
|
|
@@ -26,7 +16,8 @@ function formatRenditionPath(basePath, { scope, label, hash, format, path }) {
|
|
|
26
16
|
const extension = formatExtensions[format];
|
|
27
17
|
if (!isSafeLabel(label) || !isHash(hash) || !extension) throw new RangeError(`Invalid rendition variant "${label}.${hash}.${extension ?? format}".`);
|
|
28
18
|
if (!isSafePath(path)) throw new RangeError(`Unsafe rendition source path "${path}".`);
|
|
29
|
-
|
|
19
|
+
const scopePrefix = scope === void 0 ? "" : `${scope}/`;
|
|
20
|
+
return `${basePath}/${URL_FORMAT_VERSION}/${scopePrefix}${label}.${hash}.${extension}/${encodePath(path)}`;
|
|
30
21
|
}
|
|
31
22
|
/**
|
|
32
23
|
* Parses the path of a rendition URL, ignoring any query string.
|
|
@@ -34,7 +25,7 @@ function formatRenditionPath(basePath, { scope, label, hash, format, path }) {
|
|
|
34
25
|
* Returns `undefined` for a path outside `basePath`, another URL format version, or malformed or unsafe parts.
|
|
35
26
|
*/
|
|
36
27
|
function parseRenditionPath(basePath, url) {
|
|
37
|
-
const prefix = `${basePath}
|
|
28
|
+
const prefix = `${basePath}/${URL_FORMAT_VERSION}/`;
|
|
38
29
|
const pathname = url.split("?", 1)[0];
|
|
39
30
|
if (!pathname.startsWith(prefix)) return;
|
|
40
31
|
const parts = pathname.slice(prefix.length).split("/");
|
|
@@ -67,8 +58,13 @@ const formats = Object.keys(formatExtensions);
|
|
|
67
58
|
function isSafeLabel(label) {
|
|
68
59
|
return /^[\w@.-]{1,64}$/.test(label);
|
|
69
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Checks that a recipe hash is 1 to 64 ASCII letters, digits, `_` or `-`, which need no encoding in a URL or a storage key.
|
|
63
|
+
*
|
|
64
|
+
* The grammar does not fix the format of hashes, so a hash the catalog cannot produce is looked up as a published rendition instead of making the URL malformed.
|
|
65
|
+
*/
|
|
70
66
|
function isHash(hash) {
|
|
71
|
-
return
|
|
67
|
+
return /^[\w-]{1,64}$/.test(hash);
|
|
72
68
|
}
|
|
73
69
|
function decodeSegment(segment) {
|
|
74
70
|
try {
|
|
@@ -78,4 +74,4 @@ function decodeSegment(segment) {
|
|
|
78
74
|
}
|
|
79
75
|
}
|
|
80
76
|
//#endregion
|
|
81
|
-
export { parseRenditionPath as
|
|
77
|
+
export { parseRenditionPath as i, assertBasePath as n, formatRenditionPath as r, DEFAULT_BASE_PATH as t };
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as RenditionFormat } from "./recipe-BT8D60Qb.mjs";
|
|
2
2
|
//#region src/url.d.ts
|
|
3
|
-
/** Version segment of the rendition URL format this library builds and parses. */
|
|
4
|
-
declare const URL_FORMAT_VERSION = "v1";
|
|
5
3
|
/** Mount path of the rendition handler unless a catalog sets another one. */
|
|
6
4
|
declare const DEFAULT_BASE_PATH = "/_renditions";
|
|
7
5
|
/** Parts of a rendition URL. */
|
|
@@ -28,11 +26,5 @@ declare function formatRenditionPath(basePath: string, { scope, label, hash, for
|
|
|
28
26
|
* Returns `undefined` for a path outside `basePath`, another URL format version, or malformed or unsafe parts.
|
|
29
27
|
*/
|
|
30
28
|
declare function parseRenditionPath(basePath: string, url: string): RenditionAddress | undefined;
|
|
31
|
-
/**
|
|
32
|
-
* Checks that a base path is absolute, has no trailing slash and needs no URL encoding.
|
|
33
|
-
*
|
|
34
|
-
* @throws {RangeError} When the base path is invalid.
|
|
35
|
-
*/
|
|
36
|
-
declare function assertBasePath(basePath: string): void;
|
|
37
29
|
//#endregion
|
|
38
|
-
export {
|
|
30
|
+
export { parseRenditionPath as i, RenditionAddress as n, formatRenditionPath as r, DEFAULT_BASE_PATH as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "image-renditions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "On-demand image transformations that persist every result to durable storage and keep app servers stateless.",
|
|
5
5
|
"homepage": "https://github.com/IlyaSemenov/image-renditions#readme",
|
|
6
6
|
"bugs": "https://github.com/IlyaSemenov/image-renditions/issues",
|
|
@@ -64,12 +64,16 @@
|
|
|
64
64
|
"vue": "^3.5.44"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
+
"@aws-sdk/client-s3": "^3.1150.0",
|
|
67
68
|
"h3": "^1.15.0 || ^2.0.0",
|
|
68
69
|
"nuxt": "^4.0.0",
|
|
69
70
|
"sharp": "^0.35.0",
|
|
70
71
|
"vue": "^3.5.0"
|
|
71
72
|
},
|
|
72
73
|
"peerDependenciesMeta": {
|
|
74
|
+
"@aws-sdk/client-s3": {
|
|
75
|
+
"optional": true
|
|
76
|
+
},
|
|
73
77
|
"h3": {
|
|
74
78
|
"optional": true
|
|
75
79
|
},
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { l as SourcePolicy, r as Recipe, s as RenditionOptions } from "./recipe-Je9DxqO1.mjs";
|
|
2
|
-
//#region src/catalog.d.ts
|
|
3
|
-
/** Named transformation in a catalog. */
|
|
4
|
-
interface PresetDefinition extends RenditionOptions {
|
|
5
|
-
/** Pixel densities to render, as multipliers of `width` and `height`; defaults to `[1]`. */
|
|
6
|
-
densities?: readonly number[];
|
|
7
|
-
}
|
|
8
|
-
/** Shared configuration of renditions, imported by both the client and the server. */
|
|
9
|
-
interface CatalogDefinition<Name extends string = string> {
|
|
10
|
-
/** Path the rendition handler is mounted at, `/_renditions` by default. */
|
|
11
|
-
basePath?: string;
|
|
12
|
-
/** Bumping it gives every variant a new hash, so every rendition is generated again. */
|
|
13
|
-
pipelineVersion?: number;
|
|
14
|
-
/** Options of every preset; a preset overrides them field by field. */
|
|
15
|
-
defaults?: PresetDefinition;
|
|
16
|
-
/** How special kinds of sources are rendered. */
|
|
17
|
-
sources?: Partial<SourcePolicy>;
|
|
18
|
-
presets: Record<Name, PresetDefinition>;
|
|
19
|
-
}
|
|
20
|
-
/** One density of a preset, which is a separate recipe with its own hash. */
|
|
21
|
-
interface RenditionVariant {
|
|
22
|
-
readonly preset: string;
|
|
23
|
-
readonly density: number;
|
|
24
|
-
/** Readable URL label, such as `avatar` or `avatar@2x`. */
|
|
25
|
-
readonly label: string;
|
|
26
|
-
readonly recipe: Recipe;
|
|
27
|
-
readonly hash: string;
|
|
28
|
-
}
|
|
29
|
-
/** Source a rendition is made from. */
|
|
30
|
-
interface RenditionTarget {
|
|
31
|
-
/** Application-defined space of the path, such as a tenant; omitted when the application has one space. */
|
|
32
|
-
scope?: string;
|
|
33
|
-
/** Logical source path inside the scope. */
|
|
34
|
-
path: string;
|
|
35
|
-
}
|
|
36
|
-
/** Validated catalog with its variants and URL builders. */
|
|
37
|
-
interface Catalog<Name extends string = string> {
|
|
38
|
-
readonly basePath: string;
|
|
39
|
-
readonly presets: readonly Name[];
|
|
40
|
-
/** Variants of a preset ordered by density. */
|
|
41
|
-
variants(preset: Name): readonly RenditionVariant[];
|
|
42
|
-
/**
|
|
43
|
-
* Variant of a preset at a density, `1` by default.
|
|
44
|
-
*
|
|
45
|
-
* @throws {RangeError} When the preset does not declare the density.
|
|
46
|
-
*/
|
|
47
|
-
variant(preset: Name, density?: number): RenditionVariant;
|
|
48
|
-
/** Variant with a recipe hash, if the catalog has one. */
|
|
49
|
-
findVariant(hash: string): RenditionVariant | undefined;
|
|
50
|
-
/** Root-relative URL of a rendition. */
|
|
51
|
-
url(preset: Name, target: RenditionTarget, density?: number): string;
|
|
52
|
-
/** `srcset` attribute value listing every density of a preset. */
|
|
53
|
-
srcset(preset: Name, target: RenditionTarget): string;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Validates a catalog and computes the recipe and hash of every preset density.
|
|
57
|
-
*
|
|
58
|
-
* Preset names are only labels: renaming a preset keeps its hashes and thus its stored renditions.
|
|
59
|
-
*
|
|
60
|
-
* @throws {RangeError} When the catalog is invalid.
|
|
61
|
-
*/
|
|
62
|
-
declare function defineCatalog<const Name extends string>(definition: CatalogDefinition<Name>): Catalog<Name>;
|
|
63
|
-
//#endregion
|
|
64
|
-
export { RenditionVariant as a, RenditionTarget as i, CatalogDefinition as n, defineCatalog as o, PresetDefinition as r, Catalog as t };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { r as Recipe } from "./recipe-Je9DxqO1.mjs";
|
|
2
|
-
import { t as EncodedImage } from "./stores-DFDRMZcC.mjs";
|
|
3
|
-
//#region src/server/processor.d.ts
|
|
4
|
-
/** Renders a source image according to a recipe. */
|
|
5
|
-
interface Processor {
|
|
6
|
-
/**
|
|
7
|
-
* Renders the source.
|
|
8
|
-
*
|
|
9
|
-
* Rejects with a `RenditionError` of reason `unsupported-source` when the source cannot be decoded.
|
|
10
|
-
*/
|
|
11
|
-
process(source: Uint8Array, recipe: Recipe): Promise<EncodedImage>;
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
export { Processor as t };
|