@cibule/image-sharp 0.1.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 +96 -0
- package/dist/index.cjs +166 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +7 -0
- package/dist/lib/cache-key.d.ts +9 -0
- package/dist/lib/cache-key.d.ts.map +1 -0
- package/dist/lib/sharp-image-transformer-config.d.ts +9 -0
- package/dist/lib/sharp-image-transformer-config.d.ts.map +1 -0
- package/dist/lib/sharp-image-transformer.d.ts +12 -0
- package/dist/lib/sharp-image-transformer.d.ts.map +1 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# @cibule/image-sharp
|
|
2
|
+
|
|
3
|
+
Sharp-based image transformation for Node.js with FileStorage caching.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @cibule/image-sharp @cibule/image @cibule/storage
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { SharpImageTransformer } from '@cibule/image-sharp';
|
|
15
|
+
import { LocalFileStorage } from '@cibule/storage';
|
|
16
|
+
|
|
17
|
+
const source = new LocalFileStorage({ basePath: './uploads' });
|
|
18
|
+
const cache = new LocalFileStorage({ basePath: './cache' });
|
|
19
|
+
|
|
20
|
+
const transformer = new SharpImageTransformer({
|
|
21
|
+
source,
|
|
22
|
+
cache,
|
|
23
|
+
cachePrefix: 'thumbnails', // default: 'thumbnails'
|
|
24
|
+
defaultFormat: 'avif', // default: 'avif'
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Transform an image — resizes and converts to AVIF
|
|
28
|
+
const result = await transformer.transform('photos/hero.jpg', {
|
|
29
|
+
width: 800,
|
|
30
|
+
quality: 80, // default: 80
|
|
31
|
+
format: 'webp', // overrides defaultFormat
|
|
32
|
+
fit: 'cover', // default: 'cover'
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// result.body — ReadableStream<Uint8Array>
|
|
36
|
+
// result.contentType — 'image/webp'
|
|
37
|
+
// result.width — 800
|
|
38
|
+
// result.height — computed by Sharp
|
|
39
|
+
// result.size — byte size of transformed image
|
|
40
|
+
|
|
41
|
+
// Subsequent calls with same key + options serve from cache
|
|
42
|
+
const cached = await transformer.transform('photos/hero.jpg', { width: 800 });
|
|
43
|
+
|
|
44
|
+
// Purge all cached thumbnails
|
|
45
|
+
const purgeResult = await transformer.purgeCache();
|
|
46
|
+
// purgeResult.purgedCount — number of deleted cache entries
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
| Option | Type | Default | Description |
|
|
52
|
+
| --------------- | ------------- | -------------- | ------------------------------------ |
|
|
53
|
+
| `source` | `FileStorage` | _(required)_ | Storage driver for source images |
|
|
54
|
+
| `cache` | `FileStorage` | _(required)_ | Storage driver for cached thumbnails |
|
|
55
|
+
| `cachePrefix` | `string` | `'thumbnails'` | Key prefix for cached images |
|
|
56
|
+
| `defaultFormat` | `ImageFormat` | `'avif'` | Output format when not specified |
|
|
57
|
+
|
|
58
|
+
## Supported Formats
|
|
59
|
+
|
|
60
|
+
- `avif` — best compression, modern browsers
|
|
61
|
+
- `webp` — good compression, wide support
|
|
62
|
+
- `jpeg` — universal compatibility
|
|
63
|
+
- `png` — lossless, transparency support
|
|
64
|
+
|
|
65
|
+
## Caching
|
|
66
|
+
|
|
67
|
+
Transformed images are stored in the `cache` FileStorage under a deterministic key:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
{cachePrefix}/{sourceKey}/w{width}_q{quality}_{format}_{fit}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Cache hits skip the Sharp transformation entirely and serve directly from storage.
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### `SharpImageTransformer`
|
|
78
|
+
|
|
79
|
+
Extends `ImageTransformer` from `@cibule/image`.
|
|
80
|
+
|
|
81
|
+
#### `transform(key: string, options: TransformOptions): Promise<TransformResult>`
|
|
82
|
+
|
|
83
|
+
Downloads the source image, resizes and converts it using Sharp, caches the result, and returns a `TransformResult` with the transformed image body and metadata.
|
|
84
|
+
|
|
85
|
+
#### `purgeCache(): Promise<PurgeCacheResult>`
|
|
86
|
+
|
|
87
|
+
Deletes all cached images under the configured `cachePrefix`. Returns the number of purged entries.
|
|
88
|
+
|
|
89
|
+
## Requirements
|
|
90
|
+
|
|
91
|
+
- Node.js (Sharp requires native binaries — not compatible with Cloudflare Workers)
|
|
92
|
+
- For CF Workers, use `@cibule/image-cf` instead
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
SharpImageTransformer: () => SharpImageTransformer
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// ../image/src/lib/constants.ts
|
|
38
|
+
var DEFAULT_QUALITY = 80;
|
|
39
|
+
var DEFAULT_MAX_SOURCE_SIZE = 60 * 1024 * 1024;
|
|
40
|
+
|
|
41
|
+
// ../image/src/lib/content-type-map.ts
|
|
42
|
+
var FORMAT_TO_CONTENT_TYPE = {
|
|
43
|
+
avif: "image/avif",
|
|
44
|
+
webp: "image/webp",
|
|
45
|
+
jpeg: "image/jpeg",
|
|
46
|
+
png: "image/png"
|
|
47
|
+
};
|
|
48
|
+
function getContentType(format) {
|
|
49
|
+
return FORMAT_TO_CONTENT_TYPE[format];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ../image/src/lib/image-transformer.ts
|
|
53
|
+
var ImageTransformer = class {
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// ../storage/src/lib/create-readable-stream.ts
|
|
57
|
+
function createReadableStream(data) {
|
|
58
|
+
return new ReadableStream({
|
|
59
|
+
start(controller) {
|
|
60
|
+
controller.enqueue(new Uint8Array(data));
|
|
61
|
+
controller.close();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ../storage/src/lib/concat-uint8-arrays.ts
|
|
67
|
+
function concatUint8Arrays(chunks) {
|
|
68
|
+
if (chunks.length === 0) {
|
|
69
|
+
return new Uint8Array(0);
|
|
70
|
+
}
|
|
71
|
+
if (chunks.length === 1) {
|
|
72
|
+
return chunks[0] ?? new Uint8Array(0);
|
|
73
|
+
}
|
|
74
|
+
const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);
|
|
75
|
+
const result = new Uint8Array(totalLength);
|
|
76
|
+
let offset = 0;
|
|
77
|
+
for (const chunk of chunks) {
|
|
78
|
+
result.set(chunk, offset);
|
|
79
|
+
offset += chunk.byteLength;
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ../storage/src/lib/to-uint8-array.ts
|
|
85
|
+
async function toUint8Array(input) {
|
|
86
|
+
if (input instanceof Uint8Array) {
|
|
87
|
+
return input;
|
|
88
|
+
}
|
|
89
|
+
if (input instanceof ArrayBuffer) {
|
|
90
|
+
return new Uint8Array(input);
|
|
91
|
+
}
|
|
92
|
+
const reader = input.getReader();
|
|
93
|
+
const chunks = [];
|
|
94
|
+
for (; ; ) {
|
|
95
|
+
const { done, value } = await reader.read();
|
|
96
|
+
if (done) break;
|
|
97
|
+
chunks.push(value);
|
|
98
|
+
}
|
|
99
|
+
return concatUint8Arrays(chunks);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/lib/sharp-image-transformer.ts
|
|
103
|
+
var import_sharp = __toESM(require("sharp"), 1);
|
|
104
|
+
|
|
105
|
+
// src/lib/cache-key.ts
|
|
106
|
+
function buildCacheKey(sourceKey, options, prefix) {
|
|
107
|
+
return `${prefix}/${sourceKey}/w${String(options.width)}_q${String(options.quality)}_${options.format}_${options.fit}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/lib/sharp-image-transformer.ts
|
|
111
|
+
var SharpImageTransformer = class extends ImageTransformer {
|
|
112
|
+
constructor(config) {
|
|
113
|
+
super();
|
|
114
|
+
this.config = config;
|
|
115
|
+
this.cachePrefix = config.cachePrefix ?? "thumbnails";
|
|
116
|
+
}
|
|
117
|
+
cachePrefix;
|
|
118
|
+
async transform(key, options) {
|
|
119
|
+
const format = options.format ?? this.config.defaultFormat ?? "avif";
|
|
120
|
+
const quality = options.quality ?? DEFAULT_QUALITY;
|
|
121
|
+
const fit = options.fit ?? "cover";
|
|
122
|
+
const cacheKey = buildCacheKey(
|
|
123
|
+
key,
|
|
124
|
+
{ width: options.width, format, quality, fit },
|
|
125
|
+
this.cachePrefix
|
|
126
|
+
);
|
|
127
|
+
const cached = await this.config.cache.head(cacheKey);
|
|
128
|
+
if (cached) {
|
|
129
|
+
return this.serveCached(cacheKey, cached.size, cached.contentType ?? getContentType(format));
|
|
130
|
+
}
|
|
131
|
+
const sourceObject = await this.config.source.download(key);
|
|
132
|
+
const sourceBytes = await toUint8Array(sourceObject.body);
|
|
133
|
+
const { data, info } = await (0, import_sharp.default)(sourceBytes).resize({ width: options.width, fit }).toFormat(format, { quality }).toBuffer({ resolveWithObject: true });
|
|
134
|
+
const contentType = getContentType(format);
|
|
135
|
+
await this.config.cache.upload(cacheKey, data, { contentType });
|
|
136
|
+
return {
|
|
137
|
+
body: createReadableStream(data),
|
|
138
|
+
contentType,
|
|
139
|
+
width: info.width,
|
|
140
|
+
height: info.height,
|
|
141
|
+
size: info.size
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async purgeCache() {
|
|
145
|
+
const keys = await this.config.cache.listKeys(this.cachePrefix);
|
|
146
|
+
await Promise.all(keys.map((k) => this.config.cache.delete(k)));
|
|
147
|
+
return { purgedCount: keys.length };
|
|
148
|
+
}
|
|
149
|
+
async serveCached(cacheKey, size, contentType) {
|
|
150
|
+
const cached = await this.config.cache.download(cacheKey);
|
|
151
|
+
const bytes = await toUint8Array(cached.body);
|
|
152
|
+
const metadata = await (0, import_sharp.default)(bytes).metadata();
|
|
153
|
+
return {
|
|
154
|
+
body: createReadableStream(bytes),
|
|
155
|
+
contentType,
|
|
156
|
+
width: metadata.width ?? 0,
|
|
157
|
+
height: metadata.height ?? 0,
|
|
158
|
+
size
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
163
|
+
0 && (module.exports = {
|
|
164
|
+
SharpImageTransformer
|
|
165
|
+
});
|
|
166
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts", "../../image/src/lib/constants.ts", "../../image/src/lib/content-type-map.ts", "../../image/src/lib/image-transformer.ts", "../../storage/src/lib/create-readable-stream.ts", "../../storage/src/lib/concat-uint8-arrays.ts", "../../storage/src/lib/to-uint8-array.ts", "../src/lib/sharp-image-transformer.ts", "../src/lib/cache-key.ts"],
|
|
4
|
+
"sourcesContent": ["export { SharpImageTransformer } from './lib/sharp-image-transformer';\nexport type { SharpImageTransformerConfig } from './lib/sharp-image-transformer-config';\n", "export const ALLOWED_WIDTHS = [384, 640, 750, 828, 1080, 1200, 1920] as const;\n\nexport const ALLOWED_PLACEHOLDER_WIDTHS = [20, 30, 50, 80] as const;\n\nexport const DEFAULT_QUALITY = 80;\n\nexport const DEFAULT_MAX_SOURCE_SIZE = 60 * 1024 * 1024;\n", "import type { ImageFormat } from './transform-options';\n\nconst FORMAT_TO_CONTENT_TYPE: Record<ImageFormat, string> = {\n avif: 'image/avif',\n webp: 'image/webp',\n jpeg: 'image/jpeg',\n png: 'image/png',\n};\n\nexport function getContentType(format: ImageFormat): string {\n return FORMAT_TO_CONTENT_TYPE[format];\n}\n", "import type { PurgeCacheResult, TransformOptions, TransformResult } from './transform-options';\n\nexport abstract class ImageTransformer {\n abstract transform(key: string, options: TransformOptions): Promise<TransformResult>;\n abstract purgeCache(): Promise<PurgeCacheResult>;\n}\n", "export function createReadableStream(data: Uint8Array): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller): void {\n controller.enqueue(new Uint8Array(data));\n controller.close();\n },\n });\n}\n", "export function concatUint8Arrays(chunks: Uint8Array[]): Uint8Array {\n if (chunks.length === 0) {\n return new Uint8Array(0);\n }\n\n if (chunks.length === 1) {\n return chunks[0] ?? new Uint8Array(0);\n }\n\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return result;\n}\n", "import { concatUint8Arrays } from './concat-uint8-arrays';\n\nexport async function toUint8Array(\n input: ReadableStream<Uint8Array> | ArrayBuffer | Uint8Array,\n): Promise<Uint8Array> {\n if (input instanceof Uint8Array) {\n return input;\n }\n\n if (input instanceof ArrayBuffer) {\n return new Uint8Array(input);\n }\n\n const reader = input.getReader();\n const chunks: Uint8Array[] = [];\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n\n return concatUint8Arrays(chunks);\n}\n", "import type { PurgeCacheResult, TransformOptions, TransformResult } from '@cibule/image';\nimport { DEFAULT_QUALITY, getContentType, ImageTransformer } from '@cibule/image';\nimport { createReadableStream, toUint8Array } from '@cibule/storage';\nimport sharp from 'sharp';\n\nimport { buildCacheKey } from './cache-key';\nimport type { SharpImageTransformerConfig } from './sharp-image-transformer-config';\n\nexport class SharpImageTransformer extends ImageTransformer {\n private readonly cachePrefix: string;\n\n public constructor(private readonly config: SharpImageTransformerConfig) {\n super();\n this.cachePrefix = config.cachePrefix ?? 'thumbnails';\n }\n\n public async transform(key: string, options: TransformOptions): Promise<TransformResult> {\n const format = options.format ?? this.config.defaultFormat ?? 'avif';\n const quality = options.quality ?? DEFAULT_QUALITY;\n const fit = options.fit ?? 'cover';\n const cacheKey = buildCacheKey(\n key,\n { width: options.width, format, quality, fit },\n this.cachePrefix,\n );\n\n const cached = await this.config.cache.head(cacheKey);\n if (cached) {\n return this.serveCached(cacheKey, cached.size, cached.contentType ?? getContentType(format));\n }\n\n const sourceObject = await this.config.source.download(key);\n const sourceBytes = await toUint8Array(sourceObject.body);\n\n const { data, info } = await sharp(sourceBytes)\n .resize({ width: options.width, fit })\n .toFormat(format, { quality })\n .toBuffer({ resolveWithObject: true });\n\n const contentType = getContentType(format);\n await this.config.cache.upload(cacheKey, data, { contentType });\n\n return {\n body: createReadableStream(data),\n contentType,\n width: info.width,\n height: info.height,\n size: info.size,\n };\n }\n\n public async purgeCache(): Promise<PurgeCacheResult> {\n const keys = await this.config.cache.listKeys(this.cachePrefix);\n await Promise.all(keys.map(k => this.config.cache.delete(k)));\n return { purgedCount: keys.length };\n }\n\n private async serveCached(\n cacheKey: string,\n size: number,\n contentType: string,\n ): Promise<TransformResult> {\n const cached = await this.config.cache.download(cacheKey);\n const bytes = await toUint8Array(cached.body);\n const metadata = await sharp(bytes).metadata();\n\n return {\n body: createReadableStream(bytes),\n contentType,\n width: metadata.width ?? 0,\n height: metadata.height ?? 0,\n size,\n };\n }\n}\n", "import type { ImageFit, ImageFormat } from '@cibule/image';\n\nexport interface ResolvedTransformOptions {\n readonly width: number;\n readonly format: ImageFormat;\n readonly quality: number;\n readonly fit: ImageFit;\n}\n\nexport function buildCacheKey(\n sourceKey: string,\n options: ResolvedTransformOptions,\n prefix: string,\n): string {\n return `${prefix}/${sourceKey}/w${String(options.width)}_q${String(options.quality)}_${options.format}_${options.fit}`;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACIO,IAAM,kBAAkB;AAExB,IAAM,0BAA0B,KAAK,OAAO;;;ACJnD,IAAM,yBAAsD;AAAA,EAC1D,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AACP;AAEO,SAAS,eAAe,QAA6B;AAC1D,SAAO,uBAAuB,MAAM;AACtC;;;ACTO,IAAe,mBAAf,MAAgC;AAGvC;;;ACLO,SAAS,qBAAqB,MAA8C;AACjF,SAAO,IAAI,eAA2B;AAAA,IACpC,MAAM,YAAkB;AACtB,iBAAW,QAAQ,IAAI,WAAW,IAAI,CAAC;AACvC,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF,CAAC;AACH;;;ACPO,SAAS,kBAAkB,QAAkC;AAClE,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,IAAI,WAAW,CAAC;AAAA,EACzB;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC;AAAA,EACtC;AAEA,QAAM,cAAc,OAAO,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,YAAY,CAAC;AACnE,QAAM,SAAS,IAAI,WAAW,WAAW;AACzC,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,WAAO,IAAI,OAAO,MAAM;AACxB,cAAU,MAAM;AAAA,EAClB;AAEA,SAAO;AACT;;;AChBA,eAAsB,aACpB,OACqB;AACrB,MAAI,iBAAiB,YAAY;AAC/B,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,aAAa;AAChC,WAAO,IAAI,WAAW,KAAK;AAAA,EAC7B;AAEA,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,SAAuB,CAAC;AAE9B,aAAS;AACP,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AACV,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,SAAO,kBAAkB,MAAM;AACjC;;;ACpBA,mBAAkB;;;ACMX,SAAS,cACd,WACA,SACA,QACQ;AACR,SAAO,GAAG,MAAM,IAAI,SAAS,KAAK,OAAO,QAAQ,KAAK,CAAC,KAAK,OAAO,QAAQ,OAAO,CAAC,IAAI,QAAQ,MAAM,IAAI,QAAQ,GAAG;AACtH;;;ADPO,IAAM,wBAAN,cAAoC,iBAAiB;AAAA,EAGnD,YAA6B,QAAqC;AACvE,UAAM;AAD4B;AAElC,SAAK,cAAc,OAAO,eAAe;AAAA,EAC3C;AAAA,EALiB;AAAA,EAOjB,MAAa,UAAU,KAAa,SAAqD;AACvF,UAAM,SAAS,QAAQ,UAAU,KAAK,OAAO,iBAAiB;AAC9D,UAAM,UAAU,QAAQ,WAAW;AACnC,UAAM,MAAM,QAAQ,OAAO;AAC3B,UAAM,WAAW;AAAA,MACf;AAAA,MACA,EAAE,OAAO,QAAQ,OAAO,QAAQ,SAAS,IAAI;AAAA,MAC7C,KAAK;AAAA,IACP;AAEA,UAAM,SAAS,MAAM,KAAK,OAAO,MAAM,KAAK,QAAQ;AACpD,QAAI,QAAQ;AACV,aAAO,KAAK,YAAY,UAAU,OAAO,MAAM,OAAO,eAAe,eAAe,MAAM,CAAC;AAAA,IAC7F;AAEA,UAAM,eAAe,MAAM,KAAK,OAAO,OAAO,SAAS,GAAG;AAC1D,UAAM,cAAc,MAAM,aAAa,aAAa,IAAI;AAExD,UAAM,EAAE,MAAM,KAAK,IAAI,UAAM,aAAAA,SAAM,WAAW,EAC3C,OAAO,EAAE,OAAO,QAAQ,OAAO,IAAI,CAAC,EACpC,SAAS,QAAQ,EAAE,QAAQ,CAAC,EAC5B,SAAS,EAAE,mBAAmB,KAAK,CAAC;AAEvC,UAAM,cAAc,eAAe,MAAM;AACzC,UAAM,KAAK,OAAO,MAAM,OAAO,UAAU,MAAM,EAAE,YAAY,CAAC;AAE9D,WAAO;AAAA,MACL,MAAM,qBAAqB,IAAI;AAAA,MAC/B;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAa,aAAwC;AACnD,UAAM,OAAO,MAAM,KAAK,OAAO,MAAM,SAAS,KAAK,WAAW;AAC9D,UAAM,QAAQ,IAAI,KAAK,IAAI,OAAK,KAAK,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC;AAC5D,WAAO,EAAE,aAAa,KAAK,OAAO;AAAA,EACpC;AAAA,EAEA,MAAc,YACZ,UACA,MACA,aAC0B;AAC1B,UAAM,SAAS,MAAM,KAAK,OAAO,MAAM,SAAS,QAAQ;AACxD,UAAM,QAAQ,MAAM,aAAa,OAAO,IAAI;AAC5C,UAAM,WAAW,UAAM,aAAAA,SAAM,KAAK,EAAE,SAAS;AAE7C,WAAO;AAAA,MACL,MAAM,qBAAqB,KAAK;AAAA,MAChC;AAAA,MACA,OAAO,SAAS,SAAS;AAAA,MACzB,QAAQ,SAAS,UAAU;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": ["sharp"]
|
|
7
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,YAAY,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// ../image/src/lib/constants.ts
|
|
2
|
+
var DEFAULT_QUALITY = 80;
|
|
3
|
+
var DEFAULT_MAX_SOURCE_SIZE = 60 * 1024 * 1024;
|
|
4
|
+
|
|
5
|
+
// ../image/src/lib/content-type-map.ts
|
|
6
|
+
var FORMAT_TO_CONTENT_TYPE = {
|
|
7
|
+
avif: "image/avif",
|
|
8
|
+
webp: "image/webp",
|
|
9
|
+
jpeg: "image/jpeg",
|
|
10
|
+
png: "image/png"
|
|
11
|
+
};
|
|
12
|
+
function getContentType(format) {
|
|
13
|
+
return FORMAT_TO_CONTENT_TYPE[format];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ../image/src/lib/image-transformer.ts
|
|
17
|
+
var ImageTransformer = class {
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// ../storage/src/lib/create-readable-stream.ts
|
|
21
|
+
function createReadableStream(data) {
|
|
22
|
+
return new ReadableStream({
|
|
23
|
+
start(controller) {
|
|
24
|
+
controller.enqueue(new Uint8Array(data));
|
|
25
|
+
controller.close();
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ../storage/src/lib/concat-uint8-arrays.ts
|
|
31
|
+
function concatUint8Arrays(chunks) {
|
|
32
|
+
if (chunks.length === 0) {
|
|
33
|
+
return new Uint8Array(0);
|
|
34
|
+
}
|
|
35
|
+
if (chunks.length === 1) {
|
|
36
|
+
return chunks[0] ?? new Uint8Array(0);
|
|
37
|
+
}
|
|
38
|
+
const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);
|
|
39
|
+
const result = new Uint8Array(totalLength);
|
|
40
|
+
let offset = 0;
|
|
41
|
+
for (const chunk of chunks) {
|
|
42
|
+
result.set(chunk, offset);
|
|
43
|
+
offset += chunk.byteLength;
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ../storage/src/lib/to-uint8-array.ts
|
|
49
|
+
async function toUint8Array(input) {
|
|
50
|
+
if (input instanceof Uint8Array) {
|
|
51
|
+
return input;
|
|
52
|
+
}
|
|
53
|
+
if (input instanceof ArrayBuffer) {
|
|
54
|
+
return new Uint8Array(input);
|
|
55
|
+
}
|
|
56
|
+
const reader = input.getReader();
|
|
57
|
+
const chunks = [];
|
|
58
|
+
for (; ; ) {
|
|
59
|
+
const { done, value } = await reader.read();
|
|
60
|
+
if (done) break;
|
|
61
|
+
chunks.push(value);
|
|
62
|
+
}
|
|
63
|
+
return concatUint8Arrays(chunks);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/lib/sharp-image-transformer.ts
|
|
67
|
+
import sharp from "sharp";
|
|
68
|
+
|
|
69
|
+
// src/lib/cache-key.ts
|
|
70
|
+
function buildCacheKey(sourceKey, options, prefix) {
|
|
71
|
+
return `${prefix}/${sourceKey}/w${String(options.width)}_q${String(options.quality)}_${options.format}_${options.fit}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/lib/sharp-image-transformer.ts
|
|
75
|
+
var SharpImageTransformer = class extends ImageTransformer {
|
|
76
|
+
constructor(config) {
|
|
77
|
+
super();
|
|
78
|
+
this.config = config;
|
|
79
|
+
this.cachePrefix = config.cachePrefix ?? "thumbnails";
|
|
80
|
+
}
|
|
81
|
+
cachePrefix;
|
|
82
|
+
async transform(key, options) {
|
|
83
|
+
const format = options.format ?? this.config.defaultFormat ?? "avif";
|
|
84
|
+
const quality = options.quality ?? DEFAULT_QUALITY;
|
|
85
|
+
const fit = options.fit ?? "cover";
|
|
86
|
+
const cacheKey = buildCacheKey(
|
|
87
|
+
key,
|
|
88
|
+
{ width: options.width, format, quality, fit },
|
|
89
|
+
this.cachePrefix
|
|
90
|
+
);
|
|
91
|
+
const cached = await this.config.cache.head(cacheKey);
|
|
92
|
+
if (cached) {
|
|
93
|
+
return this.serveCached(cacheKey, cached.size, cached.contentType ?? getContentType(format));
|
|
94
|
+
}
|
|
95
|
+
const sourceObject = await this.config.source.download(key);
|
|
96
|
+
const sourceBytes = await toUint8Array(sourceObject.body);
|
|
97
|
+
const { data, info } = await sharp(sourceBytes).resize({ width: options.width, fit }).toFormat(format, { quality }).toBuffer({ resolveWithObject: true });
|
|
98
|
+
const contentType = getContentType(format);
|
|
99
|
+
await this.config.cache.upload(cacheKey, data, { contentType });
|
|
100
|
+
return {
|
|
101
|
+
body: createReadableStream(data),
|
|
102
|
+
contentType,
|
|
103
|
+
width: info.width,
|
|
104
|
+
height: info.height,
|
|
105
|
+
size: info.size
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
async purgeCache() {
|
|
109
|
+
const keys = await this.config.cache.listKeys(this.cachePrefix);
|
|
110
|
+
await Promise.all(keys.map((k) => this.config.cache.delete(k)));
|
|
111
|
+
return { purgedCount: keys.length };
|
|
112
|
+
}
|
|
113
|
+
async serveCached(cacheKey, size, contentType) {
|
|
114
|
+
const cached = await this.config.cache.download(cacheKey);
|
|
115
|
+
const bytes = await toUint8Array(cached.body);
|
|
116
|
+
const metadata = await sharp(bytes).metadata();
|
|
117
|
+
return {
|
|
118
|
+
body: createReadableStream(bytes),
|
|
119
|
+
contentType,
|
|
120
|
+
width: metadata.width ?? 0,
|
|
121
|
+
height: metadata.height ?? 0,
|
|
122
|
+
size
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
export {
|
|
127
|
+
SharpImageTransformer
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../image/src/lib/constants.ts", "../../image/src/lib/content-type-map.ts", "../../image/src/lib/image-transformer.ts", "../../storage/src/lib/create-readable-stream.ts", "../../storage/src/lib/concat-uint8-arrays.ts", "../../storage/src/lib/to-uint8-array.ts", "../src/lib/sharp-image-transformer.ts", "../src/lib/cache-key.ts"],
|
|
4
|
+
"sourcesContent": ["export const ALLOWED_WIDTHS = [384, 640, 750, 828, 1080, 1200, 1920] as const;\n\nexport const ALLOWED_PLACEHOLDER_WIDTHS = [20, 30, 50, 80] as const;\n\nexport const DEFAULT_QUALITY = 80;\n\nexport const DEFAULT_MAX_SOURCE_SIZE = 60 * 1024 * 1024;\n", "import type { ImageFormat } from './transform-options';\n\nconst FORMAT_TO_CONTENT_TYPE: Record<ImageFormat, string> = {\n avif: 'image/avif',\n webp: 'image/webp',\n jpeg: 'image/jpeg',\n png: 'image/png',\n};\n\nexport function getContentType(format: ImageFormat): string {\n return FORMAT_TO_CONTENT_TYPE[format];\n}\n", "import type { PurgeCacheResult, TransformOptions, TransformResult } from './transform-options';\n\nexport abstract class ImageTransformer {\n abstract transform(key: string, options: TransformOptions): Promise<TransformResult>;\n abstract purgeCache(): Promise<PurgeCacheResult>;\n}\n", "export function createReadableStream(data: Uint8Array): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller): void {\n controller.enqueue(new Uint8Array(data));\n controller.close();\n },\n });\n}\n", "export function concatUint8Arrays(chunks: Uint8Array[]): Uint8Array {\n if (chunks.length === 0) {\n return new Uint8Array(0);\n }\n\n if (chunks.length === 1) {\n return chunks[0] ?? new Uint8Array(0);\n }\n\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return result;\n}\n", "import { concatUint8Arrays } from './concat-uint8-arrays';\n\nexport async function toUint8Array(\n input: ReadableStream<Uint8Array> | ArrayBuffer | Uint8Array,\n): Promise<Uint8Array> {\n if (input instanceof Uint8Array) {\n return input;\n }\n\n if (input instanceof ArrayBuffer) {\n return new Uint8Array(input);\n }\n\n const reader = input.getReader();\n const chunks: Uint8Array[] = [];\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n\n return concatUint8Arrays(chunks);\n}\n", "import type { PurgeCacheResult, TransformOptions, TransformResult } from '@cibule/image';\nimport { DEFAULT_QUALITY, getContentType, ImageTransformer } from '@cibule/image';\nimport { createReadableStream, toUint8Array } from '@cibule/storage';\nimport sharp from 'sharp';\n\nimport { buildCacheKey } from './cache-key';\nimport type { SharpImageTransformerConfig } from './sharp-image-transformer-config';\n\nexport class SharpImageTransformer extends ImageTransformer {\n private readonly cachePrefix: string;\n\n public constructor(private readonly config: SharpImageTransformerConfig) {\n super();\n this.cachePrefix = config.cachePrefix ?? 'thumbnails';\n }\n\n public async transform(key: string, options: TransformOptions): Promise<TransformResult> {\n const format = options.format ?? this.config.defaultFormat ?? 'avif';\n const quality = options.quality ?? DEFAULT_QUALITY;\n const fit = options.fit ?? 'cover';\n const cacheKey = buildCacheKey(\n key,\n { width: options.width, format, quality, fit },\n this.cachePrefix,\n );\n\n const cached = await this.config.cache.head(cacheKey);\n if (cached) {\n return this.serveCached(cacheKey, cached.size, cached.contentType ?? getContentType(format));\n }\n\n const sourceObject = await this.config.source.download(key);\n const sourceBytes = await toUint8Array(sourceObject.body);\n\n const { data, info } = await sharp(sourceBytes)\n .resize({ width: options.width, fit })\n .toFormat(format, { quality })\n .toBuffer({ resolveWithObject: true });\n\n const contentType = getContentType(format);\n await this.config.cache.upload(cacheKey, data, { contentType });\n\n return {\n body: createReadableStream(data),\n contentType,\n width: info.width,\n height: info.height,\n size: info.size,\n };\n }\n\n public async purgeCache(): Promise<PurgeCacheResult> {\n const keys = await this.config.cache.listKeys(this.cachePrefix);\n await Promise.all(keys.map(k => this.config.cache.delete(k)));\n return { purgedCount: keys.length };\n }\n\n private async serveCached(\n cacheKey: string,\n size: number,\n contentType: string,\n ): Promise<TransformResult> {\n const cached = await this.config.cache.download(cacheKey);\n const bytes = await toUint8Array(cached.body);\n const metadata = await sharp(bytes).metadata();\n\n return {\n body: createReadableStream(bytes),\n contentType,\n width: metadata.width ?? 0,\n height: metadata.height ?? 0,\n size,\n };\n }\n}\n", "import type { ImageFit, ImageFormat } from '@cibule/image';\n\nexport interface ResolvedTransformOptions {\n readonly width: number;\n readonly format: ImageFormat;\n readonly quality: number;\n readonly fit: ImageFit;\n}\n\nexport function buildCacheKey(\n sourceKey: string,\n options: ResolvedTransformOptions,\n prefix: string,\n): string {\n return `${prefix}/${sourceKey}/w${String(options.width)}_q${String(options.quality)}_${options.format}_${options.fit}`;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ImageFit, ImageFormat } from '@cibule/image';
|
|
2
|
+
export interface ResolvedTransformOptions {
|
|
3
|
+
readonly width: number;
|
|
4
|
+
readonly format: ImageFormat;
|
|
5
|
+
readonly quality: number;
|
|
6
|
+
readonly fit: ImageFit;
|
|
7
|
+
}
|
|
8
|
+
export declare function buildCacheKey(sourceKey: string, options: ResolvedTransformOptions, prefix: string): string;
|
|
9
|
+
//# sourceMappingURL=cache-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-key.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/cache-key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE3D,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;CACxB;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,wBAAwB,EACjC,MAAM,EAAE,MAAM,GACb,MAAM,CAER"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ImageFormat } from '@cibule/image';
|
|
2
|
+
import type { FileStorage } from '@cibule/storage';
|
|
3
|
+
export interface SharpImageTransformerConfig {
|
|
4
|
+
readonly source: FileStorage;
|
|
5
|
+
readonly cache: FileStorage;
|
|
6
|
+
readonly cachePrefix?: string;
|
|
7
|
+
readonly defaultFormat?: ImageFormat;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=sharp-image-transformer-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sharp-image-transformer-config.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/sharp-image-transformer-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC;CACtC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PurgeCacheResult, TransformOptions, TransformResult } from '@cibule/image';
|
|
2
|
+
import { ImageTransformer } from '@cibule/image';
|
|
3
|
+
import type { SharpImageTransformerConfig } from './sharp-image-transformer-config';
|
|
4
|
+
export declare class SharpImageTransformer extends ImageTransformer {
|
|
5
|
+
private readonly config;
|
|
6
|
+
private readonly cachePrefix;
|
|
7
|
+
constructor(config: SharpImageTransformerConfig);
|
|
8
|
+
transform(key: string, options: TransformOptions): Promise<TransformResult>;
|
|
9
|
+
purgeCache(): Promise<PurgeCacheResult>;
|
|
10
|
+
private serveCached;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=sharp-image-transformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sharp-image-transformer.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/sharp-image-transformer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACzF,OAAO,EAAmC,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAKlF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAEpF,qBAAa,qBAAsB,SAAQ,gBAAgB;IAGtC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAF1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAED,MAAM,EAAE,2BAA2B;IAK1D,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAmC3E,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;YAMtC,WAAW;CAiB1B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cibule/image-sharp",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://gitlab.com/LadaBr/cibule",
|
|
28
|
+
"directory": "packages/image-sharp"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@cibule/image": "workspace:*",
|
|
35
|
+
"@cibule/storage": "workspace:*",
|
|
36
|
+
"sharp": "^0.33.0"
|
|
37
|
+
}
|
|
38
|
+
}
|