@payloadcms/plugin-cloud-storage 3.91.0-internal.6e3dc85 → 4.0.0-beta.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.md +1 -1
- package/README.md +4 -4
- package/dist/client/createClientUploadHandler.d.ts +8 -7
- package/dist/client/createClientUploadHandler.d.ts.map +1 -1
- package/dist/client/createClientUploadHandler.js +26 -22
- package/dist/client/createClientUploadHandler.js.map +1 -1
- package/dist/exports/client.d.ts +1 -1
- package/dist/exports/client.d.ts.map +1 -1
- package/dist/exports/client.js +1 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/utilities.d.ts +2 -4
- package/dist/exports/utilities.d.ts.map +1 -1
- package/dist/exports/utilities.js +2 -4
- package/dist/exports/utilities.js.map +1 -1
- package/dist/fields/getFields.d.ts +1 -5
- package/dist/fields/getFields.d.ts.map +1 -1
- package/dist/fields/getFields.js +102 -35
- package/dist/fields/getFields.js.map +1 -1
- package/dist/hooks/afterChange.d.ts +3 -1
- package/dist/hooks/afterChange.d.ts.map +1 -1
- package/dist/hooks/afterChange.js +93 -27
- package/dist/hooks/afterChange.js.map +1 -1
- package/dist/hooks/afterDelete.d.ts.map +1 -1
- package/dist/hooks/afterDelete.js +10 -2
- package/dist/hooks/afterDelete.js.map +1 -1
- package/dist/hooks/afterRead.d.ts +6 -1
- package/dist/hooks/afterRead.d.ts.map +1 -1
- package/dist/hooks/afterRead.js +27 -11
- package/dist/hooks/afterRead.js.map +1 -1
- package/dist/hooks/beforeChange.d.ts +2 -1
- package/dist/hooks/beforeChange.d.ts.map +1 -1
- package/dist/hooks/beforeChange.js +14 -9
- package/dist/hooks/beforeChange.js.map +1 -1
- package/dist/hooks/publicOriginalURL.d.ts +8 -0
- package/dist/hooks/publicOriginalURL.d.ts.map +1 -0
- package/dist/hooks/publicOriginalURL.js +34 -0
- package/dist/hooks/publicOriginalURL.js.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +198 -132
- package/dist/plugin.js.map +1 -1
- package/dist/types.d.ts +48 -31
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/buildStoragePathData.d.ts +0 -6
- package/dist/utilities/buildStoragePathData.d.ts.map +1 -1
- package/dist/utilities/buildStoragePathData.js +0 -2
- package/dist/utilities/buildStoragePathData.js.map +1 -1
- package/dist/utilities/createFileOperations.d.ts +13 -0
- package/dist/utilities/createFileOperations.d.ts.map +1 -0
- package/dist/utilities/createFileOperations.js +258 -0
- package/dist/utilities/createFileOperations.js.map +1 -0
- package/dist/utilities/getFilePrefix.d.ts +9 -20
- package/dist/utilities/getFilePrefix.d.ts.map +1 -1
- package/dist/utilities/getFilePrefix.js +42 -31
- package/dist/utilities/getFilePrefix.js.map +1 -1
- package/dist/utilities/getIncomingFiles.js +4 -4
- package/dist/utilities/getIncomingFiles.js.map +1 -1
- package/dist/utilities/getStorageLocationSelect.d.ts +9 -0
- package/dist/utilities/getStorageLocationSelect.d.ts.map +1 -0
- package/dist/utilities/getStorageLocationSelect.js +54 -0
- package/dist/utilities/getStorageLocationSelect.js.map +1 -0
- package/dist/utilities/resolveSignedURLKey.d.ts +10 -10
- package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
- package/dist/utilities/resolveSignedURLKey.js +33 -26
- package/dist/utilities/resolveSignedURLKey.js.map +1 -1
- package/dist/utilities/sanitizePrefix.d.ts +1 -9
- package/dist/utilities/sanitizePrefix.d.ts.map +1 -1
- package/dist/utilities/sanitizePrefix.js +1 -21
- package/dist/utilities/sanitizePrefix.js.map +1 -1
- package/package.json +6 -6
- package/dist/admin/fields/getFields.d.ts +0 -17
- package/dist/admin/fields/getFields.d.ts.map +0 -1
- package/dist/admin/fields/getFields.js +0 -98
- package/dist/admin/fields/getFields.js.map +0 -1
- package/dist/admin/index.d.ts +0 -4
- package/dist/admin/index.d.ts.map +0 -1
- package/dist/admin/index.js +0 -34
- package/dist/admin/index.js.map +0 -1
- package/dist/hooks/afterChange.spec.js +0 -150
- package/dist/hooks/afterChange.spec.js.map +0 -1
- package/dist/hooks/normalizeUploadPrefix.spec.js +0 -154
- package/dist/hooks/normalizeUploadPrefix.spec.js.map +0 -1
- package/dist/plugin.spec.js +0 -166
- package/dist/plugin.spec.js.map +0 -1
- package/dist/utilities/assertReceiptMatchesFileKey.d.ts +0 -15
- package/dist/utilities/assertReceiptMatchesFileKey.d.ts.map +0 -1
- package/dist/utilities/assertReceiptMatchesFileKey.js +0 -31
- package/dist/utilities/assertReceiptMatchesFileKey.js.map +0 -1
- package/dist/utilities/buildStoragePathData.spec.js +0 -254
- package/dist/utilities/buildStoragePathData.spec.js.map +0 -1
- package/dist/utilities/getFilePrefix.spec.js +0 -291
- package/dist/utilities/getFilePrefix.spec.js.map +0 -1
- package/dist/utilities/initClientUploads.d.ts +0 -13
- package/dist/utilities/initClientUploads.d.ts.map +0 -1
- package/dist/utilities/initClientUploads.js +0 -63
- package/dist/utilities/initClientUploads.js.map +0 -1
- package/dist/utilities/resolveSignedURLKey.spec.js +0 -56
- package/dist/utilities/resolveSignedURLKey.spec.js.map +0 -1
- package/dist/utilities/verifyClientUploadReceiptForFileKey.d.ts +0 -20
- package/dist/utilities/verifyClientUploadReceiptForFileKey.d.ts.map +0 -1
- package/dist/utilities/verifyClientUploadReceiptForFileKey.js +0 -24
- package/dist/utilities/verifyClientUploadReceiptForFileKey.js.map +0 -1
- package/dist/utilities/verifyClientUploadReceiptForFileKey.spec.js +0 -108
- package/dist/utilities/verifyClientUploadReceiptForFileKey.spec.js.map +0 -1
|
@@ -1,36 +1,94 @@
|
|
|
1
|
+
import { deepMergeWithSourceArrays } from 'payload';
|
|
1
2
|
import { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js';
|
|
2
3
|
import { buildStoragePathData, buildUploadStoragePathData } from '../utilities/buildStoragePathData.js';
|
|
3
4
|
import { getIncomingFiles } from '../utilities/getIncomingFiles.js';
|
|
5
|
+
import { appendProxyPrefix } from './afterRead.js';
|
|
4
6
|
// The object's folder: semantic prefix + `_objectKey` segment.
|
|
5
|
-
const getObjectFolder = (
|
|
6
|
-
const record =
|
|
7
|
+
const getObjectFolder = (data)=>{
|
|
8
|
+
const record = data ?? {};
|
|
7
9
|
return buildPrefixWithObjectKey({
|
|
8
10
|
objectKey: record._objectKey,
|
|
9
11
|
prefix: record.prefix
|
|
10
12
|
});
|
|
11
13
|
};
|
|
12
|
-
export const getAfterChangeHook = ({ adapter, collection, collectionPrefix, useCompositePrefixes })=>async ({ doc, operation, previousDoc, req })=>{
|
|
14
|
+
export const getAfterChangeHook = ({ adapter, collection, collectionPrefix, disablePayloadAccessControl, hasCustomFileURL, useCompositePrefixes })=>async ({ data, doc, operation, previousDoc, req, select })=>{
|
|
13
15
|
// Skip if this is an internal update to prevent infinite loop
|
|
14
16
|
if (req.context?.skipCloudStorage) {
|
|
15
17
|
return doc;
|
|
16
18
|
}
|
|
17
|
-
|
|
19
|
+
// Restore upload metadata removed by select, including partially selected image sizes.
|
|
20
|
+
const uploadData = select ? deepMergeWithSourceArrays(data, doc) : doc;
|
|
21
|
+
const withProxyPrefix = (upload)=>{
|
|
22
|
+
const { prefix } = upload;
|
|
23
|
+
if (disablePayloadAccessControl || hasCustomFileURL || !useCompositePrefixes || !prefix) {
|
|
24
|
+
return upload;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
...upload,
|
|
28
|
+
...upload.url && {
|
|
29
|
+
url: appendProxyPrefix({
|
|
30
|
+
prefix,
|
|
31
|
+
url: upload.url
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
...upload.original?.url && {
|
|
35
|
+
original: {
|
|
36
|
+
...upload.original,
|
|
37
|
+
url: appendProxyPrefix({
|
|
38
|
+
prefix,
|
|
39
|
+
url: upload.original.url
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const isDraftSave = uploadData._status === 'draft';
|
|
18
46
|
const isDraftOverPublished = isDraftSave && previousDoc?._status === 'published';
|
|
47
|
+
if (req.context?._payloadManagedCloudStorage) {
|
|
48
|
+
const metadata = req.context._payloadManagedCloudMetadata;
|
|
49
|
+
if (!metadata || Object.keys(metadata).length === 0) {
|
|
50
|
+
return withProxyPrefix(doc);
|
|
51
|
+
}
|
|
52
|
+
req.context.skipCloudStorage = true;
|
|
53
|
+
req.file = undefined;
|
|
54
|
+
req.payloadUploadSizes = undefined;
|
|
55
|
+
const originalQuery = req.query;
|
|
56
|
+
req.query = {
|
|
57
|
+
...req.query
|
|
58
|
+
};
|
|
59
|
+
delete req.query.uploadEdits;
|
|
60
|
+
try {
|
|
61
|
+
const updatedDoc = await req.payload.update({
|
|
62
|
+
id: doc.id,
|
|
63
|
+
collection: collection.slug,
|
|
64
|
+
data: metadata,
|
|
65
|
+
depth: 0,
|
|
66
|
+
draft: isDraftSave,
|
|
67
|
+
overrideAccess: true,
|
|
68
|
+
req,
|
|
69
|
+
select
|
|
70
|
+
});
|
|
71
|
+
return withProxyPrefix({
|
|
72
|
+
...doc,
|
|
73
|
+
...updatedDoc
|
|
74
|
+
});
|
|
75
|
+
} finally{
|
|
76
|
+
req.query = originalQuery;
|
|
77
|
+
delete req.context.skipCloudStorage;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
19
80
|
try {
|
|
20
81
|
const files = getIncomingFiles({
|
|
21
|
-
data:
|
|
82
|
+
data: uploadData,
|
|
22
83
|
req
|
|
23
84
|
});
|
|
24
85
|
if (files.length > 0) {
|
|
25
86
|
// Fold `_objectKey` so generated sizes land in the same folder as the original.
|
|
26
87
|
const dataForUpload = {
|
|
27
|
-
...
|
|
28
|
-
prefix: getObjectFolder(
|
|
88
|
+
...uploadData,
|
|
89
|
+
prefix: getObjectFolder(uploadData)
|
|
29
90
|
};
|
|
30
|
-
const uploadResults = await Promise.all(files
|
|
31
|
-
// directly by the browser), so skip re-uploading them here.
|
|
32
|
-
.filter((file)=>!file.clientUploadContext).map((file)=>adapter.handleUpload({
|
|
33
|
-
clientUploadContext: file.clientUploadContext,
|
|
91
|
+
const uploadResults = await Promise.all(files.filter((file)=>!file.uploadReference).map((file)=>adapter.handleUpload({
|
|
34
92
|
collection,
|
|
35
93
|
data: dataForUpload,
|
|
36
94
|
file,
|
|
@@ -59,49 +117,57 @@ export const getAfterChangeHook = ({ adapter, collection, collectionPrefix, useC
|
|
|
59
117
|
req.file = undefined;
|
|
60
118
|
req.payloadUploadSizes = undefined;
|
|
61
119
|
try {
|
|
62
|
-
await req.payload.update({
|
|
120
|
+
const updatedDoc = await req.payload.update({
|
|
63
121
|
id: doc.id,
|
|
64
122
|
collection: collection.slug,
|
|
65
123
|
data: uploadMetadata,
|
|
66
124
|
depth: 0,
|
|
67
125
|
draft: isDraftSave,
|
|
68
|
-
|
|
126
|
+
overrideAccess: true,
|
|
127
|
+
req,
|
|
128
|
+
select
|
|
69
129
|
});
|
|
130
|
+
// Persist all adapter metadata, but do not add unselected fields to the response.
|
|
131
|
+
docWithMetadata = select ? {
|
|
132
|
+
...doc,
|
|
133
|
+
...updatedDoc
|
|
134
|
+
} : {
|
|
135
|
+
...doc,
|
|
136
|
+
...uploadMetadata
|
|
137
|
+
};
|
|
70
138
|
} finally{
|
|
71
139
|
delete req.context.skipCloudStorage;
|
|
72
140
|
}
|
|
73
|
-
docWithMetadata = {
|
|
74
|
-
...doc,
|
|
75
|
-
...uploadMetadata
|
|
76
|
-
};
|
|
77
141
|
}
|
|
78
142
|
// Delete previous files only after the new upload and metadata
|
|
79
143
|
// persistence have succeeded. Deleting earlier would orphan the
|
|
80
144
|
// record if a later step throws (e.g. a user-defined afterChange
|
|
81
145
|
// hook on the same collection).
|
|
82
|
-
if (previousDoc && operation === 'update' && !isDraftOverPublished) {
|
|
146
|
+
if (previousDoc && operation === 'update' && !isDraftOverPublished && !collection.versions && !previousDoc.original) {
|
|
83
147
|
let filesToDelete = [];
|
|
84
148
|
if (typeof previousDoc?.filename === 'string') {
|
|
85
149
|
filesToDelete.push(previousDoc.filename);
|
|
86
150
|
}
|
|
87
|
-
if (typeof previousDoc.
|
|
88
|
-
filesToDelete = filesToDelete.concat(Object.values(previousDoc?.
|
|
151
|
+
if (typeof previousDoc.variants === 'object') {
|
|
152
|
+
filesToDelete = filesToDelete.concat(Object.values(previousDoc?.variants || []).map((resizedFileData)=>resizedFileData?.filename));
|
|
89
153
|
}
|
|
90
154
|
// Compare full locations: a replacement can reuse a filename while moving
|
|
91
155
|
// a legacy object beneath the collection prefix.
|
|
156
|
+
const newFileData = {
|
|
157
|
+
...uploadData,
|
|
158
|
+
...uploadMetadata
|
|
159
|
+
};
|
|
92
160
|
const newFilenames = new Set();
|
|
93
|
-
if (typeof
|
|
94
|
-
newFilenames.add(
|
|
161
|
+
if (typeof newFileData.filename === 'string') {
|
|
162
|
+
newFilenames.add(newFileData.filename);
|
|
95
163
|
}
|
|
96
|
-
if (typeof
|
|
97
|
-
for (const size of Object.values(
|
|
164
|
+
if (typeof newFileData.variants === 'object') {
|
|
165
|
+
for (const size of Object.values(newFileData.variants || {})){
|
|
98
166
|
if (size?.filename && typeof size.filename === 'string') {
|
|
99
167
|
newFilenames.add(size.filename);
|
|
100
168
|
}
|
|
101
169
|
}
|
|
102
170
|
}
|
|
103
|
-
// Resolve each object's real location, folding `_objectKey` so a client-uploaded
|
|
104
|
-
// original is compared and deleted at `prefix/_objectKey/filename`.
|
|
105
171
|
const resolveKey = ({ data, filename })=>buildStoragePathData({
|
|
106
172
|
collectionPrefix,
|
|
107
173
|
docPrefix: getObjectFolder(data),
|
|
@@ -111,7 +177,7 @@ export const getAfterChangeHook = ({ adapter, collection, collectionPrefix, useC
|
|
|
111
177
|
const newKeys = new Set([
|
|
112
178
|
...newFilenames
|
|
113
179
|
].map((filename)=>resolveKey({
|
|
114
|
-
data:
|
|
180
|
+
data: newFileData,
|
|
115
181
|
filename
|
|
116
182
|
})));
|
|
117
183
|
const deletionPromises = filesToDelete.map(async (filename)=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/afterChange.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\nimport {\n buildStoragePathData,\n buildUploadStoragePathData,\n} from '../utilities/buildStoragePathData.js'\nimport { getIncomingFiles } from '../utilities/getIncomingFiles.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n collectionPrefix?: string\n useCompositePrefixes?: boolean\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (doc: unknown): string => {\n const record = (doc ?? {}) as { _objectKey?: string; prefix?: string }\n return buildPrefixWithObjectKey({ objectKey: record._objectKey, prefix: record.prefix })\n}\n\nexport const getAfterChangeHook =\n ({\n adapter,\n collection,\n collectionPrefix,\n useCompositePrefixes,\n }: Args): CollectionAfterChangeHook<FileData & TypeWithID> =>\n async ({ doc, operation, previousDoc, req }) => {\n // Skip if this is an internal update to prevent infinite loop\n if (req.context?.skipCloudStorage) {\n return doc\n }\n\n const isDraftSave = (doc as { _status?: string })._status === 'draft'\n const isDraftOverPublished =\n isDraftSave && (previousDoc as { _status?: string } | undefined)?._status === 'published'\n\n try {\n const files = getIncomingFiles({ data: doc, req })\n\n if (files.length > 0) {\n // Fold `_objectKey` so generated sizes land in the same folder as the original.\n const dataForUpload = { ...doc, prefix: getObjectFolder(doc) }\n\n const uploadResults = await Promise.all(\n files\n // Files with a clientUploadContext are already in storage (uploaded\n // directly by the browser), so skip re-uploading them here.\n .filter((file) => !file.clientUploadContext)\n .map((file) =>\n adapter.handleUpload({\n clientUploadContext: file.clientUploadContext,\n collection,\n data: dataForUpload,\n file,\n req,\n storageFilePath: buildUploadStoragePathData({\n collectionPrefix,\n docPrefix: dataForUpload.prefix,\n filename: file.filename,\n useCompositePrefixes,\n }).storageFilePath,\n }),\n ),\n )\n\n const uploadMetadata = uploadResults\n .filter(\n (result): result is Partial<FileData & TypeWithID> =>\n result != null && typeof result === 'object',\n )\n .reduce(\n (acc, metadata) => ({ ...acc, ...metadata }),\n {} as Partial<FileData & TypeWithID>,\n )\n\n // Adapters may echo `data` back as metadata; keep the document's own `prefix`/`_objectKey`.\n delete (uploadMetadata as Record<string, unknown>).prefix\n delete (uploadMetadata as Record<string, unknown>)._objectKey\n\n let docWithMetadata = doc\n\n if (Object.keys(uploadMetadata).length > 0) {\n if (!req.context) {\n req.context = {}\n }\n req.context.skipCloudStorage = true\n\n // Clear to prevent re-processing\n req.file = undefined\n req.payloadUploadSizes = undefined\n\n try {\n await req.payload.update({\n id: doc.id,\n collection: collection.slug,\n data: uploadMetadata,\n depth: 0,\n draft: isDraftSave,\n req,\n })\n } finally {\n delete req.context.skipCloudStorage\n }\n\n docWithMetadata = { ...doc, ...uploadMetadata }\n }\n\n // Delete previous files only after the new upload and metadata\n // persistence have succeeded. Deleting earlier would orphan the\n // record if a later step throws (e.g. a user-defined afterChange\n // hook on the same collection).\n if (previousDoc && operation === 'update' && !isDraftOverPublished) {\n let filesToDelete: string[] = []\n\n if (typeof previousDoc?.filename === 'string') {\n filesToDelete.push(previousDoc.filename)\n }\n\n if (typeof previousDoc.sizes === 'object') {\n filesToDelete = filesToDelete.concat(\n Object.values(previousDoc?.sizes || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n )\n }\n\n // Compare full locations: a replacement can reuse a filename while moving\n // a legacy object beneath the collection prefix.\n const newFilenames = new Set<string>()\n if (typeof docWithMetadata.filename === 'string') {\n newFilenames.add(docWithMetadata.filename)\n }\n if (typeof docWithMetadata.sizes === 'object') {\n for (const size of Object.values(docWithMetadata.sizes || {})) {\n if (size?.filename && typeof size.filename === 'string') {\n newFilenames.add(size.filename)\n }\n }\n }\n\n // Resolve each object's real location, folding `_objectKey` so a client-uploaded\n // original is compared and deleted at `prefix/_objectKey/filename`.\n const resolveKey = ({\n data,\n filename,\n }: {\n data: { _objectKey?: string; prefix?: string }\n filename: string\n }) =>\n buildStoragePathData({\n collectionPrefix,\n docPrefix: getObjectFolder(data),\n filename,\n useCompositePrefixes,\n }).storageFilePath\n\n const newKeys = new Set(\n [...newFilenames].map((filename) =>\n resolveKey({\n data: docWithMetadata as { _objectKey?: string; prefix?: string },\n filename,\n }),\n ),\n )\n\n const deletionPromises = filesToDelete.map(async (filename) => {\n if (!filename) {\n return\n }\n const storageFilePath = resolveKey({\n data: previousDoc as { _objectKey?: string; prefix?: string },\n filename,\n })\n if (!newKeys.has(storageFilePath)) {\n await adapter.handleDelete({\n collection,\n doc: previousDoc,\n filename,\n req,\n storageFilePath,\n })\n }\n })\n\n await Promise.all(deletionPromises)\n }\n\n if (docWithMetadata !== doc) {\n return docWithMetadata\n }\n }\n } catch (err: unknown) {\n req.payload.logger.error(\n `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${doc.filename}:`,\n )\n req.payload.logger.error({ err })\n throw err\n }\n return doc\n }\n"],"names":["buildPrefixWithObjectKey","buildStoragePathData","buildUploadStoragePathData","getIncomingFiles","getObjectFolder","doc","record","objectKey","_objectKey","prefix","getAfterChangeHook","adapter","collection","collectionPrefix","useCompositePrefixes","operation","previousDoc","req","context","skipCloudStorage","isDraftSave","_status","isDraftOverPublished","files","data","length","dataForUpload","uploadResults","Promise","all","filter","file","clientUploadContext","map","handleUpload","storageFilePath","docPrefix","filename","uploadMetadata","result","reduce","acc","metadata","docWithMetadata","Object","keys","undefined","payloadUploadSizes","payload","update","id","slug","depth","draft","filesToDelete","push","sizes","concat","values","resizedFileData","newFilenames","Set","add","size","resolveKey","newKeys","deletionPromises","has","handleDelete","err","logger","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterChange.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport { deepMergeWithSourceArrays } from 'payload'\n\nimport type { GeneratedAdapter } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\nimport {\n buildStoragePathData,\n buildUploadStoragePathData,\n} from '../utilities/buildStoragePathData.js'\nimport { getIncomingFiles } from '../utilities/getIncomingFiles.js'\nimport { appendProxyPrefix } from './afterRead.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n collectionPrefix?: string\n disablePayloadAccessControl?: boolean\n hasCustomFileURL?: boolean\n useCompositePrefixes?: boolean\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (data: unknown): string => {\n const record = (data ?? {}) as { _objectKey?: string; prefix?: string }\n return buildPrefixWithObjectKey({ objectKey: record._objectKey, prefix: record.prefix })\n}\n\nexport const getAfterChangeHook =\n ({\n adapter,\n collection,\n collectionPrefix,\n disablePayloadAccessControl,\n hasCustomFileURL,\n useCompositePrefixes,\n }: Args): CollectionAfterChangeHook<FileData & TypeWithID> =>\n async ({ data, doc, operation, previousDoc, req, select }) => {\n // Skip if this is an internal update to prevent infinite loop\n if (req.context?.skipCloudStorage) {\n return doc\n }\n\n // Restore upload metadata removed by select, including partially selected image sizes.\n const uploadData = select ? deepMergeWithSourceArrays<FileData & TypeWithID>(data, doc) : doc\n const withProxyPrefix = (upload: FileData & TypeWithID): FileData & TypeWithID => {\n const { prefix } = upload as { prefix?: string } & FileData & TypeWithID\n\n if (disablePayloadAccessControl || hasCustomFileURL || !useCompositePrefixes || !prefix) {\n return upload\n }\n\n return {\n ...upload,\n ...(upload.url && {\n url: appendProxyPrefix({ prefix, url: upload.url }),\n }),\n ...(upload.original?.url && {\n original: {\n ...upload.original,\n url: appendProxyPrefix({ prefix, url: upload.original.url }),\n },\n }),\n }\n }\n const isDraftSave = (uploadData as { _status?: string })._status === 'draft'\n const isDraftOverPublished =\n isDraftSave && (previousDoc as { _status?: string } | undefined)?._status === 'published'\n\n if (req.context?._payloadManagedCloudStorage) {\n const metadata = req.context._payloadManagedCloudMetadata as\n | Partial<FileData & TypeWithID>\n | undefined\n\n if (!metadata || Object.keys(metadata).length === 0) {\n return withProxyPrefix(doc)\n }\n\n req.context.skipCloudStorage = true\n req.file = undefined\n req.payloadUploadSizes = undefined\n const originalQuery = req.query\n req.query = { ...req.query }\n delete req.query.uploadEdits\n\n try {\n const updatedDoc = await req.payload.update({\n id: doc.id,\n collection: collection.slug,\n data: metadata,\n depth: 0,\n draft: isDraftSave,\n overrideAccess: true,\n req,\n select,\n })\n\n return withProxyPrefix({ ...doc, ...updatedDoc })\n } finally {\n req.query = originalQuery\n delete req.context.skipCloudStorage\n }\n }\n\n try {\n const files = getIncomingFiles({ data: uploadData, req })\n\n if (files.length > 0) {\n // Fold `_objectKey` so generated sizes land in the same folder as the original.\n const dataForUpload = { ...uploadData, prefix: getObjectFolder(uploadData) }\n\n const uploadResults = await Promise.all(\n files\n .filter((file) => !file.uploadReference)\n .map((file) =>\n adapter.handleUpload({\n collection,\n data: dataForUpload,\n file,\n req,\n storageFilePath: buildUploadStoragePathData({\n collectionPrefix,\n docPrefix: dataForUpload.prefix,\n filename: file.filename,\n useCompositePrefixes,\n }).storageFilePath,\n }),\n ),\n )\n\n const uploadMetadata = uploadResults\n .filter(\n (result): result is Partial<FileData & TypeWithID> =>\n result != null && typeof result === 'object',\n )\n .reduce(\n (acc, metadata) => ({ ...acc, ...metadata }),\n {} as Partial<FileData & TypeWithID>,\n )\n\n // Adapters may echo `data` back as metadata; keep the document's own `prefix`/`_objectKey`.\n delete (uploadMetadata as Record<string, unknown>).prefix\n delete (uploadMetadata as Record<string, unknown>)._objectKey\n\n let docWithMetadata = doc\n\n if (Object.keys(uploadMetadata).length > 0) {\n if (!req.context) {\n req.context = {}\n }\n req.context.skipCloudStorage = true\n\n // Clear to prevent re-processing\n req.file = undefined\n req.payloadUploadSizes = undefined\n\n try {\n const updatedDoc = await req.payload.update({\n id: doc.id,\n collection: collection.slug,\n data: uploadMetadata,\n depth: 0,\n draft: isDraftSave,\n overrideAccess: true,\n req,\n select,\n })\n\n // Persist all adapter metadata, but do not add unselected fields to the response.\n docWithMetadata = select ? { ...doc, ...updatedDoc } : { ...doc, ...uploadMetadata }\n } finally {\n delete req.context.skipCloudStorage\n }\n }\n\n // Delete previous files only after the new upload and metadata\n // persistence have succeeded. Deleting earlier would orphan the\n // record if a later step throws (e.g. a user-defined afterChange\n // hook on the same collection).\n if (\n previousDoc &&\n operation === 'update' &&\n !isDraftOverPublished &&\n !collection.versions &&\n !previousDoc.original\n ) {\n let filesToDelete: string[] = []\n\n if (typeof previousDoc?.filename === 'string') {\n filesToDelete.push(previousDoc.filename)\n }\n\n if (typeof previousDoc.variants === 'object') {\n filesToDelete = filesToDelete.concat(\n Object.values(previousDoc?.variants || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n )\n }\n\n // Compare full locations: a replacement can reuse a filename while moving\n // a legacy object beneath the collection prefix.\n const newFileData = { ...uploadData, ...uploadMetadata }\n const newFilenames = new Set<string>()\n if (typeof newFileData.filename === 'string') {\n newFilenames.add(newFileData.filename)\n }\n if (typeof newFileData.variants === 'object') {\n for (const size of Object.values(newFileData.variants || {})) {\n if (size?.filename && typeof size.filename === 'string') {\n newFilenames.add(size.filename)\n }\n }\n }\n\n const resolveKey = ({\n data,\n filename,\n }: {\n data: { _objectKey?: string; prefix?: string }\n filename: string\n }) =>\n buildStoragePathData({\n collectionPrefix,\n docPrefix: getObjectFolder(data),\n filename,\n useCompositePrefixes,\n }).storageFilePath\n const newKeys = new Set(\n [...newFilenames].map((filename) =>\n resolveKey({\n data: newFileData as { _objectKey?: string; prefix?: string },\n filename,\n }),\n ),\n )\n\n const deletionPromises = filesToDelete.map(async (filename) => {\n if (!filename) {\n return\n }\n const storageFilePath = resolveKey({\n data: previousDoc as { _objectKey?: string; prefix?: string },\n filename,\n })\n if (!newKeys.has(storageFilePath)) {\n await adapter.handleDelete({\n collection,\n doc: previousDoc,\n filename,\n req,\n storageFilePath,\n })\n }\n })\n\n await Promise.all(deletionPromises)\n }\n\n if (docWithMetadata !== doc) {\n return docWithMetadata\n }\n }\n } catch (err: unknown) {\n req.payload.logger.error(\n `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${doc.filename}:`,\n )\n req.payload.logger.error({ err })\n throw err\n }\n return doc\n }\n"],"names":["deepMergeWithSourceArrays","buildPrefixWithObjectKey","buildStoragePathData","buildUploadStoragePathData","getIncomingFiles","appendProxyPrefix","getObjectFolder","data","record","objectKey","_objectKey","prefix","getAfterChangeHook","adapter","collection","collectionPrefix","disablePayloadAccessControl","hasCustomFileURL","useCompositePrefixes","doc","operation","previousDoc","req","select","context","skipCloudStorage","uploadData","withProxyPrefix","upload","url","original","isDraftSave","_status","isDraftOverPublished","_payloadManagedCloudStorage","metadata","_payloadManagedCloudMetadata","Object","keys","length","file","undefined","payloadUploadSizes","originalQuery","query","uploadEdits","updatedDoc","payload","update","id","slug","depth","draft","overrideAccess","files","dataForUpload","uploadResults","Promise","all","filter","uploadReference","map","handleUpload","storageFilePath","docPrefix","filename","uploadMetadata","result","reduce","acc","docWithMetadata","versions","filesToDelete","push","variants","concat","values","resizedFileData","newFileData","newFilenames","Set","add","size","resolveKey","newKeys","deletionPromises","has","handleDelete","err","logger","error"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afterDelete.d.ts","sourceRoot":"","sources":["../../src/hooks/afterDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAKnE,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,kBAAkB,qEAK5B,IAAI,KAAG,yBAAyB,CAAC,QAAQ,GAAG,UAAU,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"afterDelete.d.ts","sourceRoot":"","sources":["../../src/hooks/afterDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAKnE,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,kBAAkB,qEAK5B,IAAI,KAAG,yBAAyB,CAAC,QAAQ,GAAG,UAAU,GAAG,cAAc,CAiDzE,CAAA"}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js';
|
|
2
2
|
import { buildStoragePathData } from '../utilities/buildStoragePathData.js';
|
|
3
3
|
export const getAfterDeleteHook = ({ adapter, collection, collectionPrefix, useCompositePrefixes })=>{
|
|
4
|
-
return async ({ doc, req })=>{
|
|
4
|
+
return async ({ id, doc, req })=>{
|
|
5
|
+
// Managed objects are deleted after the operation commits and all references are checked.
|
|
6
|
+
const managedDeletedUploads = req.context?._payloadManagedDeletedUploads;
|
|
7
|
+
if (collection.versions || Boolean(doc.original) && typeof doc.original?.filename === 'string' || managedDeletedUploads?.has(JSON.stringify([
|
|
8
|
+
collection.slug,
|
|
9
|
+
String(id)
|
|
10
|
+
]))) {
|
|
11
|
+
return doc;
|
|
12
|
+
}
|
|
5
13
|
try {
|
|
6
14
|
// Fold `_objectKey` so deletes target the real object folder.
|
|
7
15
|
const docPrefix = buildPrefixWithObjectKey({
|
|
@@ -10,7 +18,7 @@ export const getAfterDeleteHook = ({ adapter, collection, collectionPrefix, useC
|
|
|
10
18
|
});
|
|
11
19
|
const filesToDelete = [
|
|
12
20
|
doc.filename,
|
|
13
|
-
...Object.values(doc?.
|
|
21
|
+
...Object.values(doc?.variants || []).map((resizedFileData)=>resizedFileData?.filename)
|
|
14
22
|
];
|
|
15
23
|
const promises = filesToDelete.map(async (filename)=>{
|
|
16
24
|
if (filename) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/afterDelete.ts"],"sourcesContent":["import type { CollectionAfterDeleteHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter, TypeWithPrefix } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\nimport { buildStoragePathData } from '../utilities/buildStoragePathData.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n collectionPrefix?: string\n useCompositePrefixes?: boolean\n}\n\nexport const getAfterDeleteHook = ({\n adapter,\n collection,\n collectionPrefix,\n useCompositePrefixes,\n}: Args): CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix> => {\n return async ({ doc, req }) => {\n try {\n // Fold `_objectKey` so deletes target the real object folder.\n const docPrefix = buildPrefixWithObjectKey({\n objectKey: (doc as { _objectKey?: string })._objectKey,\n prefix: doc.prefix,\n })\n\n const filesToDelete: string[] = [\n doc.filename,\n ...Object.values(doc?.
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterDelete.ts"],"sourcesContent":["import type { CollectionAfterDeleteHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter, TypeWithPrefix } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\nimport { buildStoragePathData } from '../utilities/buildStoragePathData.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n collectionPrefix?: string\n useCompositePrefixes?: boolean\n}\n\nexport const getAfterDeleteHook = ({\n adapter,\n collection,\n collectionPrefix,\n useCompositePrefixes,\n}: Args): CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix> => {\n return async ({ id, doc, req }) => {\n // Managed objects are deleted after the operation commits and all references are checked.\n const managedDeletedUploads = req.context?._payloadManagedDeletedUploads as\n | Set<string>\n | undefined\n if (\n collection.versions ||\n (Boolean(doc.original) && typeof doc.original?.filename === 'string') ||\n managedDeletedUploads?.has(JSON.stringify([collection.slug, String(id)]))\n ) {\n return doc\n }\n\n try {\n // Fold `_objectKey` so deletes target the real object folder.\n const docPrefix = buildPrefixWithObjectKey({\n objectKey: (doc as { _objectKey?: string })._objectKey,\n prefix: doc.prefix,\n })\n\n const filesToDelete: string[] = [\n doc.filename,\n ...Object.values(doc?.variants || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n ]\n\n const promises = filesToDelete.map(async (filename) => {\n if (filename) {\n const { storageFilePath } = buildStoragePathData({\n collectionPrefix,\n docPrefix,\n filename,\n useCompositePrefixes,\n })\n await adapter.handleDelete({ collection, doc, filename, req, storageFilePath })\n }\n })\n\n await Promise.all(promises)\n } catch (err: unknown) {\n req.payload.logger.error({\n err,\n msg: `There was an error while deleting files corresponding to the ${collection.labels?.singular} with ID ${doc.id}.`,\n })\n }\n return doc\n }\n}\n"],"names":["buildPrefixWithObjectKey","buildStoragePathData","getAfterDeleteHook","adapter","collection","collectionPrefix","useCompositePrefixes","id","doc","req","managedDeletedUploads","context","_payloadManagedDeletedUploads","versions","Boolean","original","filename","has","JSON","stringify","slug","String","docPrefix","objectKey","_objectKey","prefix","filesToDelete","Object","values","variants","map","resizedFileData","promises","storageFilePath","handleDelete","Promise","all","err","payload","logger","error","msg","labels","singular"],"mappings":"AAIA,SAASA,wBAAwB,QAAQ,2CAA0C;AACnF,SAASC,oBAAoB,QAAQ,uCAAsC;AAS3E,OAAO,MAAMC,qBAAqB,CAAC,EACjCC,OAAO,EACPC,UAAU,EACVC,gBAAgB,EAChBC,oBAAoB,EACf;IACL,OAAO,OAAO,EAAEC,EAAE,EAAEC,GAAG,EAAEC,GAAG,EAAE;QAC5B,0FAA0F;QAC1F,MAAMC,wBAAwBD,IAAIE,OAAO,EAAEC;QAG3C,IACER,WAAWS,QAAQ,IAClBC,QAAQN,IAAIO,QAAQ,KAAK,OAAOP,IAAIO,QAAQ,EAAEC,aAAa,YAC5DN,uBAAuBO,IAAIC,KAAKC,SAAS,CAAC;YAACf,WAAWgB,IAAI;YAAEC,OAAOd;SAAI,IACvE;YACA,OAAOC;QACT;QAEA,IAAI;YACF,8DAA8D;YAC9D,MAAMc,YAAYtB,yBAAyB;gBACzCuB,WAAW,AAACf,IAAgCgB,UAAU;gBACtDC,QAAQjB,IAAIiB,MAAM;YACpB;YAEA,MAAMC,gBAA0B;gBAC9BlB,IAAIQ,QAAQ;mBACTW,OAAOC,MAAM,CAACpB,KAAKqB,YAAY,EAAE,EAAEC,GAAG,CACvC,CAACC,kBAAoBA,iBAAiBf;aAEzC;YAED,MAAMgB,WAAWN,cAAcI,GAAG,CAAC,OAAOd;gBACxC,IAAIA,UAAU;oBACZ,MAAM,EAAEiB,eAAe,EAAE,GAAGhC,qBAAqB;wBAC/CI;wBACAiB;wBACAN;wBACAV;oBACF;oBACA,MAAMH,QAAQ+B,YAAY,CAAC;wBAAE9B;wBAAYI;wBAAKQ;wBAAUP;wBAAKwB;oBAAgB;gBAC/E;YACF;YAEA,MAAME,QAAQC,GAAG,CAACJ;QACpB,EAAE,OAAOK,KAAc;YACrB5B,IAAI6B,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBACvBH;gBACAI,KAAK,CAAC,6DAA6D,EAAErC,WAAWsC,MAAM,EAAEC,SAAS,SAAS,EAAEnC,IAAID,EAAE,CAAC,CAAC,CAAC;YACvH;QACF;QACA,OAAOC;IACT;AACF,EAAC"}
|
|
@@ -5,8 +5,13 @@ interface Args {
|
|
|
5
5
|
collection: CollectionConfig;
|
|
6
6
|
disablePayloadAccessControl?: boolean;
|
|
7
7
|
generateFileURL?: GenerateFileURL;
|
|
8
|
+
isOriginal?: boolean;
|
|
8
9
|
size?: ImageSize;
|
|
9
10
|
}
|
|
10
|
-
export declare const getAfterReadHook: ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args) => FieldHook;
|
|
11
|
+
export declare const getAfterReadHook: ({ adapter, collection, disablePayloadAccessControl, generateFileURL, isOriginal, size, }: Args) => FieldHook;
|
|
12
|
+
export declare const appendProxyPrefix: ({ prefix, url }: {
|
|
13
|
+
prefix: string;
|
|
14
|
+
url: string;
|
|
15
|
+
}) => string;
|
|
11
16
|
export {};
|
|
12
17
|
//# sourceMappingURL=afterRead.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afterRead.d.ts","sourceRoot":"","sources":["../../src/hooks/afterRead.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIpE,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;
|
|
1
|
+
{"version":3,"file":"afterRead.d.ts","sourceRoot":"","sources":["../../src/hooks/afterRead.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIpE,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAiBD,eAAO,MAAM,gBAAgB,6FAQxB,IAAI,KAAG,SAkCT,CAAA;AAEH,eAAO,MAAM,iBAAiB,oBAAqB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,KAAG,MAMpF,CAAA"}
|
package/dist/hooks/afterRead.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
2
2
|
// The object's folder: semantic prefix + `_objectKey` segment.
|
|
3
3
|
const getObjectFolder = (data)=>{
|
|
4
4
|
const record = data ?? {};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const safePrefix = sanitizePrefix(typeof record.prefix === 'string' ? record.prefix : '');
|
|
6
|
+
const safeObjectKey = sanitizePrefix(typeof record._objectKey === 'string' ? record._objectKey : '');
|
|
7
|
+
if (safePrefix && safeObjectKey) {
|
|
8
|
+
return `${safePrefix}/${safeObjectKey}`;
|
|
9
|
+
}
|
|
10
|
+
return safePrefix || safeObjectKey;
|
|
9
11
|
};
|
|
10
|
-
export const getAfterReadHook = ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size })=>async ({ data, value })=>{
|
|
11
|
-
const
|
|
12
|
-
const
|
|
12
|
+
export const getAfterReadHook = ({ adapter, collection, disablePayloadAccessControl, generateFileURL, isOriginal, size })=>async ({ data, value })=>{
|
|
13
|
+
const representation = isOriginal ? data?.original : size ? data?.variants?.[size.name] : data;
|
|
14
|
+
const filename = representation?.filename;
|
|
15
|
+
const hasLegacyVariant = Boolean(size && !data?.original?.filename);
|
|
16
|
+
const prefix = representation?.prefix ?? (hasLegacyVariant ? data?.prefix : undefined);
|
|
13
17
|
// Direct-serve URLs encode the full location; the proxy resolves `_objectKey` server-side.
|
|
14
|
-
const objectFolder = getObjectFolder(
|
|
18
|
+
const objectFolder = getObjectFolder({
|
|
19
|
+
_objectKey: representation?._objectKey ?? (hasLegacyVariant ? data?._objectKey : undefined),
|
|
20
|
+
prefix
|
|
21
|
+
});
|
|
15
22
|
let url = value;
|
|
16
23
|
if (filename) {
|
|
17
24
|
if (generateFileURL) {
|
|
@@ -29,11 +36,20 @@ export const getAfterReadHook = ({ adapter, collection, disablePayloadAccessCont
|
|
|
29
36
|
prefix: objectFolder
|
|
30
37
|
});
|
|
31
38
|
} else if (url && prefix) {
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
url = appendProxyPrefix({
|
|
40
|
+
prefix,
|
|
41
|
+
url
|
|
42
|
+
});
|
|
34
43
|
}
|
|
35
44
|
}
|
|
36
45
|
return url;
|
|
37
46
|
};
|
|
47
|
+
export const appendProxyPrefix = ({ prefix, url })=>{
|
|
48
|
+
if (new URL(url, 'http://payload.local').searchParams.has('prefix')) {
|
|
49
|
+
return url;
|
|
50
|
+
}
|
|
51
|
+
const separator = url.includes('?') ? '&' : '?';
|
|
52
|
+
return `${url}${separator}prefix=${encodeURIComponent(prefix)}`;
|
|
53
|
+
};
|
|
38
54
|
|
|
39
55
|
//# sourceMappingURL=afterRead.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/afterRead.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterRead.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n isOriginal?: boolean\n size?: ImageSize\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (data: unknown): string => {\n const record = (data ?? {}) as Record<string, unknown>\n const safePrefix = sanitizePrefix(typeof record.prefix === 'string' ? record.prefix : '')\n const safeObjectKey = sanitizePrefix(\n typeof record._objectKey === 'string' ? record._objectKey : '',\n )\n\n if (safePrefix && safeObjectKey) {\n return `${safePrefix}/${safeObjectKey}`\n }\n\n return safePrefix || safeObjectKey\n}\n\nexport const getAfterReadHook =\n ({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n isOriginal,\n size,\n }: Args): FieldHook =>\n async ({ data, value }) => {\n const representation = isOriginal ? data?.original : size ? data?.variants?.[size.name] : data\n const filename = representation?.filename\n const hasLegacyVariant = Boolean(size && !data?.original?.filename)\n const prefix = representation?.prefix ?? (hasLegacyVariant ? data?.prefix : undefined)\n // Direct-serve URLs encode the full location; the proxy resolves `_objectKey` server-side.\n const objectFolder = getObjectFolder({\n _objectKey: representation?._objectKey ?? (hasLegacyVariant ? data?._objectKey : undefined),\n prefix,\n })\n let url = value\n\n if (filename) {\n if (generateFileURL) {\n url = await generateFileURL({\n collection,\n filename,\n prefix: objectFolder,\n size,\n })\n } else if (disablePayloadAccessControl && adapter.generateURL) {\n url = await adapter.generateURL({\n collection,\n data,\n filename,\n prefix: objectFolder,\n })\n } else if (url && prefix) {\n url = appendProxyPrefix({ prefix, url })\n }\n }\n\n return url\n }\n\nexport const appendProxyPrefix = ({ prefix, url }: { prefix: string; url: string }): string => {\n if (new URL(url, 'http://payload.local').searchParams.has('prefix')) {\n return url\n }\n const separator = url.includes('?') ? '&' : '?'\n return `${url}${separator}prefix=${encodeURIComponent(prefix)}`\n}\n"],"names":["sanitizePrefix","getObjectFolder","data","record","safePrefix","prefix","safeObjectKey","_objectKey","getAfterReadHook","adapter","collection","disablePayloadAccessControl","generateFileURL","isOriginal","size","value","representation","original","variants","name","filename","hasLegacyVariant","Boolean","undefined","objectFolder","url","generateURL","appendProxyPrefix","URL","searchParams","has","separator","includes","encodeURIComponent"],"mappings":"AAIA,SAASA,cAAc,QAAQ,iCAAgC;AAW/D,+DAA+D;AAC/D,MAAMC,kBAAkB,CAACC;IACvB,MAAMC,SAAUD,QAAQ,CAAC;IACzB,MAAME,aAAaJ,eAAe,OAAOG,OAAOE,MAAM,KAAK,WAAWF,OAAOE,MAAM,GAAG;IACtF,MAAMC,gBAAgBN,eACpB,OAAOG,OAAOI,UAAU,KAAK,WAAWJ,OAAOI,UAAU,GAAG;IAG9D,IAAIH,cAAcE,eAAe;QAC/B,OAAO,GAAGF,WAAW,CAAC,EAAEE,eAAe;IACzC;IAEA,OAAOF,cAAcE;AACvB;AAEA,OAAO,MAAME,mBACX,CAAC,EACCC,OAAO,EACPC,UAAU,EACVC,2BAA2B,EAC3BC,eAAe,EACfC,UAAU,EACVC,IAAI,EACC,GACP,OAAO,EAAEZ,IAAI,EAAEa,KAAK,EAAE;QACpB,MAAMC,iBAAiBH,aAAaX,MAAMe,WAAWH,OAAOZ,MAAMgB,UAAU,CAACJ,KAAKK,IAAI,CAAC,GAAGjB;QAC1F,MAAMkB,WAAWJ,gBAAgBI;QACjC,MAAMC,mBAAmBC,QAAQR,QAAQ,CAACZ,MAAMe,UAAUG;QAC1D,MAAMf,SAASW,gBAAgBX,UAAWgB,CAAAA,mBAAmBnB,MAAMG,SAASkB,SAAQ;QACpF,2FAA2F;QAC3F,MAAMC,eAAevB,gBAAgB;YACnCM,YAAYS,gBAAgBT,cAAec,CAAAA,mBAAmBnB,MAAMK,aAAagB,SAAQ;YACzFlB;QACF;QACA,IAAIoB,MAAMV;QAEV,IAAIK,UAAU;YACZ,IAAIR,iBAAiB;gBACnBa,MAAM,MAAMb,gBAAgB;oBAC1BF;oBACAU;oBACAf,QAAQmB;oBACRV;gBACF;YACF,OAAO,IAAIH,+BAA+BF,QAAQiB,WAAW,EAAE;gBAC7DD,MAAM,MAAMhB,QAAQiB,WAAW,CAAC;oBAC9BhB;oBACAR;oBACAkB;oBACAf,QAAQmB;gBACV;YACF,OAAO,IAAIC,OAAOpB,QAAQ;gBACxBoB,MAAME,kBAAkB;oBAAEtB;oBAAQoB;gBAAI;YACxC;QACF;QAEA,OAAOA;IACT,EAAC;AAEH,OAAO,MAAME,oBAAoB,CAAC,EAAEtB,MAAM,EAAEoB,GAAG,EAAmC;IAChF,IAAI,IAAIG,IAAIH,KAAK,wBAAwBI,YAAY,CAACC,GAAG,CAAC,WAAW;QACnE,OAAOL;IACT;IACA,MAAMM,YAAYN,IAAIO,QAAQ,CAAC,OAAO,MAAM;IAC5C,OAAO,GAAGP,MAAMM,UAAU,OAAO,EAAEE,mBAAmB5B,SAAS;AACjE,EAAC"}
|
|
@@ -5,8 +5,9 @@ interface Args {
|
|
|
5
5
|
collection: CollectionConfig;
|
|
6
6
|
disablePayloadAccessControl?: boolean;
|
|
7
7
|
generateFileURL?: GenerateFileURL;
|
|
8
|
+
isOriginal?: boolean;
|
|
8
9
|
size?: ImageSize;
|
|
9
10
|
}
|
|
10
|
-
export declare const getBeforeChangeHook: ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args) => FieldHook;
|
|
11
|
+
export declare const getBeforeChangeHook: ({ adapter, collection, disablePayloadAccessControl, generateFileURL, isOriginal, size, }: Args) => FieldHook;
|
|
11
12
|
export {};
|
|
12
13
|
//# sourceMappingURL=beforeChange.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"beforeChange.d.ts","sourceRoot":"","sources":["../../src/hooks/beforeChange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIpE,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;
|
|
1
|
+
{"version":3,"file":"beforeChange.d.ts","sourceRoot":"","sources":["../../src/hooks/beforeChange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIpE,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAiBD,eAAO,MAAM,mBAAmB,6FAQ3B,IAAI,KAAG,SAoCT,CAAA"}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
2
2
|
// The object's folder: semantic prefix + `_objectKey` segment.
|
|
3
3
|
const getObjectFolder = (data, originalDoc)=>{
|
|
4
4
|
const source = data ?? originalDoc ?? {};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const safePrefix = sanitizePrefix(typeof source.prefix === 'string' ? source.prefix : '');
|
|
6
|
+
const safeObjectKey = sanitizePrefix(typeof source._objectKey === 'string' ? source._objectKey : '');
|
|
7
|
+
if (safePrefix && safeObjectKey) {
|
|
8
|
+
return `${safePrefix}/${safeObjectKey}`;
|
|
9
|
+
}
|
|
10
|
+
return safePrefix || safeObjectKey;
|
|
9
11
|
};
|
|
10
|
-
export const getBeforeChangeHook = ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size })=>async ({ data, originalDoc, value })=>{
|
|
11
|
-
const
|
|
12
|
-
const
|
|
12
|
+
export const getBeforeChangeHook = ({ adapter, collection, disablePayloadAccessControl, generateFileURL, isOriginal, size })=>async ({ data, originalDoc, value })=>{
|
|
13
|
+
const newRepresentation = isOriginal ? data?.original : size ? data?.variants?.[size.name] : data;
|
|
14
|
+
const originalRepresentation = isOriginal ? originalDoc?.original : size ? originalDoc?.variants?.[size.name] : originalDoc;
|
|
15
|
+
const newFilename = newRepresentation?.filename;
|
|
16
|
+
const originalFilename = originalRepresentation?.filename;
|
|
13
17
|
const filename = newFilename || originalFilename;
|
|
14
|
-
const
|
|
18
|
+
const representation = newRepresentation ?? originalRepresentation;
|
|
19
|
+
const prefix = getObjectFolder(representation, data ?? originalDoc);
|
|
15
20
|
let url = value;
|
|
16
21
|
if (generateFileURL && filename) {
|
|
17
22
|
url = await generateFileURL({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n isOriginal?: boolean\n size?: ImageSize\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (data: unknown, originalDoc: unknown): string => {\n const source = (data ?? originalDoc ?? {}) as Record<string, unknown>\n const safePrefix = sanitizePrefix(typeof source.prefix === 'string' ? source.prefix : '')\n const safeObjectKey = sanitizePrefix(\n typeof source._objectKey === 'string' ? source._objectKey : '',\n )\n\n if (safePrefix && safeObjectKey) {\n return `${safePrefix}/${safeObjectKey}`\n }\n\n return safePrefix || safeObjectKey\n}\n\nexport const getBeforeChangeHook =\n ({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n isOriginal,\n size,\n }: Args): FieldHook =>\n async ({ data, originalDoc, value }) => {\n const newRepresentation = isOriginal\n ? data?.original\n : size\n ? data?.variants?.[size.name]\n : data\n const originalRepresentation = isOriginal\n ? originalDoc?.original\n : size\n ? originalDoc?.variants?.[size.name]\n : originalDoc\n const newFilename = newRepresentation?.filename\n const originalFilename = originalRepresentation?.filename\n const filename = newFilename || originalFilename\n const representation = newRepresentation ?? originalRepresentation\n const prefix = getObjectFolder(representation, data ?? originalDoc)\n let url = value\n\n if (generateFileURL && filename) {\n url = await generateFileURL({\n collection,\n filename,\n prefix,\n size,\n })\n } else if (disablePayloadAccessControl && filename && adapter.generateURL) {\n url = await adapter.generateURL({\n collection,\n data: data || originalDoc,\n filename,\n prefix,\n })\n }\n\n return url\n }\n"],"names":["sanitizePrefix","getObjectFolder","data","originalDoc","source","safePrefix","prefix","safeObjectKey","_objectKey","getBeforeChangeHook","adapter","collection","disablePayloadAccessControl","generateFileURL","isOriginal","size","value","newRepresentation","original","variants","name","originalRepresentation","newFilename","filename","originalFilename","representation","url","generateURL"],"mappings":"AAIA,SAASA,cAAc,QAAQ,iCAAgC;AAW/D,+DAA+D;AAC/D,MAAMC,kBAAkB,CAACC,MAAeC;IACtC,MAAMC,SAAUF,QAAQC,eAAe,CAAC;IACxC,MAAME,aAAaL,eAAe,OAAOI,OAAOE,MAAM,KAAK,WAAWF,OAAOE,MAAM,GAAG;IACtF,MAAMC,gBAAgBP,eACpB,OAAOI,OAAOI,UAAU,KAAK,WAAWJ,OAAOI,UAAU,GAAG;IAG9D,IAAIH,cAAcE,eAAe;QAC/B,OAAO,GAAGF,WAAW,CAAC,EAAEE,eAAe;IACzC;IAEA,OAAOF,cAAcE;AACvB;AAEA,OAAO,MAAME,sBACX,CAAC,EACCC,OAAO,EACPC,UAAU,EACVC,2BAA2B,EAC3BC,eAAe,EACfC,UAAU,EACVC,IAAI,EACC,GACP,OAAO,EAAEb,IAAI,EAAEC,WAAW,EAAEa,KAAK,EAAE;QACjC,MAAMC,oBAAoBH,aACtBZ,MAAMgB,WACNH,OACEb,MAAMiB,UAAU,CAACJ,KAAKK,IAAI,CAAC,GAC3BlB;QACN,MAAMmB,yBAAyBP,aAC3BX,aAAae,WACbH,OACEZ,aAAagB,UAAU,CAACJ,KAAKK,IAAI,CAAC,GAClCjB;QACN,MAAMmB,cAAcL,mBAAmBM;QACvC,MAAMC,mBAAmBH,wBAAwBE;QACjD,MAAMA,WAAWD,eAAeE;QAChC,MAAMC,iBAAiBR,qBAAqBI;QAC5C,MAAMf,SAASL,gBAAgBwB,gBAAgBvB,QAAQC;QACvD,IAAIuB,MAAMV;QAEV,IAAIH,mBAAmBU,UAAU;YAC/BG,MAAM,MAAMb,gBAAgB;gBAC1BF;gBACAY;gBACAjB;gBACAS;YACF;QACF,OAAO,IAAIH,+BAA+BW,YAAYb,QAAQiB,WAAW,EAAE;YACzED,MAAM,MAAMhB,QAAQiB,WAAW,CAAC;gBAC9BhB;gBACAT,MAAMA,QAAQC;gBACdoB;gBACAjB;YACF;QACF;QAEA,OAAOoB;IACT,EAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CollectionAfterReadHook, CollectionConfig } from 'payload';
|
|
2
|
+
import type { GeneratedAdapter, GenerateFileURL } from '../types.js';
|
|
3
|
+
export declare const getPublicOriginalURLHook: ({ adapter, collection, generateFileURL, }: {
|
|
4
|
+
adapter: GeneratedAdapter;
|
|
5
|
+
collection: CollectionConfig;
|
|
6
|
+
generateFileURL?: GenerateFileURL;
|
|
7
|
+
}) => CollectionAfterReadHook;
|
|
8
|
+
//# sourceMappingURL=publicOriginalURL.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publicOriginalURL.d.ts","sourceRoot":"","sources":["../../src/hooks/publicOriginalURL.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAwB,MAAM,SAAS,CAAA;AAE9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIpE,eAAO,MAAM,wBAAwB,8CAKhC;IACD,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAA;CAClC,KAAG,uBAsBH,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js';
|
|
2
|
+
export const getPublicOriginalURLHook = ({ adapter, collection, generateFileURL })=>async ({ doc })=>{
|
|
3
|
+
const upload = doc;
|
|
4
|
+
const filename = upload.original?.filename;
|
|
5
|
+
if (!filename) {
|
|
6
|
+
return doc;
|
|
7
|
+
}
|
|
8
|
+
if (upload.original?.url && !upload.original.url.startsWith('/')) {
|
|
9
|
+
return doc;
|
|
10
|
+
}
|
|
11
|
+
const prefix = buildPrefixWithObjectKey({
|
|
12
|
+
objectKey: upload.original?._objectKey,
|
|
13
|
+
prefix: upload.original?.prefix
|
|
14
|
+
});
|
|
15
|
+
const url = generateFileURL ? await generateFileURL({
|
|
16
|
+
collection,
|
|
17
|
+
filename,
|
|
18
|
+
prefix
|
|
19
|
+
}) : await adapter.generateURL?.({
|
|
20
|
+
collection,
|
|
21
|
+
data: upload,
|
|
22
|
+
filename,
|
|
23
|
+
prefix
|
|
24
|
+
});
|
|
25
|
+
return url ? {
|
|
26
|
+
...doc,
|
|
27
|
+
original: {
|
|
28
|
+
...upload.original,
|
|
29
|
+
url
|
|
30
|
+
}
|
|
31
|
+
} : doc;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=publicOriginalURL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/publicOriginalURL.ts"],"sourcesContent":["import type { CollectionAfterReadHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\n\nexport const getPublicOriginalURLHook =\n ({\n adapter,\n collection,\n generateFileURL,\n }: {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n generateFileURL?: GenerateFileURL\n }): CollectionAfterReadHook =>\n async ({ doc }) => {\n const upload = doc as { _objectKey?: string; prefix?: string } & FileData & TypeWithID\n const filename = upload.original?.filename\n\n if (!filename) {\n return doc\n }\n\n if (upload.original?.url && !upload.original.url.startsWith('/')) {\n return doc\n }\n\n const prefix = buildPrefixWithObjectKey({\n objectKey: upload.original?._objectKey,\n prefix: upload.original?.prefix,\n })\n const url = generateFileURL\n ? await generateFileURL({ collection, filename, prefix })\n : await adapter.generateURL?.({ collection, data: upload, filename, prefix })\n\n return url ? { ...doc, original: { ...upload.original, url } } : doc\n }\n"],"names":["buildPrefixWithObjectKey","getPublicOriginalURLHook","adapter","collection","generateFileURL","doc","upload","filename","original","url","startsWith","prefix","objectKey","_objectKey","generateURL","data"],"mappings":"AAIA,SAASA,wBAAwB,QAAQ,2CAA0C;AAEnF,OAAO,MAAMC,2BACX,CAAC,EACCC,OAAO,EACPC,UAAU,EACVC,eAAe,EAKhB,GACD,OAAO,EAAEC,GAAG,EAAE;QACZ,MAAMC,SAASD;QACf,MAAME,WAAWD,OAAOE,QAAQ,EAAED;QAElC,IAAI,CAACA,UAAU;YACb,OAAOF;QACT;QAEA,IAAIC,OAAOE,QAAQ,EAAEC,OAAO,CAACH,OAAOE,QAAQ,CAACC,GAAG,CAACC,UAAU,CAAC,MAAM;YAChE,OAAOL;QACT;QAEA,MAAMM,SAASX,yBAAyB;YACtCY,WAAWN,OAAOE,QAAQ,EAAEK;YAC5BF,QAAQL,OAAOE,QAAQ,EAAEG;QAC3B;QACA,MAAMF,MAAML,kBACR,MAAMA,gBAAgB;YAAED;YAAYI;YAAUI;QAAO,KACrD,MAAMT,QAAQY,WAAW,GAAG;YAAEX;YAAYY,MAAMT;YAAQC;YAAUI;QAAO;QAE7E,OAAOF,MAAM;YAAE,GAAGJ,GAAG;YAAEG,UAAU;gBAAE,GAAGF,OAAOE,QAAQ;gBAAEC;YAAI;QAAE,IAAIJ;IACnE,EAAC"}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAA;AAoBnE,eAAO,MAAM,kBAAkB,kBACb,aAAa,sBACZ,MAAM,KAAG,MA+PzB,CAAA"}
|