@inoo-ch/payload-image-optimizer 1.1.0 → 1.2.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/AGENT_DOCS.md +383 -0
- package/dist/components/ImageBox.d.ts +1 -15
- package/dist/components/ImageBox.js.map +1 -1
- package/dist/components/OptimizationStatus.js +84 -19
- package/dist/components/OptimizationStatus.js.map +1 -1
- package/dist/fields/imageOptimizerField.d.ts +4 -2
- package/dist/fields/imageOptimizerField.js +57 -54
- package/dist/fields/imageOptimizerField.js.map +1 -1
- package/dist/hooks/afterChange.js +2 -4
- package/dist/hooks/afterChange.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +123 -105
- package/dist/index.js.map +1 -1
- package/dist/tasks/convertFormats.js +2 -4
- package/dist/tasks/convertFormats.js.map +1 -1
- package/dist/tasks/regenerateDocument.js +2 -4
- package/dist/tasks/regenerateDocument.js.map +1 -1
- package/dist/translations/index.d.ts +1 -0
- package/dist/translations/index.js +64 -0
- package/dist/translations/index.js.map +1 -0
- package/dist/types.d.ts +19 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/getImageOptimizerProps.d.ts +2 -10
- package/dist/utilities/getImageOptimizerProps.js.map +1 -1
- package/dist/utilities/resolveStaticDir.d.ts +3 -0
- package/dist/utilities/resolveStaticDir.js +10 -0
- package/dist/utilities/resolveStaticDir.js.map +1 -0
- package/package.json +36 -61
- package/src/components/ImageBox.tsx +65 -0
- package/src/components/OptimizationStatus.tsx +216 -0
- package/src/components/RegenerationButton.tsx +356 -0
- package/src/defaults.ts +36 -0
- package/src/endpoints/regenerate.ts +125 -0
- package/src/exports/client.ts +6 -0
- package/src/exports/rsc.ts +1 -0
- package/src/fields/imageOptimizerField.ts +76 -0
- package/src/hooks/afterChange.ts +73 -0
- package/src/hooks/beforeChange.ts +64 -0
- package/src/index.ts +124 -0
- package/src/next-image.d.ts +3 -0
- package/src/processing/index.ts +59 -0
- package/src/tasks/convertFormats.ts +104 -0
- package/src/tasks/regenerateDocument.ts +174 -0
- package/src/translations/index.ts +62 -0
- package/src/types.ts +57 -0
- package/src/utilities/getImageOptimizerProps.ts +50 -0
- package/src/utilities/resolveStaticDir.ts +12 -0
- package/src/utilities/thumbhash.ts +15 -0
|
@@ -1,75 +1,78 @@
|
|
|
1
|
-
export const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
export const defaultImageOptimizerFields = [
|
|
2
|
+
{
|
|
3
|
+
name: 'thumbHash',
|
|
4
|
+
type: 'text'
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
name: 'originalSize',
|
|
8
|
+
type: 'number'
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'optimizedSize',
|
|
12
|
+
type: 'number'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'status',
|
|
16
|
+
type: 'select',
|
|
17
|
+
options: [
|
|
18
|
+
'pending',
|
|
19
|
+
'processing',
|
|
20
|
+
'complete',
|
|
21
|
+
'error'
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'error',
|
|
26
|
+
type: 'text'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'variants',
|
|
30
|
+
type: 'array',
|
|
11
31
|
fields: [
|
|
12
32
|
{
|
|
13
|
-
name: '
|
|
33
|
+
name: 'format',
|
|
34
|
+
type: 'text'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'filename',
|
|
14
38
|
type: 'text'
|
|
15
39
|
},
|
|
16
40
|
{
|
|
17
|
-
name: '
|
|
41
|
+
name: 'filesize',
|
|
18
42
|
type: 'number'
|
|
19
43
|
},
|
|
20
44
|
{
|
|
21
|
-
name: '
|
|
45
|
+
name: 'width',
|
|
22
46
|
type: 'number'
|
|
23
47
|
},
|
|
24
48
|
{
|
|
25
|
-
name: '
|
|
26
|
-
type: '
|
|
27
|
-
options: [
|
|
28
|
-
'pending',
|
|
29
|
-
'processing',
|
|
30
|
-
'complete',
|
|
31
|
-
'error'
|
|
32
|
-
]
|
|
49
|
+
name: 'height',
|
|
50
|
+
type: 'number'
|
|
33
51
|
},
|
|
34
52
|
{
|
|
35
|
-
name: '
|
|
53
|
+
name: 'mimeType',
|
|
36
54
|
type: 'text'
|
|
37
55
|
},
|
|
38
56
|
{
|
|
39
|
-
name: '
|
|
40
|
-
type: '
|
|
41
|
-
fields: [
|
|
42
|
-
{
|
|
43
|
-
name: 'format',
|
|
44
|
-
type: 'text'
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
name: 'filename',
|
|
48
|
-
type: 'text'
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
name: 'filesize',
|
|
52
|
-
type: 'number'
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: 'width',
|
|
56
|
-
type: 'number'
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: 'height',
|
|
60
|
-
type: 'number'
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: 'mimeType',
|
|
64
|
-
type: 'text'
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
name: 'url',
|
|
68
|
-
type: 'text'
|
|
69
|
-
}
|
|
70
|
-
]
|
|
57
|
+
name: 'url',
|
|
58
|
+
type: 'text'
|
|
71
59
|
}
|
|
72
60
|
]
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
export const getImageOptimizerField = (fieldsOverride)=>({
|
|
64
|
+
name: 'imageOptimizer',
|
|
65
|
+
type: 'group',
|
|
66
|
+
admin: {
|
|
67
|
+
position: 'sidebar',
|
|
68
|
+
readOnly: true,
|
|
69
|
+
components: {
|
|
70
|
+
Field: '@inoo-ch/payload-image-optimizer/client#OptimizationStatus'
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
fields: fieldsOverride ? fieldsOverride({
|
|
74
|
+
defaultFields: defaultImageOptimizerFields
|
|
75
|
+
}) : defaultImageOptimizerFields
|
|
73
76
|
});
|
|
74
77
|
|
|
75
78
|
//# sourceMappingURL=imageOptimizerField.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fields/imageOptimizerField.ts"],"sourcesContent":["import type { GroupField } from 'payload'\n\
|
|
1
|
+
{"version":3,"sources":["../../src/fields/imageOptimizerField.ts"],"sourcesContent":["import type { Field, GroupField } from 'payload'\n\nimport type { FieldsOverride } from '../types.js'\n\nexport const defaultImageOptimizerFields: Field[] = [\n {\n name: 'thumbHash',\n type: 'text',\n },\n {\n name: 'originalSize',\n type: 'number',\n },\n {\n name: 'optimizedSize',\n type: 'number',\n },\n {\n name: 'status',\n type: 'select',\n options: ['pending', 'processing', 'complete', 'error'],\n },\n {\n name: 'error',\n type: 'text',\n },\n {\n name: 'variants',\n type: 'array',\n fields: [\n {\n name: 'format',\n type: 'text',\n },\n {\n name: 'filename',\n type: 'text',\n },\n {\n name: 'filesize',\n type: 'number',\n },\n {\n name: 'width',\n type: 'number',\n },\n {\n name: 'height',\n type: 'number',\n },\n {\n name: 'mimeType',\n type: 'text',\n },\n {\n name: 'url',\n type: 'text',\n },\n ],\n },\n]\n\nexport const getImageOptimizerField = (fieldsOverride?: FieldsOverride): GroupField => ({\n name: 'imageOptimizer',\n type: 'group',\n admin: {\n position: 'sidebar',\n readOnly: true,\n components: {\n Field: '@inoo-ch/payload-image-optimizer/client#OptimizationStatus',\n },\n },\n fields: fieldsOverride\n ? fieldsOverride({ defaultFields: defaultImageOptimizerFields })\n : defaultImageOptimizerFields,\n})\n"],"names":["defaultImageOptimizerFields","name","type","options","fields","getImageOptimizerField","fieldsOverride","admin","position","readOnly","components","Field","defaultFields"],"mappings":"AAIA,OAAO,MAAMA,8BAAuC;IAClD;QACEC,MAAM;QACNC,MAAM;IACR;IACA;QACED,MAAM;QACNC,MAAM;IACR;IACA;QACED,MAAM;QACNC,MAAM;IACR;IACA;QACED,MAAM;QACNC,MAAM;QACNC,SAAS;YAAC;YAAW;YAAc;YAAY;SAAQ;IACzD;IACA;QACEF,MAAM;QACNC,MAAM;IACR;IACA;QACED,MAAM;QACNC,MAAM;QACNE,QAAQ;YACN;gBACEH,MAAM;gBACNC,MAAM;YACR;YACA;gBACED,MAAM;gBACNC,MAAM;YACR;YACA;gBACED,MAAM;gBACNC,MAAM;YACR;YACA;gBACED,MAAM;gBACNC,MAAM;YACR;YACA;gBACED,MAAM;gBACNC,MAAM;YACR;YACA;gBACED,MAAM;gBACNC,MAAM;YACR;YACA;gBACED,MAAM;gBACNC,MAAM;YACR;SACD;IACH;CACD,CAAA;AAED,OAAO,MAAMG,yBAAyB,CAACC,iBAAiD,CAAA;QACtFL,MAAM;QACNC,MAAM;QACNK,OAAO;YACLC,UAAU;YACVC,UAAU;YACVC,YAAY;gBACVC,OAAO;YACT;QACF;QACAP,QAAQE,iBACJA,eAAe;YAAEM,eAAeZ;QAA4B,KAC5DA;IACN,CAAA,EAAE"}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { resolveCollectionConfig } from '../defaults.js';
|
|
4
|
+
import { resolveStaticDir } from '../utilities/resolveStaticDir.js';
|
|
4
5
|
export const createAfterChangeHook = (resolvedConfig, collectionSlug)=>{
|
|
5
6
|
return async ({ context, doc, req })=>{
|
|
6
7
|
if (context?.imageOptimizer_skip) return doc;
|
|
7
8
|
if (!req.file || !req.file.data || !req.file.mimetype?.startsWith('image/')) return doc;
|
|
8
9
|
const collectionConfig = req.payload.collections[collectionSlug].config;
|
|
9
|
-
|
|
10
|
-
if (staticDir && !path.isAbsolute(staticDir)) {
|
|
11
|
-
staticDir = path.resolve(process.cwd(), staticDir);
|
|
12
|
-
}
|
|
10
|
+
const staticDir = resolveStaticDir(collectionConfig);
|
|
13
11
|
const perCollectionConfig = resolveCollectionConfig(resolvedConfig, collectionSlug);
|
|
14
12
|
// Overwrite the file on disk with the processed (stripped/resized/converted) buffer
|
|
15
13
|
// Payload 3.0 writes the original buffer to disk; we replace it here
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/afterChange.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\nimport type { CollectionAfterChangeHook } from 'payload'\n\nimport type { ResolvedImageOptimizerConfig } from '../types.js'\nimport { resolveCollectionConfig } from '../defaults.js'\n\nexport const createAfterChangeHook = (\n resolvedConfig: ResolvedImageOptimizerConfig,\n collectionSlug: string,\n): CollectionAfterChangeHook => {\n return async ({ context, doc, req }) => {\n if (context?.imageOptimizer_skip) return doc\n\n if (!req.file || !req.file.data || !req.file.mimetype?.startsWith('image/')) return doc\n\n const collectionConfig = req.payload.collections[collectionSlug as keyof typeof req.payload.collections].config\n
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterChange.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\nimport type { CollectionAfterChangeHook } from 'payload'\n\nimport type { ResolvedImageOptimizerConfig } from '../types.js'\nimport { resolveCollectionConfig } from '../defaults.js'\nimport { resolveStaticDir } from '../utilities/resolveStaticDir.js'\n\nexport const createAfterChangeHook = (\n resolvedConfig: ResolvedImageOptimizerConfig,\n collectionSlug: string,\n): CollectionAfterChangeHook => {\n return async ({ context, doc, req }) => {\n if (context?.imageOptimizer_skip) return doc\n\n if (!req.file || !req.file.data || !req.file.mimetype?.startsWith('image/')) return doc\n\n const collectionConfig = req.payload.collections[collectionSlug as keyof typeof req.payload.collections].config\n const staticDir = resolveStaticDir(collectionConfig)\n\n const perCollectionConfig = resolveCollectionConfig(resolvedConfig, collectionSlug)\n\n // Overwrite the file on disk with the processed (stripped/resized/converted) buffer\n // Payload 3.0 writes the original buffer to disk; we replace it here\n const processedBuffer = context.imageOptimizer_processedBuffer as Buffer | undefined\n if (processedBuffer && doc.filename && staticDir) {\n const safeFilename = path.basename(doc.filename as string)\n const filePath = path.join(staticDir, safeFilename)\n await fs.writeFile(filePath, processedBuffer)\n\n // If replaceOriginal changed the filename, clean up the old file Payload wrote\n const originalFilename = context.imageOptimizer_originalFilename as string | undefined\n if (originalFilename && originalFilename !== safeFilename) {\n const oldFilePath = path.join(staticDir, path.basename(originalFilename))\n await fs.unlink(oldFilePath).catch(() => {\n // Old file may not exist if Payload used the new filename\n })\n }\n }\n\n // When replaceOriginal is on and only one format is configured, the main file\n // is already converted — skip the async job and mark complete immediately.\n if (perCollectionConfig.replaceOriginal && perCollectionConfig.formats.length <= 1) {\n await req.payload.update({\n collection: collectionSlug,\n id: doc.id,\n data: {\n imageOptimizer: {\n status: 'complete',\n variants: [],\n },\n },\n context: { imageOptimizer_skip: true },\n })\n return doc\n }\n\n // Queue async format conversion job for remaining variants\n await req.payload.jobs.queue({\n task: 'imageOptimizer_convertFormats',\n input: {\n collectionSlug,\n docId: String(doc.id),\n },\n })\n\n req.payload.jobs.run().catch((err: unknown) => {\n req.payload.logger.error({ err }, 'Image optimizer job runner failed')\n })\n\n return doc\n }\n}\n"],"names":["fs","path","resolveCollectionConfig","resolveStaticDir","createAfterChangeHook","resolvedConfig","collectionSlug","context","doc","req","imageOptimizer_skip","file","data","mimetype","startsWith","collectionConfig","payload","collections","config","staticDir","perCollectionConfig","processedBuffer","imageOptimizer_processedBuffer","filename","safeFilename","basename","filePath","join","writeFile","originalFilename","imageOptimizer_originalFilename","oldFilePath","unlink","catch","replaceOriginal","formats","length","update","collection","id","imageOptimizer","status","variants","jobs","queue","task","input","docId","String","run","err","logger","error"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAC5B,OAAOC,UAAU,OAAM;AAIvB,SAASC,uBAAuB,QAAQ,iBAAgB;AACxD,SAASC,gBAAgB,QAAQ,mCAAkC;AAEnE,OAAO,MAAMC,wBAAwB,CACnCC,gBACAC;IAEA,OAAO,OAAO,EAAEC,OAAO,EAAEC,GAAG,EAAEC,GAAG,EAAE;QACjC,IAAIF,SAASG,qBAAqB,OAAOF;QAEzC,IAAI,CAACC,IAAIE,IAAI,IAAI,CAACF,IAAIE,IAAI,CAACC,IAAI,IAAI,CAACH,IAAIE,IAAI,CAACE,QAAQ,EAAEC,WAAW,WAAW,OAAON;QAEpF,MAAMO,mBAAmBN,IAAIO,OAAO,CAACC,WAAW,CAACX,eAAuD,CAACY,MAAM;QAC/G,MAAMC,YAAYhB,iBAAiBY;QAEnC,MAAMK,sBAAsBlB,wBAAwBG,gBAAgBC;QAEpE,oFAAoF;QACpF,qEAAqE;QACrE,MAAMe,kBAAkBd,QAAQe,8BAA8B;QAC9D,IAAID,mBAAmBb,IAAIe,QAAQ,IAAIJ,WAAW;YAChD,MAAMK,eAAevB,KAAKwB,QAAQ,CAACjB,IAAIe,QAAQ;YAC/C,MAAMG,WAAWzB,KAAK0B,IAAI,CAACR,WAAWK;YACtC,MAAMxB,GAAG4B,SAAS,CAACF,UAAUL;YAE7B,+EAA+E;YAC/E,MAAMQ,mBAAmBtB,QAAQuB,+BAA+B;YAChE,IAAID,oBAAoBA,qBAAqBL,cAAc;gBACzD,MAAMO,cAAc9B,KAAK0B,IAAI,CAACR,WAAWlB,KAAKwB,QAAQ,CAACI;gBACvD,MAAM7B,GAAGgC,MAAM,CAACD,aAAaE,KAAK,CAAC;gBACjC,0DAA0D;gBAC5D;YACF;QACF;QAEA,8EAA8E;QAC9E,2EAA2E;QAC3E,IAAIb,oBAAoBc,eAAe,IAAId,oBAAoBe,OAAO,CAACC,MAAM,IAAI,GAAG;YAClF,MAAM3B,IAAIO,OAAO,CAACqB,MAAM,CAAC;gBACvBC,YAAYhC;gBACZiC,IAAI/B,IAAI+B,EAAE;gBACV3B,MAAM;oBACJ4B,gBAAgB;wBACdC,QAAQ;wBACRC,UAAU,EAAE;oBACd;gBACF;gBACAnC,SAAS;oBAAEG,qBAAqB;gBAAK;YACvC;YACA,OAAOF;QACT;QAEA,2DAA2D;QAC3D,MAAMC,IAAIO,OAAO,CAAC2B,IAAI,CAACC,KAAK,CAAC;YAC3BC,MAAM;YACNC,OAAO;gBACLxC;gBACAyC,OAAOC,OAAOxC,IAAI+B,EAAE;YACtB;QACF;QAEA9B,IAAIO,OAAO,CAAC2B,IAAI,CAACM,GAAG,GAAGhB,KAAK,CAAC,CAACiB;YAC5BzC,IAAIO,OAAO,CAACmC,MAAM,CAACC,KAAK,CAAC;gBAAEF;YAAI,GAAG;QACpC;QAEA,OAAO1C;IACT;AACF,EAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Config } from 'payload';
|
|
2
2
|
import type { ImageOptimizerConfig } from './types.js';
|
|
3
|
-
export type { ImageOptimizerConfig, ImageFormat, FormatQuality, CollectionOptimizerConfig } from './types.js';
|
|
3
|
+
export type { ImageOptimizerConfig, ImageFormat, FormatQuality, CollectionOptimizerConfig, ImageOptimizerData, MediaResource, FieldsOverride } from './types.js';
|
|
4
|
+
export { defaultImageOptimizerFields } from './fields/imageOptimizerField.js';
|
|
4
5
|
export { encodeImageToThumbHash, decodeThumbHashToDataURL } from './utilities/thumbhash.js';
|
|
5
6
|
export declare const imageOptimizer: (pluginOptions: ImageOptimizerConfig) => (config: Config) => Config;
|
package/dist/index.js
CHANGED
|
@@ -1,127 +1,145 @@
|
|
|
1
|
+
import { deepMergeSimple } from 'payload/shared';
|
|
1
2
|
import { resolveConfig } from './defaults.js';
|
|
3
|
+
import { translations } from './translations/index.js';
|
|
2
4
|
import { getImageOptimizerField } from './fields/imageOptimizerField.js';
|
|
3
5
|
import { createBeforeChangeHook } from './hooks/beforeChange.js';
|
|
4
6
|
import { createAfterChangeHook } from './hooks/afterChange.js';
|
|
5
7
|
import { createConvertFormatsHandler } from './tasks/convertFormats.js';
|
|
6
8
|
import { createRegenerateDocumentHandler } from './tasks/regenerateDocument.js';
|
|
7
9
|
import { createRegenerateHandler, createRegenerateStatusHandler } from './endpoints/regenerate.js';
|
|
10
|
+
export { defaultImageOptimizerFields } from './fields/imageOptimizerField.js';
|
|
8
11
|
export { encodeImageToThumbHash, decodeThumbHashToDataURL } from './utilities/thumbhash.js';
|
|
9
12
|
export const imageOptimizer = (pluginOptions)=>(config)=>{
|
|
10
13
|
const resolvedConfig = resolveConfig(pluginOptions);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const collection = config.collections.find((c)=>c.slug === collectionSlug);
|
|
17
|
-
if (collection) {
|
|
18
|
-
collection.fields.push(getImageOptimizerField());
|
|
14
|
+
const targetSlugs = Object.keys(resolvedConfig.collections);
|
|
15
|
+
// Inject fields (and hooks when enabled) into targeted upload collections
|
|
16
|
+
const collections = (config.collections || []).map((collection)=>{
|
|
17
|
+
if (!targetSlugs.includes(collection.slug)) {
|
|
18
|
+
return collection;
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
collection.hooks = {};
|
|
31
|
-
}
|
|
32
|
-
if (!collection.hooks.beforeChange) {
|
|
33
|
-
collection.hooks.beforeChange = [];
|
|
34
|
-
}
|
|
35
|
-
collection.hooks.beforeChange.push(createBeforeChangeHook(resolvedConfig, collectionSlug));
|
|
36
|
-
if (!collection.hooks.afterChange) {
|
|
37
|
-
collection.hooks.afterChange = [];
|
|
38
|
-
}
|
|
39
|
-
collection.hooks.afterChange.push(createAfterChangeHook(resolvedConfig, collectionSlug));
|
|
40
|
-
// Add RegenerationButton to the collection list view
|
|
41
|
-
if (!collection.admin) {
|
|
42
|
-
collection.admin = {};
|
|
43
|
-
}
|
|
44
|
-
if (!collection.admin.components) {
|
|
45
|
-
collection.admin.components = {};
|
|
46
|
-
}
|
|
47
|
-
if (!collection.admin.components.beforeListTable) {
|
|
48
|
-
collection.admin.components.beforeListTable = [];
|
|
49
|
-
}
|
|
50
|
-
collection.admin.components.beforeListTable.push('@inoo-ch/payload-image-optimizer/client#RegenerationButton');
|
|
20
|
+
// Always inject fields for schema consistency (even when disabled)
|
|
21
|
+
const fields = [
|
|
22
|
+
...collection.fields,
|
|
23
|
+
getImageOptimizerField(pluginOptions.fieldsOverride)
|
|
24
|
+
];
|
|
25
|
+
if (resolvedConfig.disabled) {
|
|
26
|
+
return {
|
|
27
|
+
...collection,
|
|
28
|
+
fields
|
|
29
|
+
};
|
|
51
30
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
name: 'collectionSlug',
|
|
67
|
-
type: 'text',
|
|
68
|
-
required: true
|
|
31
|
+
return {
|
|
32
|
+
...collection,
|
|
33
|
+
fields,
|
|
34
|
+
hooks: {
|
|
35
|
+
...collection.hooks,
|
|
36
|
+
beforeChange: [
|
|
37
|
+
...collection.hooks?.beforeChange || [],
|
|
38
|
+
createBeforeChangeHook(resolvedConfig, collection.slug)
|
|
39
|
+
],
|
|
40
|
+
afterChange: [
|
|
41
|
+
...collection.hooks?.afterChange || [],
|
|
42
|
+
createAfterChangeHook(resolvedConfig, collection.slug)
|
|
43
|
+
]
|
|
69
44
|
},
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
type: 'number'
|
|
45
|
+
admin: {
|
|
46
|
+
...collection.admin,
|
|
47
|
+
components: {
|
|
48
|
+
...collection.admin?.components,
|
|
49
|
+
beforeListTable: [
|
|
50
|
+
...collection.admin?.components?.beforeListTable || [],
|
|
51
|
+
'@inoo-ch/payload-image-optimizer/client#RegenerationButton'
|
|
52
|
+
]
|
|
53
|
+
}
|
|
80
54
|
}
|
|
81
|
-
|
|
82
|
-
retries: 2,
|
|
83
|
-
handler: createConvertFormatsHandler(resolvedConfig)
|
|
55
|
+
};
|
|
84
56
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
57
|
+
const i18n = {
|
|
58
|
+
...config.i18n,
|
|
59
|
+
translations: deepMergeSimple(translations, config.i18n?.translations ?? {})
|
|
60
|
+
};
|
|
61
|
+
// If disabled, return with fields injected but no tasks/endpoints
|
|
62
|
+
if (resolvedConfig.disabled) {
|
|
63
|
+
return {
|
|
64
|
+
...config,
|
|
65
|
+
collections,
|
|
66
|
+
i18n
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
...config,
|
|
71
|
+
collections,
|
|
72
|
+
i18n,
|
|
73
|
+
jobs: {
|
|
74
|
+
...config.jobs,
|
|
75
|
+
tasks: [
|
|
76
|
+
...config.jobs?.tasks || [],
|
|
77
|
+
{
|
|
78
|
+
slug: 'imageOptimizer_convertFormats',
|
|
79
|
+
inputSchema: [
|
|
80
|
+
{
|
|
81
|
+
name: 'collectionSlug',
|
|
82
|
+
type: 'text',
|
|
83
|
+
required: true
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'docId',
|
|
87
|
+
type: 'text',
|
|
88
|
+
required: true
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
outputSchema: [
|
|
92
|
+
{
|
|
93
|
+
name: 'variantsGenerated',
|
|
94
|
+
type: 'number'
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
retries: 2,
|
|
98
|
+
handler: createConvertFormatsHandler(resolvedConfig)
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
slug: 'imageOptimizer_regenerateDocument',
|
|
102
|
+
inputSchema: [
|
|
103
|
+
{
|
|
104
|
+
name: 'collectionSlug',
|
|
105
|
+
type: 'text',
|
|
106
|
+
required: true
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'docId',
|
|
110
|
+
type: 'text',
|
|
111
|
+
required: true
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
outputSchema: [
|
|
115
|
+
{
|
|
116
|
+
name: 'status',
|
|
117
|
+
type: 'text'
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'reason',
|
|
121
|
+
type: 'text'
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
retries: 2,
|
|
125
|
+
handler: createRegenerateDocumentHandler(resolvedConfig)
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
endpoints: [
|
|
130
|
+
...config.endpoints ?? [],
|
|
100
131
|
{
|
|
101
|
-
|
|
102
|
-
|
|
132
|
+
path: '/image-optimizer/regenerate',
|
|
133
|
+
method: 'post',
|
|
134
|
+
handler: createRegenerateHandler(resolvedConfig)
|
|
103
135
|
},
|
|
104
136
|
{
|
|
105
|
-
|
|
106
|
-
|
|
137
|
+
path: '/image-optimizer/regenerate',
|
|
138
|
+
method: 'get',
|
|
139
|
+
handler: createRegenerateStatusHandler(resolvedConfig)
|
|
107
140
|
}
|
|
108
|
-
]
|
|
109
|
-
|
|
110
|
-
handler: createRegenerateDocumentHandler(resolvedConfig)
|
|
111
|
-
});
|
|
112
|
-
// Register regeneration endpoints
|
|
113
|
-
if (!config.endpoints) config.endpoints = [];
|
|
114
|
-
config.endpoints.push({
|
|
115
|
-
path: '/image-optimizer/regenerate',
|
|
116
|
-
method: 'post',
|
|
117
|
-
handler: createRegenerateHandler(resolvedConfig)
|
|
118
|
-
});
|
|
119
|
-
config.endpoints.push({
|
|
120
|
-
path: '/image-optimizer/regenerate',
|
|
121
|
-
method: 'get',
|
|
122
|
-
handler: createRegenerateStatusHandler(resolvedConfig)
|
|
123
|
-
});
|
|
124
|
-
return config;
|
|
141
|
+
]
|
|
142
|
+
};
|
|
125
143
|
};
|
|
126
144
|
|
|
127
145
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport type { ImageOptimizerConfig } from './types.js'\nimport { resolveConfig } from './defaults.js'\nimport { getImageOptimizerField } from './fields/imageOptimizerField.js'\nimport { createBeforeChangeHook } from './hooks/beforeChange.js'\nimport { createAfterChangeHook } from './hooks/afterChange.js'\nimport { createConvertFormatsHandler } from './tasks/convertFormats.js'\nimport { createRegenerateDocumentHandler } from './tasks/regenerateDocument.js'\nimport { createRegenerateHandler, createRegenerateStatusHandler } from './endpoints/regenerate.js'\n\nexport type { ImageOptimizerConfig, ImageFormat, FormatQuality, CollectionOptimizerConfig } from './types.js'\n\nexport { encodeImageToThumbHash, decodeThumbHashToDataURL } from './utilities/thumbhash.js'\n\nexport const imageOptimizer =\n (pluginOptions: ImageOptimizerConfig) =>\n (config: Config): Config => {\n const resolvedConfig = resolveConfig(pluginOptions)\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Config } from 'payload'\nimport { deepMergeSimple } from 'payload/shared'\n\nimport type { ImageOptimizerConfig } from './types.js'\nimport { resolveConfig } from './defaults.js'\nimport { translations } from './translations/index.js'\nimport { getImageOptimizerField } from './fields/imageOptimizerField.js'\nimport { createBeforeChangeHook } from './hooks/beforeChange.js'\nimport { createAfterChangeHook } from './hooks/afterChange.js'\nimport { createConvertFormatsHandler } from './tasks/convertFormats.js'\nimport { createRegenerateDocumentHandler } from './tasks/regenerateDocument.js'\nimport { createRegenerateHandler, createRegenerateStatusHandler } from './endpoints/regenerate.js'\n\nexport type { ImageOptimizerConfig, ImageFormat, FormatQuality, CollectionOptimizerConfig, ImageOptimizerData, MediaResource, FieldsOverride } from './types.js'\nexport { defaultImageOptimizerFields } from './fields/imageOptimizerField.js'\n\nexport { encodeImageToThumbHash, decodeThumbHashToDataURL } from './utilities/thumbhash.js'\n\nexport const imageOptimizer =\n (pluginOptions: ImageOptimizerConfig) =>\n (config: Config): Config => {\n const resolvedConfig = resolveConfig(pluginOptions)\n const targetSlugs = Object.keys(resolvedConfig.collections)\n\n // Inject fields (and hooks when enabled) into targeted upload collections\n const collections = (config.collections || []).map((collection) => {\n if (!targetSlugs.includes(collection.slug)) {\n return collection\n }\n\n // Always inject fields for schema consistency (even when disabled)\n const fields = [...collection.fields, getImageOptimizerField(pluginOptions.fieldsOverride)]\n\n if (resolvedConfig.disabled) {\n return { ...collection, fields }\n }\n\n return {\n ...collection,\n fields,\n hooks: {\n ...collection.hooks,\n beforeChange: [\n ...(collection.hooks?.beforeChange || []),\n createBeforeChangeHook(resolvedConfig, collection.slug),\n ],\n afterChange: [\n ...(collection.hooks?.afterChange || []),\n createAfterChangeHook(resolvedConfig, collection.slug),\n ],\n },\n admin: {\n ...collection.admin,\n components: {\n ...collection.admin?.components,\n beforeListTable: [\n ...(collection.admin?.components?.beforeListTable || []),\n '@inoo-ch/payload-image-optimizer/client#RegenerationButton',\n ],\n },\n },\n }\n })\n\n const i18n = {\n ...config.i18n,\n translations: deepMergeSimple(translations, config.i18n?.translations ?? {}),\n }\n\n // If disabled, return with fields injected but no tasks/endpoints\n if (resolvedConfig.disabled) {\n return { ...config, collections, i18n }\n }\n\n return {\n ...config,\n collections,\n i18n,\n jobs: {\n ...config.jobs,\n tasks: [\n ...(config.jobs?.tasks || []),\n {\n slug: 'imageOptimizer_convertFormats',\n inputSchema: [\n { name: 'collectionSlug', type: 'text', required: true },\n { name: 'docId', type: 'text', required: true },\n ],\n outputSchema: [\n { name: 'variantsGenerated', type: 'number' },\n ],\n retries: 2,\n handler: createConvertFormatsHandler(resolvedConfig),\n } as any,\n {\n slug: 'imageOptimizer_regenerateDocument',\n inputSchema: [\n { name: 'collectionSlug', type: 'text', required: true },\n { name: 'docId', type: 'text', required: true },\n ],\n outputSchema: [\n { name: 'status', type: 'text' },\n { name: 'reason', type: 'text' },\n ],\n retries: 2,\n handler: createRegenerateDocumentHandler(resolvedConfig),\n } as any,\n ],\n },\n endpoints: [\n ...(config.endpoints ?? []),\n {\n path: '/image-optimizer/regenerate',\n method: 'post',\n handler: createRegenerateHandler(resolvedConfig),\n },\n {\n path: '/image-optimizer/regenerate',\n method: 'get',\n handler: createRegenerateStatusHandler(resolvedConfig),\n },\n ],\n }\n }\n"],"names":["deepMergeSimple","resolveConfig","translations","getImageOptimizerField","createBeforeChangeHook","createAfterChangeHook","createConvertFormatsHandler","createRegenerateDocumentHandler","createRegenerateHandler","createRegenerateStatusHandler","defaultImageOptimizerFields","encodeImageToThumbHash","decodeThumbHashToDataURL","imageOptimizer","pluginOptions","config","resolvedConfig","targetSlugs","Object","keys","collections","map","collection","includes","slug","fields","fieldsOverride","disabled","hooks","beforeChange","afterChange","admin","components","beforeListTable","i18n","jobs","tasks","inputSchema","name","type","required","outputSchema","retries","handler","endpoints","path","method"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { resolveCollectionConfig } from '../defaults.js';
|
|
4
4
|
import { convertFormat } from '../processing/index.js';
|
|
5
|
+
import { resolveStaticDir } from '../utilities/resolveStaticDir.js';
|
|
5
6
|
export const createConvertFormatsHandler = (resolvedConfig)=>{
|
|
6
7
|
return async ({ input, req })=>{
|
|
7
8
|
try {
|
|
@@ -10,13 +11,10 @@ export const createConvertFormatsHandler = (resolvedConfig)=>{
|
|
|
10
11
|
id: input.docId
|
|
11
12
|
});
|
|
12
13
|
const collectionConfig = req.payload.collections[input.collectionSlug].config;
|
|
13
|
-
|
|
14
|
+
const staticDir = resolveStaticDir(collectionConfig);
|
|
14
15
|
if (!staticDir) {
|
|
15
16
|
throw new Error(`No staticDir configured for collection "${input.collectionSlug}"`);
|
|
16
17
|
}
|
|
17
|
-
if (!path.isAbsolute(staticDir)) {
|
|
18
|
-
staticDir = path.resolve(process.cwd(), staticDir);
|
|
19
|
-
}
|
|
20
18
|
// Sanitize filename to prevent path traversal
|
|
21
19
|
const safeFilename = path.basename(doc.filename);
|
|
22
20
|
const filePath = path.join(staticDir, safeFilename);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/tasks/convertFormats.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\n\nimport type { CollectionSlug } from 'payload'\n\nimport type { ResolvedImageOptimizerConfig } from '../types.js'\nimport { resolveCollectionConfig } from '../defaults.js'\nimport { convertFormat } from '../processing/index.js'\n\nexport const createConvertFormatsHandler = (resolvedConfig: ResolvedImageOptimizerConfig) => {\n return async ({ input, req }: { input: { collectionSlug: string; docId: string }; req: any }) => {\n try {\n const doc = await req.payload.findByID({\n collection: input.collectionSlug as CollectionSlug,\n id: input.docId,\n })\n\n const collectionConfig = req.payload.collections[input.collectionSlug as keyof typeof req.payload.collections].config\n
|
|
1
|
+
{"version":3,"sources":["../../src/tasks/convertFormats.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\n\nimport type { CollectionSlug } from 'payload'\n\nimport type { ResolvedImageOptimizerConfig } from '../types.js'\nimport { resolveCollectionConfig } from '../defaults.js'\nimport { convertFormat } from '../processing/index.js'\nimport { resolveStaticDir } from '../utilities/resolveStaticDir.js'\n\nexport const createConvertFormatsHandler = (resolvedConfig: ResolvedImageOptimizerConfig) => {\n return async ({ input, req }: { input: { collectionSlug: string; docId: string }; req: any }) => {\n try {\n const doc = await req.payload.findByID({\n collection: input.collectionSlug as CollectionSlug,\n id: input.docId,\n })\n\n const collectionConfig = req.payload.collections[input.collectionSlug as keyof typeof req.payload.collections].config\n const staticDir = resolveStaticDir(collectionConfig)\n\n if (!staticDir) {\n throw new Error(`No staticDir configured for collection \"${input.collectionSlug}\"`)\n }\n\n // Sanitize filename to prevent path traversal\n const safeFilename = path.basename(doc.filename)\n const filePath = path.join(staticDir, safeFilename)\n const fileBuffer = await fs.readFile(filePath)\n\n const variants: Array<{\n filename: string\n filesize: number\n format: string\n height: number\n mimeType: string\n url: string\n width: number\n }> = []\n\n const perCollectionConfig = resolveCollectionConfig(resolvedConfig, input.collectionSlug)\n\n // When replaceOriginal is on, the main file is already in the primary format —\n // skip it and only generate variants for the remaining formats.\n const formatsToGenerate = perCollectionConfig.replaceOriginal && perCollectionConfig.formats.length > 0\n ? perCollectionConfig.formats.slice(1)\n : perCollectionConfig.formats\n\n for (const format of formatsToGenerate) {\n const result = await convertFormat(fileBuffer, format.format, format.quality)\n const variantFilename = `${path.parse(safeFilename).name}-optimized.${format.format}`\n\n await fs.writeFile(path.join(staticDir, variantFilename), result.buffer)\n\n variants.push({\n format: format.format,\n filename: variantFilename,\n filesize: result.size,\n width: result.width,\n height: result.height,\n mimeType: result.mimeType,\n url: `/api/${input.collectionSlug}/file/${variantFilename}`,\n })\n }\n\n await req.payload.update({\n collection: input.collectionSlug as CollectionSlug,\n id: input.docId,\n data: {\n imageOptimizer: {\n status: 'complete',\n variants,\n },\n },\n context: { imageOptimizer_skip: true },\n })\n\n return { output: { variantsGenerated: variants.length } }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err)\n\n try {\n await req.payload.update({\n collection: input.collectionSlug as CollectionSlug,\n id: input.docId,\n data: {\n imageOptimizer: {\n status: 'error',\n error: errorMessage,\n },\n },\n context: { imageOptimizer_skip: true },\n })\n } catch (updateErr) {\n req.payload.logger.error(\n { err: updateErr },\n 'Failed to persist error status for image optimizer',\n )\n }\n\n throw err\n }\n }\n}\n"],"names":["fs","path","resolveCollectionConfig","convertFormat","resolveStaticDir","createConvertFormatsHandler","resolvedConfig","input","req","doc","payload","findByID","collection","collectionSlug","id","docId","collectionConfig","collections","config","staticDir","Error","safeFilename","basename","filename","filePath","join","fileBuffer","readFile","variants","perCollectionConfig","formatsToGenerate","replaceOriginal","formats","length","slice","format","result","quality","variantFilename","parse","name","writeFile","buffer","push","filesize","size","width","height","mimeType","url","update","data","imageOptimizer","status","context","imageOptimizer_skip","output","variantsGenerated","err","errorMessage","message","String","error","updateErr","logger"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { resolveCollectionConfig } from '../defaults.js';
|
|
4
4
|
import { stripAndResize, generateThumbHash, convertFormat } from '../processing/index.js';
|
|
5
|
+
import { resolveStaticDir } from '../utilities/resolveStaticDir.js';
|
|
5
6
|
export const createRegenerateDocumentHandler = (resolvedConfig)=>{
|
|
6
7
|
return async ({ input, req })=>{
|
|
7
8
|
try {
|
|
@@ -19,13 +20,10 @@ export const createRegenerateDocumentHandler = (resolvedConfig)=>{
|
|
|
19
20
|
};
|
|
20
21
|
}
|
|
21
22
|
const collectionConfig = req.payload.collections[input.collectionSlug].config;
|
|
22
|
-
|
|
23
|
+
const staticDir = resolveStaticDir(collectionConfig);
|
|
23
24
|
if (!staticDir) {
|
|
24
25
|
throw new Error(`No staticDir configured for collection "${input.collectionSlug}"`);
|
|
25
26
|
}
|
|
26
|
-
if (!path.isAbsolute(staticDir)) {
|
|
27
|
-
staticDir = path.resolve(process.cwd(), staticDir);
|
|
28
|
-
}
|
|
29
27
|
// Sanitize filename to prevent path traversal
|
|
30
28
|
const safeFilename = path.basename(doc.filename);
|
|
31
29
|
const filePath = path.join(staticDir, safeFilename);
|