@deenruv/asset-server-plugin 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +103 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +21 -0
- package/lib/index.js.map +1 -0
- package/lib/src/common.d.ts +4 -0
- package/lib/src/common.js +42 -0
- package/lib/src/common.js.map +1 -0
- package/lib/src/constants.d.ts +2 -0
- package/lib/src/constants.js +6 -0
- package/lib/src/constants.js.map +1 -0
- package/lib/src/default-asset-storage-strategy-factory.d.ts +6 -0
- package/lib/src/default-asset-storage-strategy-factory.js +24 -0
- package/lib/src/default-asset-storage-strategy-factory.js.map +1 -0
- package/lib/src/file-icon.png +0 -0
- package/lib/src/hashed-asset-naming-strategy.d.ts +21 -0
- package/lib/src/hashed-asset-naming-strategy.js +39 -0
- package/lib/src/hashed-asset-naming-strategy.js.map +1 -0
- package/lib/src/local-asset-storage-strategy.d.ts +28 -0
- package/lib/src/local-asset-storage-strategy.js +68 -0
- package/lib/src/local-asset-storage-strategy.js.map +1 -0
- package/lib/src/plugin.d.ts +167 -0
- package/lib/src/plugin.js +394 -0
- package/lib/src/plugin.js.map +1 -0
- package/lib/src/s3-asset-storage-strategy.d.ts +159 -0
- package/lib/src/s3-asset-storage-strategy.js +289 -0
- package/lib/src/s3-asset-storage-strategy.js.map +1 -0
- package/lib/src/sharp-asset-preview-strategy.d.ts +99 -0
- package/lib/src/sharp-asset-preview-strategy.js +121 -0
- package/lib/src/sharp-asset-preview-strategy.js.map +1 -0
- package/lib/src/transform-image.d.ts +25 -0
- package/lib/src/transform-image.js +145 -0
- package/lib/src/transform-image.js.map +1 -0
- package/lib/src/types.d.ts +137 -0
- package/lib/src/types.js +3 -0
- package/lib/src/types.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# License 1
|
|
2
|
+
|
|
3
|
+
The MIT License
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2025-present Aexol
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
8
|
+
|
|
9
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
12
|
+
|
|
13
|
+
# License 2
|
|
14
|
+
|
|
15
|
+
The MIT License
|
|
16
|
+
|
|
17
|
+
Copyright (c) 2018-2025 Michael Bromley
|
|
18
|
+
|
|
19
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# @deenruv/asset-server-plugin
|
|
2
|
+
|
|
3
|
+
Serves assets (images and other files) from the local file system or cloud storage (e.g. S3), with on-the-fly image transformation (resize, crop, format conversion) and result caching.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @deenruv/asset-server-plugin
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { AssetServerPlugin } from '@deenruv/asset-server-plugin';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
|
|
17
|
+
const config = {
|
|
18
|
+
plugins: [
|
|
19
|
+
AssetServerPlugin.init({
|
|
20
|
+
route: 'assets',
|
|
21
|
+
assetUploadDir: path.join(__dirname, 'assets'),
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Options:**
|
|
28
|
+
|
|
29
|
+
| Option | Type | Default | Description |
|
|
30
|
+
|--------|------|---------|-------------|
|
|
31
|
+
| `route` | `string` | *required* | URL route for serving assets (e.g. `'assets'`) |
|
|
32
|
+
| `assetUploadDir` | `string` | *required* | Local directory for asset storage |
|
|
33
|
+
| `assetUrlPrefix` | `string \| fn` | auto-detected | Complete URL prefix for asset files |
|
|
34
|
+
| `presets` | `ImageTransformPreset[]` | See below | Named image transform presets |
|
|
35
|
+
| `namingStrategy` | `AssetNamingStrategy` | `HashedAssetNamingStrategy` | Strategy for naming uploaded assets |
|
|
36
|
+
| `previewStrategy` | `AssetPreviewStrategy` | `SharpAssetPreviewStrategy` | Strategy for generating preview images |
|
|
37
|
+
| `storageStrategyFactory` | `fn` | `LocalAssetStorageStrategy` | Factory for custom storage backends (e.g. S3) |
|
|
38
|
+
| `cacheHeader` | `string \| CacheConfig` | `'public, max-age=15552000'` | Cache-Control header (default: 6 months) |
|
|
39
|
+
|
|
40
|
+
## Image Transformation
|
|
41
|
+
|
|
42
|
+
Assets can be transformed on-the-fly via URL query parameters:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
http://localhost:3000/assets/photo.jpg?w=500&h=300&mode=resize
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Query Parameters:**
|
|
49
|
+
|
|
50
|
+
| Param | Description |
|
|
51
|
+
|-------|-------------|
|
|
52
|
+
| `w` | Target width in pixels |
|
|
53
|
+
| `h` | Target height in pixels |
|
|
54
|
+
| `mode` | `crop` (cover) or `resize` (contain) |
|
|
55
|
+
| `preset` | Named preset (e.g. `?preset=thumb`) |
|
|
56
|
+
| `fpx`, `fpy` | Focal point (0-1 normalized coordinates) for crop mode |
|
|
57
|
+
| `format` | Output format: `jpg`, `png`, `webp`, `avif` |
|
|
58
|
+
| `q` | Quality (1-100, default: 80 for jpg/webp, 50 for avif) |
|
|
59
|
+
| `cache` | Set to `false` to skip caching |
|
|
60
|
+
|
|
61
|
+
### Default Presets
|
|
62
|
+
|
|
63
|
+
| Name | Width | Height | Mode |
|
|
64
|
+
|------|-------|--------|------|
|
|
65
|
+
| `tiny` | 50px | 50px | crop |
|
|
66
|
+
| `thumb` | 150px | 150px | crop |
|
|
67
|
+
| `small` | 300px | 300px | resize |
|
|
68
|
+
| `medium` | 500px | 500px | resize |
|
|
69
|
+
| `large` | 800px | 800px | resize |
|
|
70
|
+
|
|
71
|
+
Custom presets can be added via the `presets` option:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
AssetServerPlugin.init({
|
|
75
|
+
route: 'assets',
|
|
76
|
+
assetUploadDir: path.join(__dirname, 'assets'),
|
|
77
|
+
presets: [
|
|
78
|
+
{ name: 'hero', width: 1200, height: 600, mode: 'crop' },
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Features
|
|
84
|
+
|
|
85
|
+
- On-the-fly image resize and crop via URL query parameters
|
|
86
|
+
- Format conversion (JPEG, PNG, WebP, AVIF)
|
|
87
|
+
- Quality control for lossy formats
|
|
88
|
+
- Focal point-aware cropping
|
|
89
|
+
- Named transform presets
|
|
90
|
+
- Transformed image caching for subsequent requests
|
|
91
|
+
- Configurable Cache-Control headers
|
|
92
|
+
- S3-compatible cloud storage via `S3AssetStorageStrategy`
|
|
93
|
+
- Hashed asset naming for cache busting
|
|
94
|
+
- Sharp-based image processing
|
|
95
|
+
- Content-type detection with fallback
|
|
96
|
+
|
|
97
|
+
## Admin UI
|
|
98
|
+
|
|
99
|
+
Server-only plugin. No Admin UI extensions.
|
|
100
|
+
|
|
101
|
+
## API Extensions
|
|
102
|
+
|
|
103
|
+
No GraphQL API extensions. Assets are served via Express middleware at the configured route.
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./src/plugin"), exports);
|
|
18
|
+
__exportStar(require("./src/s3-asset-storage-strategy"), exports);
|
|
19
|
+
__exportStar(require("./src/sharp-asset-preview-strategy"), exports);
|
|
20
|
+
__exportStar(require("./src/types"), exports);
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,kEAAgD;AAChD,qEAAmD;AACnD,8CAA4B"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Request } from "express";
|
|
2
|
+
import { AssetServerOptions, ImageTransformFormat } from "./types";
|
|
3
|
+
export declare function getAssetUrlPrefixFn(options: AssetServerOptions): ((request: Request, identifier: string) => string) | ((...args: any[]) => string);
|
|
4
|
+
export declare function getValidFormat(format?: unknown): ImageTransformFormat | undefined;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getValidFormat = exports.getAssetUrlPrefixFn = void 0;
|
|
4
|
+
const constants_1 = require("@deenruv/core/dist/common/constants");
|
|
5
|
+
function getAssetUrlPrefixFn(options) {
|
|
6
|
+
const { assetUrlPrefix, route } = options;
|
|
7
|
+
if (assetUrlPrefix == null) {
|
|
8
|
+
return (request, identifier) => {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const protocol = (_a = request.headers["x-forwarded-proto"]) !== null && _a !== void 0 ? _a : request.protocol;
|
|
11
|
+
return `${Array.isArray(protocol) ? protocol[0] : protocol}://${(_b = request.get("host")) !== null && _b !== void 0 ? _b : "could-not-determine-host"}/${route}/`;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (typeof assetUrlPrefix === "string") {
|
|
15
|
+
return (...args) => assetUrlPrefix;
|
|
16
|
+
}
|
|
17
|
+
if (typeof assetUrlPrefix === "function") {
|
|
18
|
+
return (request, identifier) => {
|
|
19
|
+
const ctx = request[constants_1.REQUEST_CONTEXT_KEY];
|
|
20
|
+
return assetUrlPrefix(ctx, identifier);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`The assetUrlPrefix option was of an unexpected type: ${JSON.stringify(assetUrlPrefix)}`);
|
|
24
|
+
}
|
|
25
|
+
exports.getAssetUrlPrefixFn = getAssetUrlPrefixFn;
|
|
26
|
+
function getValidFormat(format) {
|
|
27
|
+
if (typeof format !== "string") {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
switch (format) {
|
|
31
|
+
case "jpg":
|
|
32
|
+
case "jpeg":
|
|
33
|
+
case "png":
|
|
34
|
+
case "webp":
|
|
35
|
+
case "avif":
|
|
36
|
+
return format;
|
|
37
|
+
default:
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.getValidFormat = getValidFormat;
|
|
42
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/common.ts"],"names":[],"mappings":";;;AAAA,mEAA0E;AAK1E,SAAgB,mBAAmB,CAAC,OAA2B;IAC7D,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAC1C,IAAI,cAAc,IAAI,IAAI,EAAE,CAAC;QAC3B,OAAO,CAAC,OAAgB,EAAE,UAAkB,EAAE,EAAE;;YAC9C,MAAM,QAAQ,GAAG,MAAA,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,mCAAI,OAAO,CAAC,QAAQ,CAAC;YAC1E,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,MACxD,MAAA,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,mCAAI,0BACzB,IAAI,KAAK,GAAG,CAAC;QACf,CAAC,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,cAAc,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,IAAW,EAAE,EAAE,CAAC,cAAc,CAAC;IAC5C,CAAC;IACD,IAAI,OAAO,cAAc,KAAK,UAAU,EAAE,CAAC;QACzC,OAAO,CAAC,OAAgB,EAAE,UAAkB,EAAE,EAAE;YAC9C,MAAM,GAAG,GAAI,OAAe,CAAC,+BAAmB,CAAC,CAAC;YAClD,OAAO,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACzC,CAAC,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,KAAK,CACb,wDAAwD,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,CACzF,CAAC;AACJ,CAAC;AAtBD,kDAsBC;AAED,SAAgB,cAAc,CAC5B,MAAgB;IAEhB,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAhBD,wCAgBC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_CACHE_HEADER = exports.loggerCtx = void 0;
|
|
4
|
+
exports.loggerCtx = "AssetServerPlugin";
|
|
5
|
+
exports.DEFAULT_CACHE_HEADER = "public, max-age=15552000";
|
|
6
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,SAAS,GAAG,mBAAmB,CAAC;AAChC,QAAA,oBAAoB,GAAG,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { LocalAssetStorageStrategy } from "./local-asset-storage-strategy";
|
|
2
|
+
import { AssetServerOptions } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* By default the AssetServerPlugin will configure and use the LocalStorageStrategy to persist Assets.
|
|
5
|
+
*/
|
|
6
|
+
export declare function defaultAssetStorageStrategyFactory(options: AssetServerOptions): LocalAssetStorageStrategy;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultAssetStorageStrategyFactory = void 0;
|
|
4
|
+
const common_1 = require("./common");
|
|
5
|
+
const local_asset_storage_strategy_1 = require("./local-asset-storage-strategy");
|
|
6
|
+
/**
|
|
7
|
+
* By default the AssetServerPlugin will configure and use the LocalStorageStrategy to persist Assets.
|
|
8
|
+
*/
|
|
9
|
+
function defaultAssetStorageStrategyFactory(options) {
|
|
10
|
+
const { assetUrlPrefix, assetUploadDir, route } = options;
|
|
11
|
+
const prefixFn = (0, common_1.getAssetUrlPrefixFn)(options);
|
|
12
|
+
const toAbsoluteUrlFn = (request, identifier) => {
|
|
13
|
+
if (!identifier) {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
const prefix = prefixFn(request, identifier);
|
|
17
|
+
return identifier.startsWith(prefix)
|
|
18
|
+
? identifier
|
|
19
|
+
: `${prefix}${identifier}`;
|
|
20
|
+
};
|
|
21
|
+
return new local_asset_storage_strategy_1.LocalAssetStorageStrategy(assetUploadDir, toAbsoluteUrlFn);
|
|
22
|
+
}
|
|
23
|
+
exports.defaultAssetStorageStrategyFactory = defaultAssetStorageStrategyFactory;
|
|
24
|
+
//# sourceMappingURL=default-asset-storage-strategy-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-asset-storage-strategy-factory.js","sourceRoot":"","sources":["../../src/default-asset-storage-strategy-factory.ts"],"names":[],"mappings":";;;AAEA,qCAA+C;AAC/C,iFAA2E;AAG3E;;GAEG;AACH,SAAgB,kCAAkC,CAChD,OAA2B;IAE3B,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAC1D,MAAM,QAAQ,GAAG,IAAA,4BAAmB,EAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,eAAe,GAAG,CAAC,OAAgB,EAAE,UAAkB,EAAU,EAAE;QACvE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAC7C,OAAO,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC;YAClC,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,GAAG,MAAM,GAAG,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC;IACF,OAAO,IAAI,wDAAyB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;AACxE,CAAC;AAfD,gFAeC"}
|
|
Binary file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DefaultAssetNamingStrategy, RequestContext } from "@deenruv/core";
|
|
2
|
+
/**
|
|
3
|
+
* @description
|
|
4
|
+
* An extension of the {@link DefaultAssetNamingStrategy} which prefixes file names with
|
|
5
|
+
* the type (`'source'` or `'preview'`) as well as a 2-character sub-directory based on
|
|
6
|
+
* the md5 hash of the original file name.
|
|
7
|
+
*
|
|
8
|
+
* This is an implementation of the technique knows as "hashed directory" file storage,
|
|
9
|
+
* and the purpose is to reduce the number of files in a single directory, since a very large
|
|
10
|
+
* number of files can lead to performance issues when reading and writing to that directory.
|
|
11
|
+
*
|
|
12
|
+
* With this strategy, even with 200,000 total assets stored, each directory would
|
|
13
|
+
* only contain less than 800 files.
|
|
14
|
+
*
|
|
15
|
+
* @docsCategory core plugins/AssetServerPlugin
|
|
16
|
+
*/
|
|
17
|
+
export declare class HashedAssetNamingStrategy extends DefaultAssetNamingStrategy {
|
|
18
|
+
generateSourceFileName(ctx: RequestContext, originalFileName: string, conflictFileName?: string): string;
|
|
19
|
+
generatePreviewFileName(ctx: RequestContext, originalFileName: string, conflictFileName?: string): string;
|
|
20
|
+
private getHashedDir;
|
|
21
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.HashedAssetNamingStrategy = void 0;
|
|
7
|
+
const core_1 = require("@deenruv/core");
|
|
8
|
+
const crypto_1 = require("crypto");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
/**
|
|
11
|
+
* @description
|
|
12
|
+
* An extension of the {@link DefaultAssetNamingStrategy} which prefixes file names with
|
|
13
|
+
* the type (`'source'` or `'preview'`) as well as a 2-character sub-directory based on
|
|
14
|
+
* the md5 hash of the original file name.
|
|
15
|
+
*
|
|
16
|
+
* This is an implementation of the technique knows as "hashed directory" file storage,
|
|
17
|
+
* and the purpose is to reduce the number of files in a single directory, since a very large
|
|
18
|
+
* number of files can lead to performance issues when reading and writing to that directory.
|
|
19
|
+
*
|
|
20
|
+
* With this strategy, even with 200,000 total assets stored, each directory would
|
|
21
|
+
* only contain less than 800 files.
|
|
22
|
+
*
|
|
23
|
+
* @docsCategory core plugins/AssetServerPlugin
|
|
24
|
+
*/
|
|
25
|
+
class HashedAssetNamingStrategy extends core_1.DefaultAssetNamingStrategy {
|
|
26
|
+
generateSourceFileName(ctx, originalFileName, conflictFileName) {
|
|
27
|
+
const filename = super.generateSourceFileName(ctx, originalFileName, conflictFileName);
|
|
28
|
+
return path_1.default.join("source", this.getHashedDir(filename), filename);
|
|
29
|
+
}
|
|
30
|
+
generatePreviewFileName(ctx, originalFileName, conflictFileName) {
|
|
31
|
+
const filename = super.generatePreviewFileName(ctx, originalFileName, conflictFileName);
|
|
32
|
+
return path_1.default.join("preview", this.getHashedDir(filename), filename);
|
|
33
|
+
}
|
|
34
|
+
getHashedDir(filename) {
|
|
35
|
+
return (0, crypto_1.createHash)("md5").update(filename).digest("hex").slice(0, 2);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.HashedAssetNamingStrategy = HashedAssetNamingStrategy;
|
|
39
|
+
//# sourceMappingURL=hashed-asset-naming-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashed-asset-naming-strategy.js","sourceRoot":"","sources":["../../src/hashed-asset-naming-strategy.ts"],"names":[],"mappings":";;;;;;AAAA,wCAA2E;AAC3E,mCAAoC;AACpC,gDAAwB;AAExB;;;;;;;;;;;;;;GAcG;AACH,MAAa,yBAA0B,SAAQ,iCAA0B;IACvE,sBAAsB,CACpB,GAAmB,EACnB,gBAAwB,EACxB,gBAAyB;QAEzB,MAAM,QAAQ,GAAG,KAAK,CAAC,sBAAsB,CAC3C,GAAG,EACH,gBAAgB,EAChB,gBAAgB,CACjB,CAAC;QACF,OAAO,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IACpE,CAAC;IACD,uBAAuB,CACrB,GAAmB,EACnB,gBAAwB,EACxB,gBAAyB;QAEzB,MAAM,QAAQ,GAAG,KAAK,CAAC,uBAAuB,CAC5C,GAAG,EACH,gBAAgB,EAChB,gBAAgB,CACjB,CAAC;QACF,OAAO,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IACrE,CAAC;IAEO,YAAY,CAAC,QAAgB;QACnC,OAAO,IAAA,mBAAU,EAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,CAAC;CACF;AA7BD,8DA6BC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
/// <reference types="node" />
|
|
5
|
+
import { AssetStorageStrategy } from "@deenruv/core";
|
|
6
|
+
import { Request } from "express";
|
|
7
|
+
import { ReadStream } from "fs";
|
|
8
|
+
import { Stream } from "stream";
|
|
9
|
+
/**
|
|
10
|
+
* @description
|
|
11
|
+
* A persistence strategy which saves files to the local file system.
|
|
12
|
+
*
|
|
13
|
+
* @docsCategory core plugins/AssetServerPlugin
|
|
14
|
+
*/
|
|
15
|
+
export declare class LocalAssetStorageStrategy implements AssetStorageStrategy {
|
|
16
|
+
private readonly uploadPath;
|
|
17
|
+
private readonly toAbsoluteUrlFn?;
|
|
18
|
+
toAbsoluteUrl: ((reqest: Request, identifier: string) => string) | undefined;
|
|
19
|
+
constructor(uploadPath: string, toAbsoluteUrlFn?: ((reqest: Request, identifier: string) => string) | undefined);
|
|
20
|
+
writeFileFromStream(fileName: string, data: ReadStream): Promise<string>;
|
|
21
|
+
writeFileFromBuffer(fileName: string, data: Buffer): Promise<string>;
|
|
22
|
+
fileExists(fileName: string): Promise<boolean>;
|
|
23
|
+
readFileToBuffer(identifier: string): Promise<Buffer>;
|
|
24
|
+
readFileToStream(identifier: string): Promise<Stream>;
|
|
25
|
+
deleteFile(identifier: string): Promise<void>;
|
|
26
|
+
private filePathToIdentifier;
|
|
27
|
+
private identifierToFilePath;
|
|
28
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LocalAssetStorageStrategy = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* @description
|
|
11
|
+
* A persistence strategy which saves files to the local file system.
|
|
12
|
+
*
|
|
13
|
+
* @docsCategory core plugins/AssetServerPlugin
|
|
14
|
+
*/
|
|
15
|
+
class LocalAssetStorageStrategy {
|
|
16
|
+
constructor(uploadPath, toAbsoluteUrlFn) {
|
|
17
|
+
this.uploadPath = uploadPath;
|
|
18
|
+
this.toAbsoluteUrlFn = toAbsoluteUrlFn;
|
|
19
|
+
fs_extra_1.default.ensureDirSync(this.uploadPath);
|
|
20
|
+
if (toAbsoluteUrlFn) {
|
|
21
|
+
this.toAbsoluteUrl = toAbsoluteUrlFn;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async writeFileFromStream(fileName, data) {
|
|
25
|
+
const filePath = path_1.default.join(this.uploadPath, fileName);
|
|
26
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
27
|
+
const writeStream = fs_extra_1.default.createWriteStream(filePath, "binary");
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
data.pipe(writeStream);
|
|
30
|
+
writeStream.on("close", () => resolve(this.filePathToIdentifier(filePath)));
|
|
31
|
+
writeStream.on("error", reject);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async writeFileFromBuffer(fileName, data) {
|
|
35
|
+
const filePath = path_1.default.join(this.uploadPath, fileName);
|
|
36
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
37
|
+
await fs_extra_1.default.writeFile(filePath, data, "binary");
|
|
38
|
+
return this.filePathToIdentifier(filePath);
|
|
39
|
+
}
|
|
40
|
+
fileExists(fileName) {
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
fs_extra_1.default.access(this.identifierToFilePath(fileName), fs_extra_1.default.constants.F_OK, (err) => {
|
|
43
|
+
resolve(!err);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
readFileToBuffer(identifier) {
|
|
48
|
+
return fs_extra_1.default.readFile(this.identifierToFilePath(identifier));
|
|
49
|
+
}
|
|
50
|
+
readFileToStream(identifier) {
|
|
51
|
+
const readStream = fs_extra_1.default.createReadStream(this.identifierToFilePath(identifier), "binary");
|
|
52
|
+
return Promise.resolve(readStream);
|
|
53
|
+
}
|
|
54
|
+
deleteFile(identifier) {
|
|
55
|
+
return fs_extra_1.default.unlink(this.identifierToFilePath(identifier));
|
|
56
|
+
}
|
|
57
|
+
filePathToIdentifier(filePath) {
|
|
58
|
+
const filePathDirname = path_1.default.dirname(filePath);
|
|
59
|
+
const deltaDirname = filePathDirname.replace(this.uploadPath, "");
|
|
60
|
+
const identifier = path_1.default.join(deltaDirname, path_1.default.basename(filePath));
|
|
61
|
+
return identifier.replace(/^[\\/]+/, "");
|
|
62
|
+
}
|
|
63
|
+
identifierToFilePath(identifier) {
|
|
64
|
+
return path_1.default.join(this.uploadPath, identifier);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.LocalAssetStorageStrategy = LocalAssetStorageStrategy;
|
|
68
|
+
//# sourceMappingURL=local-asset-storage-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-asset-storage-strategy.js","sourceRoot":"","sources":["../../src/local-asset-storage-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { MiddlewareConsumer, NestModule, OnApplicationBootstrap } from "@nestjs/common";
|
|
2
|
+
import { Type } from "@deenruv/common/lib/shared-types";
|
|
3
|
+
import { ProcessContext, RuntimeDeenruvConfig } from "@deenruv/core";
|
|
4
|
+
import { AssetServerOptions } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* The `AssetServerPlugin` serves assets (images and other files) from the local file system, and can also be configured to use
|
|
8
|
+
* other storage strategies (e.g. {@link S3AssetStorageStrategy}. It can also perform on-the-fly image transformations
|
|
9
|
+
* and caches the results for subsequent calls.
|
|
10
|
+
*
|
|
11
|
+
* ## Installation
|
|
12
|
+
*
|
|
13
|
+
* `yarn add \@deenruv/asset-server-plugin`
|
|
14
|
+
*
|
|
15
|
+
* or
|
|
16
|
+
*
|
|
17
|
+
* `npm install \@deenruv/asset-server-plugin`
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { AssetServerPlugin } from '\@deenruv/asset-server-plugin';
|
|
22
|
+
*
|
|
23
|
+
* const config: DeenruvConfig = {
|
|
24
|
+
* // Add an instance of the plugin to the plugins array
|
|
25
|
+
* plugins: [
|
|
26
|
+
* AssetServerPlugin.init({
|
|
27
|
+
* route: 'assets',
|
|
28
|
+
* assetUploadDir: path.join(__dirname, 'assets'),
|
|
29
|
+
* }),
|
|
30
|
+
* ],
|
|
31
|
+
* };
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* The full configuration is documented at [AssetServerOptions](/reference/core-plugins/asset-server-plugin/asset-server-options)
|
|
35
|
+
*
|
|
36
|
+
* ## Image transformation
|
|
37
|
+
*
|
|
38
|
+
* Asset preview images can be transformed (resized & cropped) on the fly by appending query parameters to the url:
|
|
39
|
+
*
|
|
40
|
+
* `http://localhost:3000/assets/some-asset.jpg?w=500&h=300&mode=resize`
|
|
41
|
+
*
|
|
42
|
+
* The above URL will return `some-asset.jpg`, resized to fit in the bounds of a 500px x 300px rectangle.
|
|
43
|
+
*
|
|
44
|
+
* ### Preview mode
|
|
45
|
+
*
|
|
46
|
+
* The `mode` parameter can be either `crop` or `resize`. See the [ImageTransformMode](/reference/core-plugins/asset-server-plugin/image-transform-mode) docs for details.
|
|
47
|
+
*
|
|
48
|
+
* ### Focal point
|
|
49
|
+
*
|
|
50
|
+
* When cropping an image (`mode=crop`), Deenruv will attempt to keep the most "interesting" area of the image in the cropped frame. It does this
|
|
51
|
+
* by finding the area of the image with highest entropy (the busiest area of the image). However, sometimes this does not yield a satisfactory
|
|
52
|
+
* result - part or all of the main subject may still be cropped out.
|
|
53
|
+
*
|
|
54
|
+
* This is where specifying the focal point can help. The focal point of the image may be specified by passing the `fpx` and `fpy` query parameters.
|
|
55
|
+
* These are normalized coordinates (i.e. a number between 0 and 1), so the `fpx=0&fpy=0` corresponds to the top left of the image.
|
|
56
|
+
*
|
|
57
|
+
* For example, let's say there is a very wide landscape image which we want to crop to be square. The main subject is a house to the far left of the
|
|
58
|
+
* image. The following query would crop it to a square with the house centered:
|
|
59
|
+
*
|
|
60
|
+
* `http://localhost:3000/assets/landscape.jpg?w=150&h=150&mode=crop&fpx=0.2&fpy=0.7`
|
|
61
|
+
*
|
|
62
|
+
* ### Format
|
|
63
|
+
*
|
|
64
|
+
* Since v1.7.0, the image format can be specified by adding the `format` query parameter:
|
|
65
|
+
*
|
|
66
|
+
* `http://localhost:3000/assets/some-asset.jpg?format=webp`
|
|
67
|
+
*
|
|
68
|
+
* This means that, no matter the format of your original asset files, you can use more modern formats in your storefront if the browser
|
|
69
|
+
* supports them. Supported values for `format` are:
|
|
70
|
+
*
|
|
71
|
+
* * `jpeg` or `jpg`
|
|
72
|
+
* * `png`
|
|
73
|
+
* * `webp`
|
|
74
|
+
* * `avif`
|
|
75
|
+
*
|
|
76
|
+
* The `format` parameter can also be combined with presets (see below).
|
|
77
|
+
*
|
|
78
|
+
* ### Quality
|
|
79
|
+
*
|
|
80
|
+
* Since v2.2.0, the image quality can be specified by adding the `q` query parameter:
|
|
81
|
+
*
|
|
82
|
+
* `http://localhost:3000/assets/some-asset.jpg?q=75`
|
|
83
|
+
*
|
|
84
|
+
* This applies to the `jpg`, `webp` and `avif` formats. The default quality value for `jpg` and `webp` is 80, and for `avif` is 50.
|
|
85
|
+
*
|
|
86
|
+
* The `q` parameter can also be combined with presets (see below).
|
|
87
|
+
*
|
|
88
|
+
* ### Transform presets
|
|
89
|
+
*
|
|
90
|
+
* Presets can be defined which allow a single preset name to be used instead of specifying the width, height and mode. Presets are
|
|
91
|
+
* configured via the AssetServerOptions [presets property](/reference/core-plugins/asset-server-plugin/asset-server-options/#presets).
|
|
92
|
+
*
|
|
93
|
+
* For example, defining the following preset:
|
|
94
|
+
*
|
|
95
|
+
* ```ts
|
|
96
|
+
* AssetServerPlugin.init({
|
|
97
|
+
* // ...
|
|
98
|
+
* presets: [
|
|
99
|
+
* { name: 'my-preset', width: 85, height: 85, mode: 'crop' },
|
|
100
|
+
* ],
|
|
101
|
+
* }),
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* means that a request to:
|
|
105
|
+
*
|
|
106
|
+
* `http://localhost:3000/assets/some-asset.jpg?preset=my-preset`
|
|
107
|
+
*
|
|
108
|
+
* is equivalent to:
|
|
109
|
+
*
|
|
110
|
+
* `http://localhost:3000/assets/some-asset.jpg?w=85&h=85&mode=crop`
|
|
111
|
+
*
|
|
112
|
+
* The AssetServerPlugin comes pre-configured with the following presets:
|
|
113
|
+
*
|
|
114
|
+
* name | width | height | mode
|
|
115
|
+
* -----|-------|--------|-----
|
|
116
|
+
* tiny | 50px | 50px | crop
|
|
117
|
+
* thumb | 150px | 150px | crop
|
|
118
|
+
* small | 300px | 300px | resize
|
|
119
|
+
* medium | 500px | 500px | resize
|
|
120
|
+
* large | 800px | 800px | resize
|
|
121
|
+
*
|
|
122
|
+
* ### Caching
|
|
123
|
+
* By default, the AssetServerPlugin will cache every transformed image, so that the transformation only needs to be performed a single time for
|
|
124
|
+
* a given configuration. Caching can be disabled per-request by setting the `?cache=false` query parameter.
|
|
125
|
+
*
|
|
126
|
+
* @docsCategory core plugins/AssetServerPlugin
|
|
127
|
+
*/
|
|
128
|
+
export declare class AssetServerPlugin implements NestModule, OnApplicationBootstrap {
|
|
129
|
+
private processContext;
|
|
130
|
+
private static assetStorage;
|
|
131
|
+
private readonly cacheDir;
|
|
132
|
+
private presets;
|
|
133
|
+
private static options;
|
|
134
|
+
private cacheHeader;
|
|
135
|
+
/**
|
|
136
|
+
* @description
|
|
137
|
+
* Set the plugin options.
|
|
138
|
+
*/
|
|
139
|
+
static init(options: AssetServerOptions): Type<AssetServerPlugin>;
|
|
140
|
+
/** @internal */
|
|
141
|
+
static configure(config: RuntimeDeenruvConfig): Promise<RuntimeDeenruvConfig>;
|
|
142
|
+
constructor(processContext: ProcessContext);
|
|
143
|
+
/** @internal */
|
|
144
|
+
onApplicationBootstrap(): void;
|
|
145
|
+
configure(consumer: MiddlewareConsumer): void;
|
|
146
|
+
/**
|
|
147
|
+
* Creates the image server instance
|
|
148
|
+
*/
|
|
149
|
+
private createAssetServer;
|
|
150
|
+
/**
|
|
151
|
+
* Reads the file requested and send the response to the browser.
|
|
152
|
+
*/
|
|
153
|
+
private sendAsset;
|
|
154
|
+
/**
|
|
155
|
+
* If an exception was thrown by the first handler, then it may be because a transformed image
|
|
156
|
+
* is being requested which does not yet exist. In this case, this handler will generate the
|
|
157
|
+
* transformed image, save it to cache, and serve the result as a response.
|
|
158
|
+
*/
|
|
159
|
+
private generateTransformedImage;
|
|
160
|
+
private getFileNameFromRequest;
|
|
161
|
+
private md5;
|
|
162
|
+
private addSuffix;
|
|
163
|
+
/**
|
|
164
|
+
* Attempt to get the mime type from the file name.
|
|
165
|
+
*/
|
|
166
|
+
private getMimeType;
|
|
167
|
+
}
|