payload 4.0.0-beta.2 → 4.0.0-beta.4
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/dist/admin/adapters/router.d.ts +1 -1
- package/dist/admin/adapters/router.d.ts.map +1 -1
- package/dist/admin/adapters/router.js.map +1 -1
- package/dist/admin/initAdminContext.js.map +1 -1
- package/dist/auth/getFieldsToSign.js.map +1 -1
- package/dist/auth/loginWithCookie.js.map +1 -1
- package/dist/auth/serverFunctions/cookies.js.map +1 -1
- package/dist/auth/serverFunctions/login.js.map +1 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/cli/commands/data/utilities.d.ts +1 -1
- package/dist/cli/commands/data/utilities.d.ts.map +1 -1
- package/dist/cli/commands/data/utilities.js.map +1 -1
- package/dist/cli/defineCLICommand.js +1 -1
- package/dist/cli/defineCLICommand.js.map +1 -1
- package/dist/collections/config/client.js.map +1 -1
- package/dist/collections/config/types.d.ts.map +1 -1
- package/dist/collections/config/types.js.map +1 -1
- package/dist/collections/operations/findByID.js.map +1 -1
- package/dist/collections/operations/findVersionByID.js.map +1 -1
- package/dist/collections/operations/findVersions.js.map +1 -1
- package/dist/collections/operations/local/findDistinct.js.map +1 -1
- package/dist/collections/operations/renameFile.js +1 -1
- package/dist/collections/operations/renameFile.js.map +1 -1
- package/dist/collections/operations/utilities/update.js +1 -1
- package/dist/collections/operations/utilities/update.js.map +1 -1
- package/dist/collections/operations/validate.js +4 -4
- package/dist/collections/operations/validate.js.map +1 -1
- package/dist/config/definePlugin.js.map +1 -1
- package/dist/config/sanitize.js +2 -2
- package/dist/config/sanitize.js.map +1 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/database/types.d.ts +4 -0
- package/dist/database/types.d.ts.map +1 -1
- package/dist/database/types.js.map +1 -1
- package/dist/exports/build-config.d.ts +9 -0
- package/dist/exports/build-config.d.ts.map +1 -0
- package/dist/exports/build-config.js +38 -0
- package/dist/exports/build-config.js.map +1 -0
- package/dist/fields/config/client.js.map +1 -1
- package/dist/fields/config/reservedFieldNames.d.ts.map +1 -1
- package/dist/fields/config/reservedFieldNames.js.map +1 -1
- package/dist/fields/config/types.d.ts.map +1 -1
- package/dist/fields/config/types.js.map +1 -1
- package/dist/fields/hooks/afterChange/promise.js.map +1 -1
- package/dist/fields/hooks/afterRead/promise.js.map +1 -1
- package/dist/fields/hooks/beforeChange/flattenValidationData.d.ts +14 -0
- package/dist/fields/hooks/beforeChange/flattenValidationData.d.ts.map +1 -0
- package/dist/fields/hooks/beforeChange/flattenValidationData.js +36 -0
- package/dist/fields/hooks/beforeChange/flattenValidationData.js.map +1 -0
- package/dist/fields/hooks/beforeChange/promise.d.ts +2 -1
- package/dist/fields/hooks/beforeChange/promise.d.ts.map +1 -1
- package/dist/fields/hooks/beforeChange/promise.js +96 -22
- package/dist/fields/hooks/beforeChange/promise.js.map +1 -1
- package/dist/fields/hooks/beforeChange/traverseFields.d.ts +2 -1
- package/dist/fields/hooks/beforeChange/traverseFields.d.ts.map +1 -1
- package/dist/fields/hooks/beforeChange/traverseFields.js +2 -1
- package/dist/fields/hooks/beforeChange/traverseFields.js.map +1 -1
- package/dist/fields/validations.d.ts.map +1 -1
- package/dist/fields/validations.js +4 -1
- package/dist/fields/validations.js.map +1 -1
- package/dist/globals/config/types.d.ts.map +1 -1
- package/dist/globals/config/types.js.map +1 -1
- package/dist/globals/operations/local/findOne.js.map +1 -1
- package/dist/globals/operations/local/update.js.map +1 -1
- package/dist/globals/operations/restoreVersion.d.ts +2 -3
- package/dist/globals/operations/restoreVersion.d.ts.map +1 -1
- package/dist/globals/operations/restoreVersion.js +22 -15
- package/dist/globals/operations/restoreVersion.js.map +1 -1
- package/dist/globals/operations/validate.js +1 -1
- package/dist/globals/operations/validate.js.map +1 -1
- package/dist/hierarchy/createFolderField.js.map +1 -1
- package/dist/hierarchy/resolveHierarchyCollections.js +2 -2
- package/dist/hierarchy/resolveHierarchyCollections.js.map +1 -1
- package/dist/hierarchy/utils/computePaths.d.ts.map +1 -1
- package/dist/hierarchy/utils/computePaths.js.map +1 -1
- package/dist/index.bundled.d.ts +18 -4
- package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js +1 -1
- package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/uploads/fileVersioning/archive.js.map +1 -1
- package/dist/uploads/fileVersioning/cloudStorage.js.map +1 -1
- package/dist/uploads/fileVersioning/resolveHistoricalFile.js.map +1 -1
- package/dist/uploads/generateFileData.d.ts.map +1 -1
- package/dist/uploads/generateFileData.js.map +1 -1
- package/dist/uploads/getFileContentRequirement.js.map +1 -1
- package/dist/uploads/getFileFromUploadInstructions.js.map +1 -1
- package/dist/uploads/safeFetch.js.map +1 -1
- package/dist/uploads/stagedUpload.js.map +1 -1
- package/dist/uploads/transformers/handleDynamicFileRequest.js +11 -2
- package/dist/uploads/transformers/handleDynamicFileRequest.js.map +1 -1
- package/dist/utilities/addSelectGenericsToGeneretedTypes.d.ts.map +1 -1
- package/dist/utilities/addSelectGenericsToGeneretedTypes.js +0 -1
- package/dist/utilities/addSelectGenericsToGeneretedTypes.js.map +1 -1
- package/dist/utilities/appendDateTimezoneSelectFields.js.map +1 -1
- package/dist/utilities/cloneValidationRequest.js.map +1 -1
- package/dist/utilities/createPayloadRequest.js.map +1 -1
- package/dist/utilities/deepCopyObject.js.map +1 -1
- package/dist/utilities/documentMatchingWhereExists.js +1 -1
- package/dist/utilities/documentMatchingWhereExists.js.map +1 -1
- package/dist/utilities/entityInputSchema/validateEntityData.d.ts.map +1 -1
- package/dist/utilities/entityInputSchema/validateEntityData.js.map +1 -1
- package/dist/utilities/filterDataToSelectedLocales.js.map +1 -1
- package/dist/utilities/getEntityPermissions/getEntityPermissions.d.ts.map +1 -1
- package/dist/utilities/getEntityPermissions/getEntityPermissions.js +1 -0
- package/dist/utilities/getEntityPermissions/getEntityPermissions.js.map +1 -1
- package/dist/utilities/getEntityPermissions/populateFieldPermissions.js.map +1 -1
- package/dist/utilities/getVersionsConfig.js.map +1 -1
- package/dist/utilities/parseParams/index.js.map +1 -1
- package/dist/utilities/parseValidationLocale.js.map +1 -1
- package/dist/utilities/sanitizePopulateParam.js.map +1 -1
- package/dist/utilities/telemetry/conf/index.d.ts +4 -1
- package/dist/utilities/telemetry/conf/index.d.ts.map +1 -1
- package/dist/utilities/telemetry/conf/index.js.map +1 -1
- package/dist/utilities/telemetry/featureInfo/getFeatureInfo.js.map +1 -1
- package/dist/versions/allLocalesPublicationStatus.js.map +1 -1
- package/dist/versions/isInheritedReadVersionsAccess.js.map +1 -1
- package/package.json +29 -27
- package/skills/payload/reference/ENDPOINTS.md +3 -9
- package/skills/payload/reference/PLUGIN-DEVELOPMENT.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/uploads/fileVersioning/archive.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport type { SanitizedCollectionConfig } from '../../collections/config/types.js'\nimport type { Config } from '../../config/types.js'\nimport type { JsonObject, PayloadRequest } from '../../types/index.js'\nimport type { FileToSave } from '../types.js'\nimport type { StagedObject } from './fileOperationManager.js'\nimport type { StoredFileList } from './types.js'\n\nimport { saveVersion } from '../../versions/saveVersion.js'\nimport { removeUnreferencedStagedObjects, scheduleUnreferencedFileCleanup } from './cleanup.js'\nimport { runFileOperationPlan, stageLocalUploadFiles } from './fileOperationManager.js'\nimport { copyLocalFile } from './localStorage.js'\nimport { getArchivedFilename } from './naming.js'\nimport {\n collectStoredFiles,\n getStoredFileIdentity,\n withLegacyUploadFileData,\n} from './storedFiles.js'\n\ntype VersionRow = {\n createdAt: string\n id: number | string\n latest?: boolean\n parent: number | string\n publishedLocale?: string\n updatedAt: string\n version: JsonObject\n}\n\nexport const runLocalFileUpdate = async <T>({\n id,\n collection,\n current,\n files,\n next,\n req,\n write,\n}: {\n collection: SanitizedCollectionConfig\n current: JsonObject\n files: FileToSave[]\n id: number | string\n next: JsonObject\n req: PayloadRequest\n write: () => Promise<T>\n}): Promise<T> => {\n const storedCurrent = withLegacyUploadFileData({\n collection,\n config: req.payload.config,\n doc: current,\n })\n const nextDoc = { ...storedCurrent, ...next }\n\n if (\n !hasLocalFileChange({\n collection,\n config: req.payload.config,\n current,\n hasNewFiles: files.length > 0,\n next: nextDoc,\n req,\n })\n ) {\n return write()\n }\n\n return runFileOperationPlan({\n cleanupStagedAfterWriteFailure: (objects) =>\n removeUnreferencedStagedObjects({ collection, objects, req }),\n req,\n stage: ({ trackStagedObject }) =>\n stageLocalUploadFiles({\n files,\n staticDir: collection.upload.staticDir!,\n trackStagedObject,\n }),\n write: async ({ trackStagedObject }) => {\n await archiveOutgoingLocalFiles({\n id,\n collection,\n current,\n next: nextDoc,\n req,\n trackStagedObject,\n })\n\n const result = await write()\n\n await scheduleUnreferencedFileCleanup({\n candidates: getOutgoingLocalFiles({\n collection,\n config: req.payload.config,\n current,\n next: nextDoc,\n req,\n }),\n collection,\n req,\n })\n\n return result\n },\n })\n}\n\n/** Also detects removals, which have no new upload to stage. */\nconst hasLocalFileChange = ({\n collection,\n config,\n current,\n hasNewFiles,\n next,\n req,\n}: {\n collection: SanitizedCollectionConfig\n config: Pick<Config, 'routes' | 'serverURL'>\n current: JsonObject\n hasNewFiles: boolean\n next: JsonObject\n req: PayloadRequest\n}): boolean =>\n !collection.upload.disableLocalStorage &&\n (hasNewFiles ||\n getOutgoingLocalFiles({\n collection,\n config,\n current,\n next,\n req,\n }).length > 0)\n\n/** Preserves outgoing local objects and repairs every retained version that referenced them. */\nexport const archiveOutgoingLocalFiles = async ({\n id,\n collection,\n current,\n next,\n req,\n trackStagedObject,\n}: {\n collection: SanitizedCollectionConfig\n current: JsonObject\n id: number | string\n next: JsonObject\n req: PayloadRequest\n trackStagedObject: (object: StagedObject) => void\n}): Promise<void> => {\n const outgoing = getOutgoingLocalFiles({\n collection,\n config: req.payload.config,\n current,\n next,\n req,\n })\n\n if (!outgoing.length || !collection.versions) {\n return\n }\n\n const currentWithState = withLegacyUploadFileData({\n collection,\n config: req.payload.config,\n doc: current,\n })\n let versions = await getVersions({ id, collection, req })\n\n if (!versions.length) {\n await saveVersion({\n id,\n collection,\n docWithLocales: currentWithState,\n draft: false,\n operation: 'update',\n payload: req.payload,\n req,\n })\n versions = await getVersions({ id, collection, req })\n }\n\n const replacements = new Map<string, string>()\n for (const file of outgoing) {\n const identity = getStoredFileIdentity(file)\n const newestVersion = versions.find(({ version }) => {\n const stored = withLegacyUploadFileData({\n collection,\n config: req.payload.config,\n doc: version,\n })\n\n return collectStoredFiles({ collection, doc: stored, req }).some(\n (candidate) => getStoredFileIdentity(candidate) === identity,\n )\n })\n\n if (!newestVersion) {\n continue\n }\n\n const directory = path.posix.dirname(file.key)\n let archivedKey: string\n let suffix = 0\n\n while (true) {\n const archivedFilename = getArchivedFilename({\n filename: path.posix.basename(file.key),\n versionID: suffix ? `${newestVersion.id}-${suffix}` : newestVersion.id,\n })\n archivedKey = directory === '.' ? archivedFilename : `${directory}/${archivedFilename}`\n\n try {\n await copyLocalFile({\n from: file.key,\n staticDir: collection.upload.staticDir!,\n to: archivedKey,\n })\n break\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EEXIST') {\n throw err\n }\n suffix += 1\n }\n }\n trackStagedObject({\n key: archivedKey,\n remove: () => fs.rm(path.join(collection.upload.staticDir!, archivedKey), { force: true }),\n })\n replacements.set(identity, archivedKey)\n }\n\n for (const row of versions) {\n const stored = withLegacyUploadFileData({\n collection,\n config: req.payload.config,\n doc: row.version,\n })\n const version = replaceStoredFileReferences({\n files: collectStoredFiles({ collection, doc: stored, req }),\n replacements,\n version: stored,\n })\n\n if (!version) {\n continue\n }\n\n await req.payload.db.updateVersion({\n id: row.id,\n collection: collection.slug,\n req,\n versionData: {\n createdAt: row.createdAt,\n latest: row.latest,\n parent: row.parent,\n publishedLocale: row.publishedLocale,\n updatedAt: row.updatedAt,\n version,\n },\n })\n }\n}\n\nconst getOutgoingLocalFiles = ({\n collection,\n config,\n current,\n next,\n req,\n}: {\n collection: SanitizedCollectionConfig\n config: Pick<Config, 'routes' | 'serverURL'>\n current: JsonObject\n next: JsonObject\n req: PayloadRequest\n}): StoredFileList => {\n const currentWithState = withLegacyUploadFileData({ collection, config, doc: current })\n const currentFiles = collectStoredFiles({ collection, doc: currentWithState, req })\n const nextFiles = collectStoredFiles({ collection, doc: next, req, trustGenerated: true })\n const nextIdentities = new Set(nextFiles.map(getStoredFileIdentity))\n return currentFiles.filter((file) => !nextIdentities.has(getStoredFileIdentity(file)))\n}\n\nconst getVersions = async ({\n id,\n collection,\n req,\n}: {\n collection: SanitizedCollectionConfig\n id: number | string\n req: PayloadRequest\n}): Promise<VersionRow[]> => {\n const { docs } = await req.payload.db.findVersions<JsonObject>({\n collection: collection.slug,\n limit: 0,\n pagination: false,\n req,\n sort: '-updatedAt',\n where: { parent: { equals: id } },\n })\n\n return docs as VersionRow[]\n}\n\nexport const replaceStoredFileReferences = ({\n files,\n replacements,\n version,\n}: {\n files: StoredFileList\n replacements: Map<string, string>\n version: JsonObject\n}): JsonObject | undefined => {\n if (!files.length) {\n return\n }\n\n const archived = structuredClone(version)\n let hasChanged = false\n\n for (const file of files) {\n const archivedKey = replacements.get(getStoredFileIdentity(file))\n\n if (!archivedKey) {\n continue\n }\n\n const archivedFilename = path.posix.basename(archivedKey)\n\n for (const role of file.roles) {\n let stored: JsonObject | undefined\n switch (role.type) {\n case 'default':\n stored = archived\n break\n case 'original':\n stored = archived.original as JsonObject | undefined\n break\n case 'size':\n stored = (archived.variants as Record<string, JsonObject> | undefined)?.[role.sizeKey]\n break\n }\n\n if (typeof stored?.filename === 'string') {\n const previousFilename = stored.filename\n const directory = path.posix.dirname(previousFilename)\n const filename = directory === '.' ? archivedFilename : `${directory}/${archivedFilename}`\n stored.filename = filename\n stored.url = replaceURLFilename({\n filename,\n previousFilename,\n url: stored.url,\n })\n hasChanged = true\n }\n }\n }\n\n return hasChanged ? archived : undefined\n}\n\nconst replaceURLFilename = ({\n filename,\n previousFilename,\n url,\n}: {\n filename: string\n previousFilename: string\n url: unknown\n}): unknown => {\n if (typeof url !== 'string') {\n return url\n }\n\n const previous = encodeURIComponent(previousFilename)\n const index = url.lastIndexOf(`/${previous}`)\n\n return index < 0\n ? url\n : `${url.slice(0, index + 1)}${encodeURIComponent(filename)}${url.slice(index + 1 + previous.length)}`\n}\n"],"names":["fs","path","saveVersion","removeUnreferencedStagedObjects","scheduleUnreferencedFileCleanup","runFileOperationPlan","stageLocalUploadFiles","copyLocalFile","getArchivedFilename","collectStoredFiles","getStoredFileIdentity","withLegacyUploadFileData","runLocalFileUpdate","id","collection","current","files","next","req","write","storedCurrent","config","payload","doc","nextDoc","hasLocalFileChange","hasNewFiles","length","cleanupStagedAfterWriteFailure","objects","stage","trackStagedObject","staticDir","upload","archiveOutgoingLocalFiles","result","candidates","getOutgoingLocalFiles","disableLocalStorage","outgoing","versions","currentWithState","getVersions","docWithLocales","draft","operation","replacements","Map","file","identity","newestVersion","find","version","stored","some","candidate","directory","posix","dirname","key","archivedKey","suffix","archivedFilename","filename","basename","versionID","from","to","err","code","remove","rm","join","force","set","row","replaceStoredFileReferences","db","updateVersion","slug","versionData","createdAt","latest","parent","publishedLocale","updatedAt","currentFiles","nextFiles","trustGenerated","nextIdentities","Set","map","filter","has","docs","findVersions","limit","pagination","sort","where","equals","archived","structuredClone","hasChanged","get","role","roles","type","original","variants","sizeKey","previousFilename","url","replaceURLFilename","undefined","previous","encodeURIComponent","index","lastIndexOf","slice"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/uploads/fileVersioning/archive.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport type { SanitizedCollectionConfig } from '../../collections/config/types.js'\nimport type { Config } from '../../config/types.js'\nimport type { JsonObject, PayloadRequest } from '../../types/index.js'\nimport type { FileToSave } from '../types.js'\nimport type { StagedObject } from './fileOperationManager.js'\nimport type { StoredFileList } from './types.js'\n\nimport { saveVersion } from '../../versions/saveVersion.js'\nimport { removeUnreferencedStagedObjects, scheduleUnreferencedFileCleanup } from './cleanup.js'\nimport { runFileOperationPlan, stageLocalUploadFiles } from './fileOperationManager.js'\nimport { copyLocalFile } from './localStorage.js'\nimport { getArchivedFilename } from './naming.js'\nimport {\n collectStoredFiles,\n getStoredFileIdentity,\n withLegacyUploadFileData,\n} from './storedFiles.js'\n\ntype VersionRow = {\n createdAt: string\n id: number | string\n latest?: boolean\n parent: number | string\n publishedLocale?: string\n updatedAt: string\n version: JsonObject\n}\n\nexport const runLocalFileUpdate = async <T>({\n id,\n collection,\n current,\n files,\n next,\n req,\n write,\n}: {\n collection: SanitizedCollectionConfig\n current: JsonObject\n files: FileToSave[]\n id: number | string\n next: JsonObject\n req: PayloadRequest\n write: () => Promise<T>\n}): Promise<T> => {\n const storedCurrent = withLegacyUploadFileData({\n collection,\n config: req.payload.config,\n doc: current,\n })\n const nextDoc = { ...storedCurrent, ...next }\n\n if (\n !hasLocalFileChange({\n collection,\n config: req.payload.config,\n current,\n hasNewFiles: files.length > 0,\n next: nextDoc,\n req,\n })\n ) {\n return write()\n }\n\n return runFileOperationPlan({\n cleanupStagedAfterWriteFailure: (objects) =>\n removeUnreferencedStagedObjects({ collection, objects, req }),\n req,\n stage: ({ trackStagedObject }) =>\n stageLocalUploadFiles({\n files,\n staticDir: collection.upload.staticDir!,\n trackStagedObject,\n }),\n write: async ({ trackStagedObject }) => {\n await archiveOutgoingLocalFiles({\n id,\n collection,\n current,\n next: nextDoc,\n req,\n trackStagedObject,\n })\n\n const result = await write()\n\n await scheduleUnreferencedFileCleanup({\n candidates: getOutgoingLocalFiles({\n collection,\n config: req.payload.config,\n current,\n next: nextDoc,\n req,\n }),\n collection,\n req,\n })\n\n return result\n },\n })\n}\n\n/** Also detects removals, which have no new upload to stage. */\nconst hasLocalFileChange = ({\n collection,\n config,\n current,\n hasNewFiles,\n next,\n req,\n}: {\n collection: SanitizedCollectionConfig\n config: Pick<Config, 'routes' | 'serverURL'>\n current: JsonObject\n hasNewFiles: boolean\n next: JsonObject\n req: PayloadRequest\n}): boolean =>\n !collection.upload.disableLocalStorage &&\n (hasNewFiles ||\n getOutgoingLocalFiles({\n collection,\n config,\n current,\n next,\n req,\n }).length > 0)\n\n/** Preserves outgoing local objects and repairs every retained version that referenced them. */\nexport const archiveOutgoingLocalFiles = async ({\n id,\n collection,\n current,\n next,\n req,\n trackStagedObject,\n}: {\n collection: SanitizedCollectionConfig\n current: JsonObject\n id: number | string\n next: JsonObject\n req: PayloadRequest\n trackStagedObject: (object: StagedObject) => void\n}): Promise<void> => {\n const outgoing = getOutgoingLocalFiles({\n collection,\n config: req.payload.config,\n current,\n next,\n req,\n })\n\n if (!outgoing.length || !collection.versions) {\n return\n }\n\n const currentWithState = withLegacyUploadFileData({\n collection,\n config: req.payload.config,\n doc: current,\n })\n let versions = await getVersions({ id, collection, req })\n\n if (!versions.length) {\n await saveVersion({\n id,\n collection,\n docWithLocales: currentWithState,\n draft: false,\n operation: 'update',\n payload: req.payload,\n req,\n })\n versions = await getVersions({ id, collection, req })\n }\n\n const replacements = new Map<string, string>()\n for (const file of outgoing) {\n const identity = getStoredFileIdentity(file)\n const newestVersion = versions.find(({ version }) => {\n const stored = withLegacyUploadFileData({\n collection,\n config: req.payload.config,\n doc: version,\n })\n\n return collectStoredFiles({ collection, doc: stored, req }).some(\n (candidate) => getStoredFileIdentity(candidate) === identity,\n )\n })\n\n if (!newestVersion) {\n continue\n }\n\n const directory = path.posix.dirname(file.key)\n let archivedKey: string\n let suffix = 0\n\n while (true) {\n const archivedFilename = getArchivedFilename({\n filename: path.posix.basename(file.key),\n versionID: suffix ? `${newestVersion.id}-${suffix}` : newestVersion.id,\n })\n archivedKey = directory === '.' ? archivedFilename : `${directory}/${archivedFilename}`\n\n try {\n await copyLocalFile({\n from: file.key,\n staticDir: collection.upload.staticDir!,\n to: archivedKey,\n })\n break\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EEXIST') {\n throw err\n }\n suffix += 1\n }\n }\n trackStagedObject({\n key: archivedKey,\n remove: () => fs.rm(path.join(collection.upload.staticDir!, archivedKey), { force: true }),\n })\n replacements.set(identity, archivedKey)\n }\n\n for (const row of versions) {\n const stored = withLegacyUploadFileData({\n collection,\n config: req.payload.config,\n doc: row.version,\n })\n const version = replaceStoredFileReferences({\n files: collectStoredFiles({ collection, doc: stored, req }),\n replacements,\n version: stored,\n })\n\n if (!version) {\n continue\n }\n\n await req.payload.db.updateVersion({\n id: row.id,\n collection: collection.slug,\n req,\n versionData: {\n createdAt: row.createdAt,\n latest: row.latest,\n parent: row.parent,\n publishedLocale: row.publishedLocale,\n updatedAt: row.updatedAt,\n version,\n },\n })\n }\n}\n\nconst getOutgoingLocalFiles = ({\n collection,\n config,\n current,\n next,\n req,\n}: {\n collection: SanitizedCollectionConfig\n config: Pick<Config, 'routes' | 'serverURL'>\n current: JsonObject\n next: JsonObject\n req: PayloadRequest\n}): StoredFileList => {\n const currentWithState = withLegacyUploadFileData({ collection, config, doc: current })\n const currentFiles = collectStoredFiles({ collection, doc: currentWithState, req })\n const nextFiles = collectStoredFiles({ collection, doc: next, req, trustGenerated: true })\n const nextIdentities = new Set(nextFiles.map(getStoredFileIdentity))\n return currentFiles.filter((file) => !nextIdentities.has(getStoredFileIdentity(file)))\n}\n\nconst getVersions = async ({\n id,\n collection,\n req,\n}: {\n collection: SanitizedCollectionConfig\n id: number | string\n req: PayloadRequest\n}): Promise<VersionRow[]> => {\n const { docs } = await req.payload.db.findVersions<JsonObject>({\n collection: collection.slug,\n limit: 0,\n pagination: false,\n req,\n sort: '-updatedAt',\n where: { parent: { equals: id } },\n })\n\n return docs\n}\n\nexport const replaceStoredFileReferences = ({\n files,\n replacements,\n version,\n}: {\n files: StoredFileList\n replacements: Map<string, string>\n version: JsonObject\n}): JsonObject | undefined => {\n if (!files.length) {\n return\n }\n\n const archived = structuredClone(version)\n let hasChanged = false\n\n for (const file of files) {\n const archivedKey = replacements.get(getStoredFileIdentity(file))\n\n if (!archivedKey) {\n continue\n }\n\n const archivedFilename = path.posix.basename(archivedKey)\n\n for (const role of file.roles) {\n let stored: JsonObject | undefined\n switch (role.type) {\n case 'default':\n stored = archived\n break\n case 'original':\n stored = archived.original as JsonObject | undefined\n break\n case 'size':\n stored = (archived.variants as Record<string, JsonObject> | undefined)?.[role.sizeKey]\n break\n }\n\n if (typeof stored?.filename === 'string') {\n const previousFilename = stored.filename\n const directory = path.posix.dirname(previousFilename)\n const filename = directory === '.' ? archivedFilename : `${directory}/${archivedFilename}`\n stored.filename = filename\n stored.url = replaceURLFilename({\n filename,\n previousFilename,\n url: stored.url,\n })\n hasChanged = true\n }\n }\n }\n\n return hasChanged ? archived : undefined\n}\n\nconst replaceURLFilename = ({\n filename,\n previousFilename,\n url,\n}: {\n filename: string\n previousFilename: string\n url: unknown\n}): unknown => {\n if (typeof url !== 'string') {\n return url\n }\n\n const previous = encodeURIComponent(previousFilename)\n const index = url.lastIndexOf(`/${previous}`)\n\n return index < 0\n ? url\n : `${url.slice(0, index + 1)}${encodeURIComponent(filename)}${url.slice(index + 1 + previous.length)}`\n}\n"],"names":["fs","path","saveVersion","removeUnreferencedStagedObjects","scheduleUnreferencedFileCleanup","runFileOperationPlan","stageLocalUploadFiles","copyLocalFile","getArchivedFilename","collectStoredFiles","getStoredFileIdentity","withLegacyUploadFileData","runLocalFileUpdate","id","collection","current","files","next","req","write","storedCurrent","config","payload","doc","nextDoc","hasLocalFileChange","hasNewFiles","length","cleanupStagedAfterWriteFailure","objects","stage","trackStagedObject","staticDir","upload","archiveOutgoingLocalFiles","result","candidates","getOutgoingLocalFiles","disableLocalStorage","outgoing","versions","currentWithState","getVersions","docWithLocales","draft","operation","replacements","Map","file","identity","newestVersion","find","version","stored","some","candidate","directory","posix","dirname","key","archivedKey","suffix","archivedFilename","filename","basename","versionID","from","to","err","code","remove","rm","join","force","set","row","replaceStoredFileReferences","db","updateVersion","slug","versionData","createdAt","latest","parent","publishedLocale","updatedAt","currentFiles","nextFiles","trustGenerated","nextIdentities","Set","map","filter","has","docs","findVersions","limit","pagination","sort","where","equals","archived","structuredClone","hasChanged","get","role","roles","type","original","variants","sizeKey","previousFilename","url","replaceURLFilename","undefined","previous","encodeURIComponent","index","lastIndexOf","slice"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/uploads/fileVersioning/cloudStorage.ts"],"sourcesContent":["import type { SanitizedCollectionConfig } from '../../collections/config/types.js'\nimport type { JsonObject, PayloadRequest } from '../../types/index.js'\nimport type { FileToSave } from '../types.js'\nimport type { StagedObject } from './fileOperationManager.js'\n\nimport { saveVersion } from '../../versions/saveVersion.js'\nimport {\n collectStoredFiles as collectSavedFiles,\n removeUnreferencedStagedObjects,\n scheduleUnreferencedFileCleanup,\n} from './cleanup.js'\nimport { runFileCreationPlan, runFileOperationPlan } from './fileOperationManager.js'\nimport {\n collectStoredFiles,\n getStoredFileIdentity,\n withLegacyCloudUploadFileData,\n} from './storedFiles.js'\n\n/** Preserve the caller's cloud flags; nested Local API calls can replace req.context. */\nexport const captureCloudHookState = ({ req }: { req: PayloadRequest }): (() => void) => {\n const previousState = ['_payloadManagedCloudStorage', '_payloadManagedCloudMetadata'].map(\n (key) => ({\n hasProperty: Object.hasOwn(req.context ?? {}, key),\n key,\n value: req.context?.[key],\n }),\n )\n\n return () => {\n req.context ??= {}\n for (const { hasProperty, key, value } of previousState) {\n if (hasProperty) {\n req.context[key] = value\n } else {\n delete req.context[key]\n }\n }\n }\n}\n\nexport const runCloudFileCreation = async <T>({\n collection,\n data,\n files,\n req,\n write,\n}: {\n collection: SanitizedCollectionConfig\n data: JsonObject\n files: FileToSave[]\n req: PayloadRequest\n write: () => Promise<T>\n}): Promise<T> => {\n const operations = collection.upload.fileOperations\n\n if (\n !operations ||\n req.context?.skipCloudStorage ||\n (files.length === 0 && !req.context?._payloadVerifiedProviderOriginal)\n ) {\n return write()\n }\n\n let metadata: Record<string, unknown> = {}\n\n return runFileCreationPlan({\n cleanupStagedAfterWriteFailure: (objects) =>\n removeUnreferencedStagedObjects({ collection, objects, req }),\n req,\n stage: async ({ trackStagedObject }) => {\n trackClientUploadOriginal({ collection, data, req, trackStagedObject })\n const staged = await operations.stage({\n data,\n files,\n req,\n trackStagedObject,\n })\n metadata = staged.metadata\n Object.assign(data, metadata)\n },\n // Create's version and afterChange hooks run after the database insert. The\n // outer create operation restores the previous guard after those hooks finish.\n write: () => {\n req.context ??= {}\n req.context._payloadManagedCloudStorage = true\n req.context._payloadManagedCloudMetadata = metadata\n return write()\n },\n })\n}\n\nexport const runCloudFileUpdate = async <T>({\n id,\n collection,\n current,\n data,\n files,\n req,\n write,\n}: {\n collection: SanitizedCollectionConfig\n current: JsonObject\n data: JsonObject\n files: FileToSave[]\n id: number | string\n req: PayloadRequest\n write: () => Promise<T>\n}): Promise<T> => {\n const operations = collection.upload.fileOperations\n const storedCurrent = operations\n ? await withLegacyCloudUploadFileData({ collection, doc: current, req })\n : current\n const nextFiles = collectStoredFiles({\n collection,\n doc: { ...storedCurrent, ...data },\n req,\n trustGenerated: true,\n })\n const currentFiles = collectStoredFiles({ collection, doc: storedCurrent, req })\n const nextIdentities = new Set(nextFiles.map(getStoredFileIdentity))\n const hasStoredFileChange =\n nextIdentities.size !== currentFiles.length ||\n currentFiles.some((file) => !nextIdentities.has(getStoredFileIdentity(file)))\n\n if (\n !operations ||\n req.context?.skipCloudStorage ||\n (files.length === 0 && !req.context?._payloadVerifiedProviderOriginal && !hasStoredFileChange)\n ) {\n return write()\n }\n\n let metadata: Record<string, unknown> = {}\n\n return runFileOperationPlan({\n cleanupStagedAfterWriteFailure: (objects) =>\n removeUnreferencedStagedObjects({ collection, objects, req }),\n req,\n stage: async ({ trackStagedObject }) => {\n if (files.length === 0 && !req.context?._payloadVerifiedProviderOriginal) {\n return\n }\n trackClientUploadOriginal({ collection, data, req, trackStagedObject })\n const staged = await operations.stage({\n data,\n files,\n req,\n trackStagedObject,\n })\n metadata = staged.metadata\n Object.assign(data, metadata)\n },\n write: async () => {\n if (\n collection.versions &&\n !hasStoredOriginal({ doc: current }) &&\n hasStoredOriginal({ doc: storedCurrent })\n ) {\n await persistLegacyCloudVersions({ id, collection, current: storedCurrent, req })\n }\n\n const result = await withCloudHookGuard({\n metadata,\n req,\n write,\n })\n\n await scheduleUnreferencedFileCleanup({\n candidates: await collectSavedFiles({ collection, doc: storedCurrent, req }),\n collection,\n req,\n })\n\n return result\n },\n })\n}\n\n/** Track a verified client-uploaded source, retaining it if another document still references it. */\nconst trackClientUploadOriginal = ({\n collection,\n data,\n req,\n trackStagedObject,\n}: {\n collection: SanitizedCollectionConfig\n data: JsonObject\n req: PayloadRequest\n trackStagedObject: (object: StagedObject) => void\n}): void => {\n const verifiedOriginal = req.context?._payloadVerifiedProviderOriginal as\n | { key: string }\n | undefined\n\n if (!verifiedOriginal) {\n return\n }\n\n const original = collectStoredFiles({ collection, doc: data, req, trustGenerated: true }).find(\n ({ key, roles }) =>\n key === verifiedOriginal.key && roles.some((role) => role.type === 'original'),\n )\n\n if (!original) {\n return\n }\n\n const object: StagedObject = {\n key: original.key,\n remove: () => collection.upload.fileOperations!.delete({ key: original.key, req }),\n }\n\n trackStagedObject({\n key: object.key,\n remove: () => removeUnreferencedStagedObjects({ collection, objects: [object], req }),\n })\n}\n\nconst persistLegacyCloudVersions = async ({\n id,\n collection,\n current,\n req,\n}: {\n collection: SanitizedCollectionConfig\n current: JsonObject\n id: number | string\n req: PayloadRequest\n}): Promise<void> => {\n let page = 1\n let hasVersions = false\n\n while (true) {\n const versions = await req.payload.db.findVersions<JsonObject>({\n collection: collection.slug,\n limit: 100,\n page,\n req,\n where: { parent: { equals: id } },\n })\n\n for (const row of versions.docs) {\n hasVersions = true\n if (hasStoredOriginal({ doc: row.version })) {\n continue\n }\n\n const version = await withLegacyCloudUploadFileData({\n collection,\n doc: row.version,\n req,\n })\n if (!hasStoredOriginal({ doc: version })) {\n continue\n }\n\n await req.payload.db.updateVersion({\n id: row.id,\n collection: collection.slug,\n req,\n versionData: {\n createdAt: row.createdAt,\n latest: row.latest,\n parent: row.parent,\n publishedLocale: row.publishedLocale,\n updatedAt: row.updatedAt,\n version,\n },\n })\n }\n\n if (versions.docs.length < 100) {\n break\n }\n page += 1\n }\n\n if (!hasVersions && hasStoredOriginal({ doc: current })) {\n await saveVersion({\n id,\n collection,\n docWithLocales: current,\n draft: false,\n operation: 'update',\n payload: req.payload,\n req,\n })\n }\n}\n\nconst hasStoredOriginal = ({ doc }: { doc: JsonObject }): boolean =>\n Boolean(\n doc.original &&\n typeof doc.original === 'object' &&\n typeof (doc.original as Record<string, unknown>).filename === 'string',\n )\n\nconst withCloudHookGuard = async <T>({\n metadata,\n req,\n write,\n}: {\n metadata: Record<string, unknown>\n req: PayloadRequest\n write: () => Promise<T>\n}): Promise<T> => {\n const restoreCloudHookState = captureCloudHookState({ req })\n req.context ??= {}\n req.context._payloadManagedCloudStorage = true\n req.context._payloadManagedCloudMetadata = metadata\n\n try {\n return await write()\n } finally {\n restoreCloudHookState()\n }\n}\n"],"names":["saveVersion","collectStoredFiles","collectSavedFiles","removeUnreferencedStagedObjects","scheduleUnreferencedFileCleanup","runFileCreationPlan","runFileOperationPlan","getStoredFileIdentity","withLegacyCloudUploadFileData","captureCloudHookState","req","previousState","map","key","hasProperty","Object","hasOwn","context","value","runCloudFileCreation","collection","data","files","write","operations","upload","fileOperations","skipCloudStorage","length","_payloadVerifiedProviderOriginal","metadata","cleanupStagedAfterWriteFailure","objects","stage","trackStagedObject","trackClientUploadOriginal","staged","assign","_payloadManagedCloudStorage","_payloadManagedCloudMetadata","runCloudFileUpdate","id","current","storedCurrent","doc","nextFiles","trustGenerated","currentFiles","nextIdentities","Set","hasStoredFileChange","size","some","file","has","versions","hasStoredOriginal","persistLegacyCloudVersions","result","withCloudHookGuard","candidates","verifiedOriginal","original","find","roles","role","type","object","remove","delete","page","hasVersions","payload","db","findVersions","slug","limit","where","parent","equals","row","docs","version","updateVersion","versionData","createdAt","latest","publishedLocale","updatedAt","docWithLocales","draft","operation","Boolean","filename","restoreCloudHookState"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/uploads/fileVersioning/cloudStorage.ts"],"sourcesContent":["import type { SanitizedCollectionConfig } from '../../collections/config/types.js'\nimport type { JsonObject, PayloadRequest } from '../../types/index.js'\nimport type { FileToSave } from '../types.js'\nimport type { StagedObject } from './fileOperationManager.js'\n\nimport { saveVersion } from '../../versions/saveVersion.js'\nimport {\n collectStoredFiles as collectSavedFiles,\n removeUnreferencedStagedObjects,\n scheduleUnreferencedFileCleanup,\n} from './cleanup.js'\nimport { runFileCreationPlan, runFileOperationPlan } from './fileOperationManager.js'\nimport {\n collectStoredFiles,\n getStoredFileIdentity,\n withLegacyCloudUploadFileData,\n} from './storedFiles.js'\n\n/** Preserve the caller's cloud flags; nested Local API calls can replace req.context. */\nexport const captureCloudHookState = ({ req }: { req: PayloadRequest }): (() => void) => {\n const previousState = ['_payloadManagedCloudStorage', '_payloadManagedCloudMetadata'].map(\n (key) => ({\n hasProperty: Object.hasOwn(req.context ?? {}, key),\n key,\n value: req.context?.[key],\n }),\n )\n\n return () => {\n req.context ??= {}\n for (const { hasProperty, key, value } of previousState) {\n if (hasProperty) {\n req.context[key] = value\n } else {\n delete req.context[key]\n }\n }\n }\n}\n\nexport const runCloudFileCreation = async <T>({\n collection,\n data,\n files,\n req,\n write,\n}: {\n collection: SanitizedCollectionConfig\n data: JsonObject\n files: FileToSave[]\n req: PayloadRequest\n write: () => Promise<T>\n}): Promise<T> => {\n const operations = collection.upload.fileOperations\n\n if (\n !operations ||\n req.context?.skipCloudStorage ||\n (files.length === 0 && !req.context?._payloadVerifiedProviderOriginal)\n ) {\n return write()\n }\n\n let metadata: Record<string, unknown> = {}\n\n return runFileCreationPlan({\n cleanupStagedAfterWriteFailure: (objects) =>\n removeUnreferencedStagedObjects({ collection, objects, req }),\n req,\n stage: async ({ trackStagedObject }) => {\n trackClientUploadOriginal({ collection, data, req, trackStagedObject })\n const staged = await operations.stage({\n data,\n files,\n req,\n trackStagedObject,\n })\n metadata = staged.metadata\n Object.assign(data, metadata)\n },\n // Create's version and afterChange hooks run after the database insert. The\n // outer create operation restores the previous guard after those hooks finish.\n write: () => {\n req.context ??= {}\n req.context._payloadManagedCloudStorage = true\n req.context._payloadManagedCloudMetadata = metadata\n return write()\n },\n })\n}\n\nexport const runCloudFileUpdate = async <T>({\n id,\n collection,\n current,\n data,\n files,\n req,\n write,\n}: {\n collection: SanitizedCollectionConfig\n current: JsonObject\n data: JsonObject\n files: FileToSave[]\n id: number | string\n req: PayloadRequest\n write: () => Promise<T>\n}): Promise<T> => {\n const operations = collection.upload.fileOperations\n const storedCurrent = operations\n ? await withLegacyCloudUploadFileData({ collection, doc: current, req })\n : current\n const nextFiles = collectStoredFiles({\n collection,\n doc: { ...storedCurrent, ...data },\n req,\n trustGenerated: true,\n })\n const currentFiles = collectStoredFiles({ collection, doc: storedCurrent, req })\n const nextIdentities = new Set(nextFiles.map(getStoredFileIdentity))\n const hasStoredFileChange =\n nextIdentities.size !== currentFiles.length ||\n currentFiles.some((file) => !nextIdentities.has(getStoredFileIdentity(file)))\n\n if (\n !operations ||\n req.context?.skipCloudStorage ||\n (files.length === 0 && !req.context?._payloadVerifiedProviderOriginal && !hasStoredFileChange)\n ) {\n return write()\n }\n\n let metadata: Record<string, unknown> = {}\n\n return runFileOperationPlan({\n cleanupStagedAfterWriteFailure: (objects) =>\n removeUnreferencedStagedObjects({ collection, objects, req }),\n req,\n stage: async ({ trackStagedObject }) => {\n if (files.length === 0 && !req.context?._payloadVerifiedProviderOriginal) {\n return\n }\n trackClientUploadOriginal({ collection, data, req, trackStagedObject })\n const staged = await operations.stage({\n data,\n files,\n req,\n trackStagedObject,\n })\n metadata = staged.metadata\n Object.assign(data, metadata)\n },\n write: async () => {\n if (\n collection.versions &&\n !hasStoredOriginal({ doc: current }) &&\n hasStoredOriginal({ doc: storedCurrent })\n ) {\n await persistLegacyCloudVersions({ id, collection, current: storedCurrent, req })\n }\n\n const result = await withCloudHookGuard({\n metadata,\n req,\n write,\n })\n\n await scheduleUnreferencedFileCleanup({\n candidates: await collectSavedFiles({ collection, doc: storedCurrent, req }),\n collection,\n req,\n })\n\n return result\n },\n })\n}\n\n/** Track a verified client-uploaded source, retaining it if another document still references it. */\nconst trackClientUploadOriginal = ({\n collection,\n data,\n req,\n trackStagedObject,\n}: {\n collection: SanitizedCollectionConfig\n data: JsonObject\n req: PayloadRequest\n trackStagedObject: (object: StagedObject) => void\n}): void => {\n const verifiedOriginal = req.context?._payloadVerifiedProviderOriginal as\n | { key: string }\n | undefined\n\n if (!verifiedOriginal) {\n return\n }\n\n const original = collectStoredFiles({ collection, doc: data, req, trustGenerated: true }).find(\n ({ key, roles }) =>\n key === verifiedOriginal.key && roles.some((role) => role.type === 'original'),\n )\n\n if (!original) {\n return\n }\n\n const object: StagedObject = {\n key: original.key,\n remove: () => collection.upload.fileOperations!.delete({ key: original.key, req }),\n }\n\n trackStagedObject({\n key: object.key,\n remove: () => removeUnreferencedStagedObjects({ collection, objects: [object], req }),\n })\n}\n\nconst persistLegacyCloudVersions = async ({\n id,\n collection,\n current,\n req,\n}: {\n collection: SanitizedCollectionConfig\n current: JsonObject\n id: number | string\n req: PayloadRequest\n}): Promise<void> => {\n let page = 1\n let hasVersions = false\n\n while (true) {\n const versions = await req.payload.db.findVersions<JsonObject>({\n collection: collection.slug,\n limit: 100,\n page,\n req,\n where: { parent: { equals: id } },\n })\n\n for (const row of versions.docs) {\n hasVersions = true\n if (hasStoredOriginal({ doc: row.version })) {\n continue\n }\n\n const version = await withLegacyCloudUploadFileData({\n collection,\n doc: row.version,\n req,\n })\n if (!hasStoredOriginal({ doc: version })) {\n continue\n }\n\n await req.payload.db.updateVersion({\n id: row.id,\n collection: collection.slug,\n req,\n versionData: {\n createdAt: row.createdAt,\n latest: row.latest,\n parent: row.parent,\n publishedLocale: row.publishedLocale,\n updatedAt: row.updatedAt,\n version,\n },\n })\n }\n\n if (versions.docs.length < 100) {\n break\n }\n page += 1\n }\n\n if (!hasVersions && hasStoredOriginal({ doc: current })) {\n await saveVersion({\n id,\n collection,\n docWithLocales: current,\n draft: false,\n operation: 'update',\n payload: req.payload,\n req,\n })\n }\n}\n\nconst hasStoredOriginal = ({ doc }: { doc: JsonObject }): boolean =>\n Boolean(\n doc.original &&\n typeof doc.original === 'object' &&\n typeof (doc.original as Record<string, unknown>).filename === 'string',\n )\n\nconst withCloudHookGuard = async <T>({\n metadata,\n req,\n write,\n}: {\n metadata: Record<string, unknown>\n req: PayloadRequest\n write: () => Promise<T>\n}): Promise<T> => {\n const restoreCloudHookState = captureCloudHookState({ req })\n req.context ??= {}\n req.context._payloadManagedCloudStorage = true\n req.context._payloadManagedCloudMetadata = metadata\n\n try {\n return await write()\n } finally {\n restoreCloudHookState()\n }\n}\n"],"names":["saveVersion","collectStoredFiles","collectSavedFiles","removeUnreferencedStagedObjects","scheduleUnreferencedFileCleanup","runFileCreationPlan","runFileOperationPlan","getStoredFileIdentity","withLegacyCloudUploadFileData","captureCloudHookState","req","previousState","map","key","hasProperty","Object","hasOwn","context","value","runCloudFileCreation","collection","data","files","write","operations","upload","fileOperations","skipCloudStorage","length","_payloadVerifiedProviderOriginal","metadata","cleanupStagedAfterWriteFailure","objects","stage","trackStagedObject","trackClientUploadOriginal","staged","assign","_payloadManagedCloudStorage","_payloadManagedCloudMetadata","runCloudFileUpdate","id","current","storedCurrent","doc","nextFiles","trustGenerated","currentFiles","nextIdentities","Set","hasStoredFileChange","size","some","file","has","versions","hasStoredOriginal","persistLegacyCloudVersions","result","withCloudHookGuard","candidates","verifiedOriginal","original","find","roles","role","type","object","remove","delete","page","hasVersions","payload","db","findVersions","slug","limit","where","parent","equals","row","docs","version","updateVersion","versionData","createdAt","latest","publishedLocale","updatedAt","docWithLocales","draft","operation","Boolean","filename","restoreCloudHookState"],"mappings":"AAKA,SAASA,WAAW,QAAQ,gCAA+B;AAC3D,SACEC,sBAAsBC,iBAAiB,EACvCC,+BAA+B,EAC/BC,+BAA+B,QAC1B,eAAc;AACrB,SAASC,mBAAmB,EAAEC,oBAAoB,QAAQ,4BAA2B;AACrF,SACEL,kBAAkB,EAClBM,qBAAqB,EACrBC,6BAA6B,QACxB,mBAAkB;AAEzB,uFAAuF,GACvF,OAAO,MAAMC,wBAAwB,CAAC,EAAEC,GAAG,EAA2B;IACpE,MAAMC,gBAAgB;QAAC;QAA+B;KAA+B,CAACC,GAAG,CACvF,CAACC,MAAS,CAAA;YACRC,aAAaC,OAAOC,MAAM,CAACN,IAAIO,OAAO,IAAI,CAAC,GAAGJ;YAC9CA;YACAK,OAAOR,IAAIO,OAAO,EAAE,CAACJ,IAAI;QAC3B,CAAA;IAGF,OAAO;QACLH,IAAIO,OAAO,KAAK,CAAC;QACjB,KAAK,MAAM,EAAEH,WAAW,EAAED,GAAG,EAAEK,KAAK,EAAE,IAAIP,cAAe;YACvD,IAAIG,aAAa;gBACfJ,IAAIO,OAAO,CAACJ,IAAI,GAAGK;YACrB,OAAO;gBACL,OAAOR,IAAIO,OAAO,CAACJ,IAAI;YACzB;QACF;IACF;AACF,EAAC;AAED,OAAO,MAAMM,uBAAuB,OAAU,EAC5CC,UAAU,EACVC,IAAI,EACJC,KAAK,EACLZ,GAAG,EACHa,KAAK,EAON;IACC,MAAMC,aAAaJ,WAAWK,MAAM,CAACC,cAAc;IAEnD,IACE,CAACF,cACDd,IAAIO,OAAO,EAAEU,oBACZL,MAAMM,MAAM,KAAK,KAAK,CAAClB,IAAIO,OAAO,EAAEY,kCACrC;QACA,OAAON;IACT;IAEA,IAAIO,WAAoC,CAAC;IAEzC,OAAOzB,oBAAoB;QACzB0B,gCAAgC,CAACC,UAC/B7B,gCAAgC;gBAAEiB;gBAAYY;gBAAStB;YAAI;QAC7DA;QACAuB,OAAO,OAAO,EAAEC,iBAAiB,EAAE;YACjCC,0BAA0B;gBAAEf;gBAAYC;gBAAMX;gBAAKwB;YAAkB;YACrE,MAAME,SAAS,MAAMZ,WAAWS,KAAK,CAAC;gBACpCZ;gBACAC;gBACAZ;gBACAwB;YACF;YACAJ,WAAWM,OAAON,QAAQ;YAC1Bf,OAAOsB,MAAM,CAAChB,MAAMS;QACtB;QACA,4EAA4E;QAC5E,+EAA+E;QAC/EP,OAAO;YACLb,IAAIO,OAAO,KAAK,CAAC;YACjBP,IAAIO,OAAO,CAACqB,2BAA2B,GAAG;YAC1C5B,IAAIO,OAAO,CAACsB,4BAA4B,GAAGT;YAC3C,OAAOP;QACT;IACF;AACF,EAAC;AAED,OAAO,MAAMiB,qBAAqB,OAAU,EAC1CC,EAAE,EACFrB,UAAU,EACVsB,OAAO,EACPrB,IAAI,EACJC,KAAK,EACLZ,GAAG,EACHa,KAAK,EASN;IACC,MAAMC,aAAaJ,WAAWK,MAAM,CAACC,cAAc;IACnD,MAAMiB,gBAAgBnB,aAClB,MAAMhB,8BAA8B;QAAEY;QAAYwB,KAAKF;QAAShC;IAAI,KACpEgC;IACJ,MAAMG,YAAY5C,mBAAmB;QACnCmB;QACAwB,KAAK;YAAE,GAAGD,aAAa;YAAE,GAAGtB,IAAI;QAAC;QACjCX;QACAoC,gBAAgB;IAClB;IACA,MAAMC,eAAe9C,mBAAmB;QAAEmB;QAAYwB,KAAKD;QAAejC;IAAI;IAC9E,MAAMsC,iBAAiB,IAAIC,IAAIJ,UAAUjC,GAAG,CAACL;IAC7C,MAAM2C,sBACJF,eAAeG,IAAI,KAAKJ,aAAanB,MAAM,IAC3CmB,aAAaK,IAAI,CAAC,CAACC,OAAS,CAACL,eAAeM,GAAG,CAAC/C,sBAAsB8C;IAExE,IACE,CAAC7B,cACDd,IAAIO,OAAO,EAAEU,oBACZL,MAAMM,MAAM,KAAK,KAAK,CAAClB,IAAIO,OAAO,EAAEY,oCAAoC,CAACqB,qBAC1E;QACA,OAAO3B;IACT;IAEA,IAAIO,WAAoC,CAAC;IAEzC,OAAOxB,qBAAqB;QAC1ByB,gCAAgC,CAACC,UAC/B7B,gCAAgC;gBAAEiB;gBAAYY;gBAAStB;YAAI;QAC7DA;QACAuB,OAAO,OAAO,EAAEC,iBAAiB,EAAE;YACjC,IAAIZ,MAAMM,MAAM,KAAK,KAAK,CAAClB,IAAIO,OAAO,EAAEY,kCAAkC;gBACxE;YACF;YACAM,0BAA0B;gBAAEf;gBAAYC;gBAAMX;gBAAKwB;YAAkB;YACrE,MAAME,SAAS,MAAMZ,WAAWS,KAAK,CAAC;gBACpCZ;gBACAC;gBACAZ;gBACAwB;YACF;YACAJ,WAAWM,OAAON,QAAQ;YAC1Bf,OAAOsB,MAAM,CAAChB,MAAMS;QACtB;QACAP,OAAO;YACL,IACEH,WAAWmC,QAAQ,IACnB,CAACC,kBAAkB;gBAAEZ,KAAKF;YAAQ,MAClCc,kBAAkB;gBAAEZ,KAAKD;YAAc,IACvC;gBACA,MAAMc,2BAA2B;oBAAEhB;oBAAIrB;oBAAYsB,SAASC;oBAAejC;gBAAI;YACjF;YAEA,MAAMgD,SAAS,MAAMC,mBAAmB;gBACtC7B;gBACApB;gBACAa;YACF;YAEA,MAAMnB,gCAAgC;gBACpCwD,YAAY,MAAM1D,kBAAkB;oBAAEkB;oBAAYwB,KAAKD;oBAAejC;gBAAI;gBAC1EU;gBACAV;YACF;YAEA,OAAOgD;QACT;IACF;AACF,EAAC;AAED,mGAAmG,GACnG,MAAMvB,4BAA4B,CAAC,EACjCf,UAAU,EACVC,IAAI,EACJX,GAAG,EACHwB,iBAAiB,EAMlB;IACC,MAAM2B,mBAAmBnD,IAAIO,OAAO,EAAEY;IAItC,IAAI,CAACgC,kBAAkB;QACrB;IACF;IAEA,MAAMC,WAAW7D,mBAAmB;QAAEmB;QAAYwB,KAAKvB;QAAMX;QAAKoC,gBAAgB;IAAK,GAAGiB,IAAI,CAC5F,CAAC,EAAElD,GAAG,EAAEmD,KAAK,EAAE,GACbnD,QAAQgD,iBAAiBhD,GAAG,IAAImD,MAAMZ,IAAI,CAAC,CAACa,OAASA,KAAKC,IAAI,KAAK;IAGvE,IAAI,CAACJ,UAAU;QACb;IACF;IAEA,MAAMK,SAAuB;QAC3BtD,KAAKiD,SAASjD,GAAG;QACjBuD,QAAQ,IAAMhD,WAAWK,MAAM,CAACC,cAAc,CAAE2C,MAAM,CAAC;gBAAExD,KAAKiD,SAASjD,GAAG;gBAAEH;YAAI;IAClF;IAEAwB,kBAAkB;QAChBrB,KAAKsD,OAAOtD,GAAG;QACfuD,QAAQ,IAAMjE,gCAAgC;gBAAEiB;gBAAYY,SAAS;oBAACmC;iBAAO;gBAAEzD;YAAI;IACrF;AACF;AAEA,MAAM+C,6BAA6B,OAAO,EACxChB,EAAE,EACFrB,UAAU,EACVsB,OAAO,EACPhC,GAAG,EAMJ;IACC,IAAI4D,OAAO;IACX,IAAIC,cAAc;IAElB,MAAO,KAAM;QACX,MAAMhB,WAAW,MAAM7C,IAAI8D,OAAO,CAACC,EAAE,CAACC,YAAY,CAAa;YAC7DtD,YAAYA,WAAWuD,IAAI;YAC3BC,OAAO;YACPN;YACA5D;YACAmE,OAAO;gBAAEC,QAAQ;oBAAEC,QAAQtC;gBAAG;YAAE;QAClC;QAEA,KAAK,MAAMuC,OAAOzB,SAAS0B,IAAI,CAAE;YAC/BV,cAAc;YACd,IAAIf,kBAAkB;gBAAEZ,KAAKoC,IAAIE,OAAO;YAAC,IAAI;gBAC3C;YACF;YAEA,MAAMA,UAAU,MAAM1E,8BAA8B;gBAClDY;gBACAwB,KAAKoC,IAAIE,OAAO;gBAChBxE;YACF;YACA,IAAI,CAAC8C,kBAAkB;gBAAEZ,KAAKsC;YAAQ,IAAI;gBACxC;YACF;YAEA,MAAMxE,IAAI8D,OAAO,CAACC,EAAE,CAACU,aAAa,CAAC;gBACjC1C,IAAIuC,IAAIvC,EAAE;gBACVrB,YAAYA,WAAWuD,IAAI;gBAC3BjE;gBACA0E,aAAa;oBACXC,WAAWL,IAAIK,SAAS;oBACxBC,QAAQN,IAAIM,MAAM;oBAClBR,QAAQE,IAAIF,MAAM;oBAClBS,iBAAiBP,IAAIO,eAAe;oBACpCC,WAAWR,IAAIQ,SAAS;oBACxBN;gBACF;YACF;QACF;QAEA,IAAI3B,SAAS0B,IAAI,CAACrD,MAAM,GAAG,KAAK;YAC9B;QACF;QACA0C,QAAQ;IACV;IAEA,IAAI,CAACC,eAAef,kBAAkB;QAAEZ,KAAKF;IAAQ,IAAI;QACvD,MAAM1C,YAAY;YAChByC;YACArB;YACAqE,gBAAgB/C;YAChBgD,OAAO;YACPC,WAAW;YACXnB,SAAS9D,IAAI8D,OAAO;YACpB9D;QACF;IACF;AACF;AAEA,MAAM8C,oBAAoB,CAAC,EAAEZ,GAAG,EAAuB,GACrDgD,QACEhD,IAAIkB,QAAQ,IACZ,OAAOlB,IAAIkB,QAAQ,KAAK,YACxB,OAAO,AAAClB,IAAIkB,QAAQ,CAA6B+B,QAAQ,KAAK;AAGlE,MAAMlC,qBAAqB,OAAU,EACnC7B,QAAQ,EACRpB,GAAG,EACHa,KAAK,EAKN;IACC,MAAMuE,wBAAwBrF,sBAAsB;QAAEC;IAAI;IAC1DA,IAAIO,OAAO,KAAK,CAAC;IACjBP,IAAIO,OAAO,CAACqB,2BAA2B,GAAG;IAC1C5B,IAAIO,OAAO,CAACsB,4BAA4B,GAAGT;IAE3C,IAAI;QACF,OAAO,MAAMP;IACf,SAAU;QACRuE;IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/uploads/fileVersioning/resolveHistoricalFile.ts"],"sourcesContent":["import type { Collection, TypeWithID } from '../../collections/config/types.js'\nimport type { JsonObject, PayloadRequest } from '../../types/index.js'\n\nimport { Forbidden } from '../../errors/Forbidden.js'\nimport { NotFound } from '../../errors/NotFound.js'\nimport { checkFileAccess } from '../checkFileAccess.js'\nimport { collectStoredFiles, withLegacyCloudUploadFileData } from './storedFiles.js'\n\ntype StoredVersion = {\n id: number | string\n parent: number | string\n version: JsonObject\n}\n\n/** Finds an exact saved object reference, including sizes removed from the current config. */\nexport const resolveHistoricalFile = async ({\n collection,\n filename,\n prefix,\n req,\n versionID,\n}: {\n collection: Collection\n filename: string\n prefix?: string\n req: PayloadRequest\n versionID: string\n}): Promise<TypeWithID> => {\n const { docs } = await req.payload.db.findVersions<JsonObject>({\n collection: collection.config.slug,\n limit: 1,\n req,\n where: { id: { equals: versionID } },\n })\n const matched = docs[0]\n\n // Check both policies before exposing a missing version or a filename mismatch.\n await checkFileAccess({ collection, documentID: matched?.parent, filename, req })\n const authorized = await req.payload.findVersionByID({\n id: versionID,\n collection: collection.config.slug,\n depth: 0,\n overrideAccess: false,\n req,\n showHiddenFields: true,\n })\n\n if (!authorized) {\n throw new Forbidden(req.t)\n }\n\n if (!matched) {\n throw new NotFound(req.t)\n }\n\n const historical = await resolveVersionFile({ collection, filename, prefix, req, row: matched })\n\n if (!historical) {\n throw new NotFound(req.t)\n }\n\n return historical\n}\n\nconst resolveVersionFile = async ({\n collection,\n filename,\n prefix,\n req,\n row,\n}: {\n collection: Collection\n filename: string\n prefix?: string\n req: PayloadRequest\n row: StoredVersion\n}): Promise<TypeWithID | undefined> => {\n const saved = await withLegacyCloudUploadFileData({\n collection: collection.config,\n doc: row.version,\n req,\n })\n const hasFile = collectStoredFiles({ collection: collection.config, doc: saved, req }).some(\n (file) =>\n file.roles.some((role) => {\n const representation =\n role.type === 'size'\n ? (saved.variants as Record<string, JsonObject> | undefined)?.[role.sizeKey]\n : role.type === 'original'\n ? (saved.original as JsonObject | undefined)\n : saved\n return (\n representation?.filename === filename && (!prefix || representation.prefix === prefix)\n )\n }),\n )\n\n if (!hasFile) {\n return\n }\n\n return { ...saved, id: row.parent }
|
|
1
|
+
{"version":3,"sources":["../../../src/uploads/fileVersioning/resolveHistoricalFile.ts"],"sourcesContent":["import type { Collection, TypeWithID } from '../../collections/config/types.js'\nimport type { JsonObject, PayloadRequest } from '../../types/index.js'\n\nimport { Forbidden } from '../../errors/Forbidden.js'\nimport { NotFound } from '../../errors/NotFound.js'\nimport { checkFileAccess } from '../checkFileAccess.js'\nimport { collectStoredFiles, withLegacyCloudUploadFileData } from './storedFiles.js'\n\ntype StoredVersion = {\n id: number | string\n parent: number | string\n version: JsonObject\n}\n\n/** Finds an exact saved object reference, including sizes removed from the current config. */\nexport const resolveHistoricalFile = async ({\n collection,\n filename,\n prefix,\n req,\n versionID,\n}: {\n collection: Collection\n filename: string\n prefix?: string\n req: PayloadRequest\n versionID: string\n}): Promise<TypeWithID> => {\n const { docs } = await req.payload.db.findVersions<JsonObject>({\n collection: collection.config.slug,\n limit: 1,\n req,\n where: { id: { equals: versionID } },\n })\n const matched = docs[0]\n\n // Check both policies before exposing a missing version or a filename mismatch.\n await checkFileAccess({ collection, documentID: matched?.parent, filename, req })\n const authorized = await req.payload.findVersionByID({\n id: versionID,\n collection: collection.config.slug,\n depth: 0,\n overrideAccess: false,\n req,\n showHiddenFields: true,\n })\n\n if (!authorized) {\n throw new Forbidden(req.t)\n }\n\n if (!matched) {\n throw new NotFound(req.t)\n }\n\n const historical = await resolveVersionFile({ collection, filename, prefix, req, row: matched })\n\n if (!historical) {\n throw new NotFound(req.t)\n }\n\n return historical\n}\n\nconst resolveVersionFile = async ({\n collection,\n filename,\n prefix,\n req,\n row,\n}: {\n collection: Collection\n filename: string\n prefix?: string\n req: PayloadRequest\n row: StoredVersion\n}): Promise<TypeWithID | undefined> => {\n const saved = await withLegacyCloudUploadFileData({\n collection: collection.config,\n doc: row.version,\n req,\n })\n const hasFile = collectStoredFiles({ collection: collection.config, doc: saved, req }).some(\n (file) =>\n file.roles.some((role) => {\n const representation =\n role.type === 'size'\n ? (saved.variants as Record<string, JsonObject> | undefined)?.[role.sizeKey]\n : role.type === 'original'\n ? (saved.original as JsonObject | undefined)\n : saved\n return (\n representation?.filename === filename && (!prefix || representation.prefix === prefix)\n )\n }),\n )\n\n if (!hasFile) {\n return\n }\n\n return { ...saved, id: row.parent }\n}\n"],"names":["Forbidden","NotFound","checkFileAccess","collectStoredFiles","withLegacyCloudUploadFileData","resolveHistoricalFile","collection","filename","prefix","req","versionID","docs","payload","db","findVersions","config","slug","limit","where","id","equals","matched","documentID","parent","authorized","findVersionByID","depth","overrideAccess","showHiddenFields","t","historical","resolveVersionFile","row","saved","doc","version","hasFile","some","file","roles","role","representation","type","variants","sizeKey","original"],"mappings":"AAGA,SAASA,SAAS,QAAQ,4BAA2B;AACrD,SAASC,QAAQ,QAAQ,2BAA0B;AACnD,SAASC,eAAe,QAAQ,wBAAuB;AACvD,SAASC,kBAAkB,EAAEC,6BAA6B,QAAQ,mBAAkB;AAQpF,4FAA4F,GAC5F,OAAO,MAAMC,wBAAwB,OAAO,EAC1CC,UAAU,EACVC,QAAQ,EACRC,MAAM,EACNC,GAAG,EACHC,SAAS,EAOV;IACC,MAAM,EAAEC,IAAI,EAAE,GAAG,MAAMF,IAAIG,OAAO,CAACC,EAAE,CAACC,YAAY,CAAa;QAC7DR,YAAYA,WAAWS,MAAM,CAACC,IAAI;QAClCC,OAAO;QACPR;QACAS,OAAO;YAAEC,IAAI;gBAAEC,QAAQV;YAAU;QAAE;IACrC;IACA,MAAMW,UAAUV,IAAI,CAAC,EAAE;IAEvB,gFAAgF;IAChF,MAAMT,gBAAgB;QAAEI;QAAYgB,YAAYD,SAASE;QAAQhB;QAAUE;IAAI;IAC/E,MAAMe,aAAa,MAAMf,IAAIG,OAAO,CAACa,eAAe,CAAC;QACnDN,IAAIT;QACJJ,YAAYA,WAAWS,MAAM,CAACC,IAAI;QAClCU,OAAO;QACPC,gBAAgB;QAChBlB;QACAmB,kBAAkB;IACpB;IAEA,IAAI,CAACJ,YAAY;QACf,MAAM,IAAIxB,UAAUS,IAAIoB,CAAC;IAC3B;IAEA,IAAI,CAACR,SAAS;QACZ,MAAM,IAAIpB,SAASQ,IAAIoB,CAAC;IAC1B;IAEA,MAAMC,aAAa,MAAMC,mBAAmB;QAAEzB;QAAYC;QAAUC;QAAQC;QAAKuB,KAAKX;IAAQ;IAE9F,IAAI,CAACS,YAAY;QACf,MAAM,IAAI7B,SAASQ,IAAIoB,CAAC;IAC1B;IAEA,OAAOC;AACT,EAAC;AAED,MAAMC,qBAAqB,OAAO,EAChCzB,UAAU,EACVC,QAAQ,EACRC,MAAM,EACNC,GAAG,EACHuB,GAAG,EAOJ;IACC,MAAMC,QAAQ,MAAM7B,8BAA8B;QAChDE,YAAYA,WAAWS,MAAM;QAC7BmB,KAAKF,IAAIG,OAAO;QAChB1B;IACF;IACA,MAAM2B,UAAUjC,mBAAmB;QAAEG,YAAYA,WAAWS,MAAM;QAAEmB,KAAKD;QAAOxB;IAAI,GAAG4B,IAAI,CACzF,CAACC,OACCA,KAAKC,KAAK,CAACF,IAAI,CAAC,CAACG;YACf,MAAMC,iBACJD,KAAKE,IAAI,KAAK,SACTT,MAAMU,QAAQ,EAA6C,CAACH,KAAKI,OAAO,CAAC,GAC1EJ,KAAKE,IAAI,KAAK,aACXT,MAAMY,QAAQ,GACfZ;YACR,OACEQ,gBAAgBlC,aAAaA,YAAa,CAAA,CAACC,UAAUiC,eAAejC,MAAM,KAAKA,MAAK;QAExF;IAGJ,IAAI,CAAC4B,SAAS;QACZ;IACF;IAEA,OAAO;QAAE,GAAGH,KAAK;QAAEd,IAAIa,IAAIT,MAAM;IAAC;AACpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateFileData.d.ts","sourceRoot":"","sources":["../../src/uploads/generateFileData.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,gCAAgC,CAAA;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAEnE,OAAO,KAAK,EAAuB,UAAU,EAAe,MAAM,YAAY,CAAA;AAwB9E,KAAK,IAAI,CAAC,CAAC,IAAI;IACb,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,eAAe,CAAA;IACvB,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC9B,WAAW,CAAC,EAAE,CAAC,CAAA;IACf,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,GAAG,EAAE,cAAc,CAAA;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,KAAK,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC;IACvB,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB,CAAC,CAAA;AA6BF,MAAM,MAAM,gBAAgB,GACxB;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAA;AAEzB;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,+DAIjC;IACD,mBAAmB,EAAE,OAAO,CAAA;IAC5B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC,KAAG,gBAQH,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAU,CAAC,4KAWrC,IAAI,CAAC,CAAC,CAAC,KAAG,MAAM,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"generateFileData.d.ts","sourceRoot":"","sources":["../../src/uploads/generateFileData.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,gCAAgC,CAAA;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAEnE,OAAO,KAAK,EAAuB,UAAU,EAAe,MAAM,YAAY,CAAA;AAwB9E,KAAK,IAAI,CAAC,CAAC,IAAI;IACb,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,eAAe,CAAA;IACvB,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC9B,WAAW,CAAC,EAAE,CAAC,CAAA;IACf,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,GAAG,EAAE,cAAc,CAAA;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,KAAK,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC;IACvB,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB,CAAC,CAAA;AA6BF,MAAM,MAAM,gBAAgB,GACxB;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAA;AAEzB;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,+DAIjC;IACD,mBAAmB,EAAE,OAAO,CAAA;IAC5B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC,KAAG,gBAQH,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAU,CAAC,4KAWrC,IAAI,CAAC,CAAC,CAAC,KAAG,MAAM,CAAC,CAAC,CAooBpB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/uploads/generateFileData.ts"],"sourcesContent":["import { fileTypeFromBuffer } from 'file-type'\nimport fs from 'fs/promises'\nimport { randomUUID } from 'node:crypto'\nimport { openAsBlob } from 'node:fs'\n\nimport type { Collection, TypeWithID } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { Document, PayloadRequest } from '../types/index.js'\nimport type { ExternalUploadSource } from './sanitizeUploadData.js'\nimport type { PreparedUploadTransformation } from './transformers/uploadTransformerBridge.js'\nimport type { FileData, FileSizes, FileToSave, UploadEdits } from './types.js'\n\nimport { FileRetrievalError, FileUploadError, Forbidden, MissingFile } from '../errors/index.js'\nimport { formatAdminURL } from '../utilities/formatAdminURL.js'\nimport { isNumber } from '../utilities/isNumber.js'\nimport { canResizeImage } from './canResizeImage.js'\nimport { checkFileRestrictions } from './checkFileRestrictions.js'\nimport { downloadFileToBuffer } from './downloadFileToBuffer.js'\nimport { getOriginalFilename } from './fileVersioning/naming.js'\nimport { generateImageSizeFilename } from './generateImageSizeFilename.js'\nimport { getFileByPath } from './getFileByPath.js'\nimport { getFileExtension, getSanitizedUploadFilename } from './getFileTypeIdentity.js'\nimport { getImageSize } from './getImageSize.js'\nimport { getSafeFileName, incrementName } from './getSafeFilename.js'\nimport { hasCropOrResizeEdit } from './hasCropOrResizeEdit.js'\nimport { hasFullFileContents } from './hasFullFileContents.js'\nimport { isProcessableImage } from './isProcessableImage.js'\nimport { parseFilename } from './parseFilename.js'\nimport { planTransformerPipeline } from './transformers/planTransformerPipeline.js'\nimport { transformUploadFile } from './transformers/transformUploadFile.js'\nimport {\n getUploadTransformerInternal,\n setUploadFilePath,\n} from './transformers/uploadTransformerBridge.js'\ntype Args<T> = {\n collection: Collection\n config: SanitizedConfig\n data: T\n draft?: boolean\n externalUploadSource?: ExternalUploadSource\n isDuplicating?: boolean\n operation: 'create' | 'update'\n originalDoc?: T\n overwriteExistingFiles?: boolean\n req: PayloadRequest\n throwOnMissingFile?: boolean\n}\n\ntype Result<T> = Promise<{\n data: T\n files: FileToSave[]\n}>\n\nconst shouldReupload = (\n uploadEdits: undefined | UploadEdits,\n fileData: Record<string, unknown> | undefined,\n) => {\n if (!fileData || !uploadEdits) {\n return false\n }\n\n if (hasCropOrResizeEdit(uploadEdits)) {\n return true\n }\n\n // Since uploadEdits always has focalPoint, compare to the value in the data if it was changed\n if (uploadEdits.focalPoint) {\n const incomingFocalX = uploadEdits.focalPoint.x\n const incomingFocalY = uploadEdits.focalPoint.y\n\n const currentFocalX = 'focalX' in fileData && fileData.focalX\n const currentFocalY = 'focalY' in fileData && fileData.focalY\n\n const isEqual = incomingFocalX === currentFocalX && incomingFocalY === currentFocalY\n return !isEqual\n }\n\n return false\n}\n\nexport type TempFileHandling =\n | { sourcePath: string; type: 'copyFromTempFile' }\n | { type: 'skip' }\n | { type: 'useBuffer' }\n\n/**\n * Decides how to get a file's bytes onto disk when no transformer rewrote it (a transformed\n * file is already an in-memory buffer, so it always takes the `useBuffer` path). Copies straight\n * from the temp file when possible, rather than reading a potentially large temp file into memory\n * just to write it back out - see the `generateFileData` function doc for why.\n */\nexport const resolveTempFileHandling = ({\n disableLocalStorage,\n hasProcessedBuffer,\n tempFilePath,\n}: {\n disableLocalStorage: boolean\n hasProcessedBuffer: boolean\n tempFilePath: string | undefined\n}): TempFileHandling => {\n if (hasProcessedBuffer || !tempFilePath) {\n return { type: 'useBuffer' }\n }\n\n return disableLocalStorage\n ? { type: 'skip' }\n : { type: 'copyFromTempFile', sourcePath: tempFilePath }\n}\n\n/**\n * Builds the document's file metadata and the list of files to write to disk.\n *\n * A large client upload may arrive as a temp file instead of an in-memory buffer (see\n * getFileFromUploadInstructions.ts), and `file.data` can hold only a partial probe rather than\n * the full file. To avoid loading such files into memory unnecessarily, no transformer runs\n * unless the full bytes are available, this skips reading a temp file entirely when local\n * storage is disabled, and copies it straight to its destination when local storage is enabled.\n */\nexport const generateFileData = async <T>({\n collection: { config: collectionConfig },\n data,\n draft,\n externalUploadSource,\n isDuplicating,\n operation,\n originalDoc,\n overwriteExistingFiles,\n req,\n throwOnMissingFile,\n}: Args<T>): Result<T> => {\n if (!collectionConfig.upload) {\n return {\n data,\n files: [],\n }\n }\n\n const { serverURL } = req.payload.config\n\n let file = isDuplicating ? undefined : req.file\n\n const uploadEdits = parseUploadEditsFromReqOrIncomingData({\n data,\n isDuplicating,\n operation,\n // Only a duplication source informs edit parsing. Updates now also pass `originalDoc` so the\n // stored file can be reprocessed, and that must not change which edits are applied.\n originalDoc: isDuplicating ? originalDoc : undefined,\n req,\n })\n\n const {\n disableLocalStorage,\n focalPoint: focalPointEnabled = true,\n staticDir,\n } = collectionConfig.upload\n const hasManagedCloudStorage = Boolean(collectionConfig.upload.fileOperations)\n const uploadReference = file?.uploadReference\n const hasProviderDirectReference =\n uploadReference && typeof uploadReference === 'object' && !('uploadId' in uploadReference)\n const verifiedOriginal = req.context?._payloadVerifiedProviderOriginal as\n | {\n _objectKey?: string\n filename: string\n key: string\n prefix?: string\n signedReceipt: string\n }\n | undefined\n const providerOriginal =\n hasProviderDirectReference &&\n 'signedReceipt' in uploadReference &&\n uploadReference.signedReceipt === verifiedOriginal?.signedReceipt &&\n verifiedOriginal &&\n typeof collectionConfig.upload.adapter === 'string'\n ? {\n _objectKey: verifiedOriginal._objectKey,\n filename: verifiedOriginal.filename,\n key: verifiedOriginal.key,\n prefix: verifiedOriginal.prefix,\n }\n : undefined\n const shouldStageCloudFiles = hasManagedCloudStorage && !hasProviderDirectReference\n\n const staticPath = staticDir\n\n const incomingFileData: Document = isDuplicating ? originalDoc : data\n const currentFileData = (operation === 'update' ? originalDoc : incomingFileData) as\n | FileData\n | undefined\n const retainedOriginal =\n operation === 'update' &&\n !file &&\n !externalUploadSource &&\n typeof currentFileData?.original?.filename === 'string' &&\n typeof currentFileData.original.url === 'string'\n ? currentFileData.original\n : undefined\n const fileSourceData = externalUploadSource ?? retainedOriginal ?? currentFileData\n let isLocalFile = false\n\n if (\n !file &&\n fileSourceData &&\n (externalUploadSource ||\n isDuplicating ||\n shouldReupload(uploadEdits, incomingFileData as Record<string, unknown>))\n ) {\n const { filename, url } = fileSourceData\n if (filename && (filename.includes('../') || filename.includes('..\\\\'))) {\n throw new Forbidden(req.t)\n }\n\n if ((serverURL && url?.startsWith(serverURL)) || url?.startsWith('/')) {\n isLocalFile = true\n }\n\n try {\n if (!externalUploadSource && !disableLocalStorage && isLocalFile) {\n // File is stored locally\n const filePath = `${staticPath}/${filename}`\n const response = await getFileByPath(filePath)\n file = response\n overwriteExistingFiles = true\n } else if (filename && retainedOriginal && hasManagedCloudStorage) {\n const { retrieveFileResponse } = await import('./endpoints/getFile.js')\n const response = await retrieveFileResponse({\n collection: { config: collectionConfig },\n doc: originalDoc as TypeWithID,\n filename,\n operation: 'transform',\n req,\n })\n if (!response.ok) {\n throw new Error(`Unable to read retained original ${filename}`)\n }\n const buffer = Buffer.from(await response.arrayBuffer())\n file = {\n name: filename,\n data: buffer,\n mimetype: retainedOriginal.mimeType,\n size: buffer.length,\n }\n overwriteExistingFiles = true\n } else if (filename && url) {\n // File is remote\n file = await downloadFileToBuffer({\n data: fileSourceData,\n req,\n uploadConfig: collectionConfig.upload,\n })\n overwriteExistingFiles = !externalUploadSource\n }\n } catch (err: unknown) {\n throw new FileRetrievalError(req.t, err instanceof Error ? err.message : undefined)\n }\n\n if (file && retainedOriginal && currentFileData?.filename) {\n file = { ...file, name: currentFileData.filename }\n }\n }\n\n if (isDuplicating) {\n overwriteExistingFiles = false\n }\n\n if (!file) {\n if (throwOnMissingFile) {\n throw new MissingFile(req.t)\n }\n\n return {\n data: incomingFileData!,\n files: [],\n }\n }\n\n const detectedFileType = await checkFileRestrictions({\n collection: collectionConfig,\n file,\n req,\n })\n\n const shouldUseDetectedFileType =\n detectedFileType &&\n (isProcessableImage(file.mimetype) || isProcessableImage(detectedFileType.mime))\n\n if (shouldUseDetectedFileType && detectedFileType.mime !== file.mimetype) {\n file = { ...file, mimetype: detectedFileType.mime }\n }\n\n if (!disableLocalStorage) {\n await fs.mkdir(staticPath!, { recursive: true })\n }\n\n let newData = incomingFileData as T\n const filesToSave: FileToSave[] = []\n const fileData: Partial<FileData> = {}\n const crop = uploadEdits?.crop\n const isResettingCrop =\n retainedOriginal &&\n crop?.unit === '%' &&\n Number(crop.width) === 100 &&\n Number(crop.height) === 100 &&\n Number(crop.x) === 0 &&\n Number(crop.y) === 0 &&\n (uploadEdits.widthInPixels === undefined ||\n Number(uploadEdits.widthInPixels) === retainedOriginal.width) &&\n (uploadEdits.heightInPixels === undefined ||\n Number(uploadEdits.heightInPixels) === retainedOriginal.height)\n const hasFocalPointChange =\n uploadEdits?.focalPoint &&\n (Number(uploadEdits.focalPoint.x) !== (currentFileData?.focalX ?? 50) ||\n Number(uploadEdits.focalPoint.y) !== (currentFileData?.focalY ?? 50))\n const editsForTransformer = isResettingCrop\n ? { ...uploadEdits, crop: undefined, heightInPixels: undefined, widthInPixels: undefined }\n : uploadEdits\n\n try {\n const pipeline = await planTransformerPipeline({\n args: {\n collectionSlug: collectionConfig.slug,\n mimeType: file.mimetype,\n operation: 'upload',\n req,\n },\n capability: 'transformFile',\n transformers: req.payload.config.upload?.transformers ?? [],\n })\n\n // A large client upload can arrive as a bounded probe alongside a temp file. Transformers\n // need the whole file, so leave such an upload untouched rather than buffering it.\n const canRunTransformers = pipeline.length > 0 && hasFullFileContents(file)\n\n const bridgeTransformers = canRunTransformers\n ? pipeline.filter((transformer) =>\n Boolean(getUploadTransformerInternal(transformer)?.prepareUpload),\n )\n : []\n\n const bridgeTransformer =\n bridgeTransformers.find((transformer) =>\n getUploadTransformerInternal(transformer)!.handlesCollection?.({\n collectionSlug: collectionConfig.slug,\n }),\n ) ?? bridgeTransformers[0]\n\n // The chosen bridge's task options are private to it, so other bridges must not see them.\n const bridgeTaskPipeline = pipeline.filter(\n (transformer) =>\n transformer === bridgeTransformer || !bridgeTransformers.includes(transformer),\n )\n\n let originalWebFile: File | undefined\n let mainWebFile: File | undefined\n let hasDimensionsFromBridge = false\n let sizeResults: PreparedUploadTransformation[] = []\n\n if (canRunTransformers) {\n const fileContents = file.tempFilePath ? await openAsBlob(file.tempFilePath) : file.data\n originalWebFile = new File([fileContents], file.name, { type: file.mimetype })\n if (file.tempFilePath) {\n setUploadFilePath(originalWebFile, file.tempFilePath)\n }\n\n if (bridgeTransformer) {\n const bridge = getUploadTransformerInternal(bridgeTransformer)!\n\n const results = await bridge.prepareUpload!({\n collectionSlug: collectionConfig.slug,\n file: originalWebFile,\n req,\n transform: (task) =>\n transformUploadFile({\n collectionSlug: collectionConfig.slug,\n file: task.file ?? originalWebFile!,\n options: task.options,\n pipeline: bridgeTaskPipeline,\n req,\n }),\n uploadEdits: editsForTransformer,\n })\n\n const mainResult = results.find((result) => result.fieldPath === 'filename')\n\n mainWebFile = mainResult?.file ?? originalWebFile\n fileData.width = mainResult?.width\n fileData.height = mainResult?.height\n hasDimensionsFromBridge = true\n sizeResults = results.filter((result) => result.fieldPath !== 'filename')\n } else {\n mainWebFile = await transformUploadFile({\n collectionSlug: collectionConfig.slug,\n file: originalWebFile,\n options: undefined,\n pipeline,\n req,\n })\n }\n }\n\n // Saved for any resizable image, not just one a transformer processed, so it's kept with no\n // transformer registered and on a header-only client upload.\n if (\n focalPointEnabled &&\n uploadEdits?.focalPoint &&\n (hasDimensionsFromBridge || canResizeImage(file.mimetype))\n ) {\n fileData.focalX = isNumber(uploadEdits.focalPoint.x)\n ? Math.round(uploadEdits.focalPoint.x)\n : 50\n fileData.focalY = isNumber(uploadEdits.focalPoint.y)\n ? Math.round(uploadEdits.focalPoint.y)\n : 50\n }\n\n const fileWasTransformed = Boolean(mainWebFile && mainWebFile !== originalWebFile)\n const hasReusableOriginalMain = Boolean(\n isResettingCrop && !fileWasTransformed && retainedOriginal,\n )\n if (hasReusableOriginalMain && !hasFocalPointChange && retainedOriginal) {\n return {\n data: {\n ...incomingFileData,\n _objectKey: retainedOriginal._objectKey,\n filename: retainedOriginal.filename,\n filesize: retainedOriginal.filesize,\n height: retainedOriginal.height,\n mimeType: retainedOriginal.mimeType,\n original: retainedOriginal,\n prefix: retainedOriginal.prefix,\n url: retainedOriginal.url,\n variants: currentFileData?.variants,\n width: retainedOriginal.width,\n ...(draft ? { _status: 'draft' } : {}),\n } as T,\n files: [],\n }\n }\n const mainBuffer = fileWasTransformed\n ? Buffer.from(await mainWebFile!.arrayBuffer())\n : undefined\n\n // A transformed file is named after what the transformer returned, not the upload.\n const outputName = hasReusableOriginalMain\n ? retainedOriginal!.filename\n : (fileWasTransformed && mainWebFile!.name) || file.name\n\n let mimeType: string\n let ext: string | undefined\n\n if (mainBuffer) {\n // Detected bytes win for binary formats (Sharp keeps the input's name and type on a\n // converted output), but text-like output such as CSV has no signature to detect, so\n // fall back to the type and extension the transformer declared on the returned File.\n const typeResult = await fileTypeFromBuffer(mainBuffer)\n ext =\n typeResult?.ext ?? (getFileExtension(getSanitizedUploadFilename(outputName)) || undefined)\n mimeType = typeResult?.mime ?? (mainWebFile!.type || file.mimetype)\n } else {\n mimeType = file.mimetype\n ext = getFileExtension(getSanitizedUploadFilename(file.name))\n }\n\n // Adjust SVG mime type. fromBuffer modifies it.\n if (mimeType === 'application/xml' && ext === 'svg') {\n mimeType = 'image/svg+xml'\n }\n fileData.mimeType = mimeType\n fileData.filesize = mainBuffer ? mainBuffer.length : file.size\n\n // Only probe formats that could carry dimensions - probing reads the file, and a large\n // non-image upload may only exist as a temp file we deliberately never buffer.\n if (!hasDimensionsFromBridge && isProcessableImage(mimeType)) {\n try {\n const probed = await getImageSize({\n file: mainBuffer ? { ...file, data: mainBuffer, tempFilePath: undefined } : file,\n })\n fileData.width = probed.width\n fileData.height = probed.height\n } catch {\n // Not a recognized image format — leave width/height unset.\n }\n }\n\n let fsSafeName = getSanitizedUploadFilename(outputName, ext)\n const isDuplicatingAnOriginal =\n isDuplicating && file.name === (originalDoc as FileData | undefined)?.original?.filename\n\n // A provider reference without a receipt names an object the client already stored; renaming\n // it would point the document at a key that was never uploaded.\n const isUnverifiedProviderReference = Boolean(hasProviderDirectReference && !providerOriginal)\n\n if (\n !fileWasTransformed &&\n !retainedOriginal &&\n !providerOriginal &&\n !isDuplicatingAnOriginal &&\n !isUnverifiedProviderReference\n ) {\n fsSafeName = getOriginalFilename({ filename: fsSafeName })\n }\n\n if (hasReusableOriginalMain) {\n fsSafeName = retainedOriginal!.filename\n } else if (\n !overwriteExistingFiles ||\n !disableLocalStorage ||\n (shouldStageCloudFiles && retainedOriginal)\n ) {\n // Extract prefix if present (added by plugin-cloud-storage)\n const prefix = (data as Record<string, unknown>)?.prefix as string | undefined\n fsSafeName = await getSafeFileName({\n collectionSlug: collectionConfig.slug,\n desiredFilename: fsSafeName,\n prefix,\n req,\n staticPath: staticPath!,\n })\n }\n\n fileData.filename = fsSafeName\n if (hasReusableOriginalMain) {\n fileData.url = retainedOriginal!.url\n }\n\n const hasGeneratedProviderRepresentations = Boolean(\n providerOriginal &&\n (fileWasTransformed || sizeResults.some((result) => Boolean(result.file))),\n )\n const newObjectKey =\n hasManagedCloudStorage && (shouldStageCloudFiles || hasGeneratedProviderRepresentations)\n ? randomUUID()\n : undefined\n if (newObjectKey) {\n fileData._objectKey = newObjectKey\n }\n if (providerOriginal && !fileWasTransformed) {\n fileData._objectKey = providerOriginal._objectKey\n fileData.prefix = providerOriginal.prefix\n }\n if (hasReusableOriginalMain && retainedOriginal) {\n fileData._objectKey = retainedOriginal._objectKey\n fileData.prefix = retainedOriginal.prefix\n }\n\n if (!disableLocalStorage || shouldStageCloudFiles || providerOriginal) {\n const originalFilename =\n retainedOriginal?.filename ??\n providerOriginal?.filename ??\n (fileWasTransformed\n ? await getSafeFileName({\n collectionSlug: collectionConfig.slug,\n desiredFilename: getOriginalFilename({\n filename: getSanitizedUploadFilename(file.name),\n }),\n req,\n staticPath: staticPath!,\n })\n : fsSafeName)\n const original =\n retainedOriginal ??\n ({\n _objectKey: providerOriginal ? providerOriginal._objectKey : newObjectKey,\n filename: originalFilename,\n filesize: file.size,\n mimeType: file.mimetype,\n prefix: providerOriginal?.prefix ?? currentFileData?.prefix,\n url: formatAdminURL({\n apiRoute: req.payload.config.routes.api,\n path: `/${collectionConfig.slug}/file/${encodeURIComponent(originalFilename)}`,\n relative: true,\n serverURL: req.payload.config.serverURL,\n }),\n } as NonNullable<FileData['original']>)\n\n if (!retainedOriginal && isProcessableImage(file.mimetype)) {\n try {\n const dimensions = await getImageSize({ file })\n original.width = dimensions.width\n original.height = dimensions.height\n } catch {\n // Files with an image MIME type may not have readable dimensions.\n }\n }\n\n fileData.original = original\n\n if (providerOriginal) {\n if (!fileWasTransformed) {\n fileData.filename = originalFilename\n }\n }\n\n if (fileWasTransformed && !retainedOriginal && !providerOriginal) {\n filesToSave.push({\n buffer: Buffer.from(await originalWebFile!.arrayBuffer()),\n path: `${staticPath}/${originalFilename}`,\n })\n }\n }\n\n if (mainBuffer) {\n // The stored bytes are no longer the ones the client uploaded, so the client's upload\n // reference must not be reused for them.\n delete file.uploadReference\n\n filesToSave.push({\n buffer: mainBuffer,\n path: `${staticPath}/${fsSafeName}`,\n })\n\n if (file.tempFilePath) {\n await fs.writeFile(file.tempFilePath, mainBuffer)\n } else {\n req.file = {\n ...file,\n data: mainBuffer,\n size: mainBuffer.length,\n }\n }\n } else if (!hasReusableOriginalMain) {\n // file.data is empty when useTempFiles is on, so the real content lives at\n // file.tempFilePath instead (see the function doc for why we avoid buffering it).\n const tempFileHandling = resolveTempFileHandling({\n disableLocalStorage: Boolean(disableLocalStorage) && !shouldStageCloudFiles,\n hasProcessedBuffer: false,\n tempFilePath: file.tempFilePath,\n })\n\n if (tempFileHandling.type === 'copyFromTempFile') {\n filesToSave.push({\n path: `${staticPath}/${fsSafeName}`,\n sourcePath: tempFileHandling.sourcePath,\n })\n } else if (tempFileHandling.type === 'useBuffer') {\n const bufferToSave = file.tempFilePath ? await fs.readFile(file.tempFilePath) : file.data\n\n // A 'header'/'none' content requirement (see getFileContentRequirement.ts) means\n // file.data is only a partial probe, not the real content - never save it as-is.\n const fileDataIsPartialView = !file.tempFilePath && bufferToSave.length !== file.size\n\n if (!fileDataIsPartialView) {\n filesToSave.push({\n buffer: bufferToSave,\n path: `${staticPath}/${fsSafeName}`,\n })\n\n if (bufferToSave.length > 0) {\n if (file.tempFilePath) {\n await fs.writeFile(file.tempFilePath, bufferToSave)\n } else {\n // Keep req.file in sync, since downstream hooks/plugins may read it.\n req.file = {\n ...file,\n data: bufferToSave,\n size: bufferToSave.length,\n }\n }\n }\n }\n }\n }\n\n if (sizeResults.length > 0) {\n req.payloadUploadSizes = {}\n const sizes: FileSizes = {}\n const { name: baseName, ext: baseExt } = parseFilename(fsSafeName)\n const plannedNames = new Set([fileData.original?.filename, fsSafeName])\n const plannedSizeBuffers = new Map<string, Buffer>()\n\n for (const result of sizeResults) {\n const sizeName = result.fieldPath.slice('variants.'.length)\n\n if (!result.file) {\n sizes[sizeName] = {\n filename: null,\n filesize: null,\n height: null,\n mimeType: null,\n url: null,\n width: null,\n }\n continue\n }\n\n const sizeBuffer = Buffer.from(await result.file.arrayBuffer())\n const sizeTypeResult = await fileTypeFromBuffer(sizeBuffer)\n const sizeExt = sizeTypeResult?.ext || baseExt\n const sizeMimeType = sizeTypeResult?.mime || result.mimeType || fileData.mimeType\n\n req.payloadUploadSizes[sizeName] = sizeBuffer\n\n const imageSizeConfig = collectionConfig.upload.variants?.find(\n (imageSize) => imageSize.name === sizeName,\n )\n\n const imageNameWithDimensions = imageSizeConfig?.generateImageName\n ? imageSizeConfig.generateImageName({\n extension: sizeExt,\n height: result.height!,\n originalName: baseName,\n sizeName,\n width: result.width!,\n })\n : generateImageSizeFilename({\n extension: sizeExt,\n height: result.height!,\n outputImageName: baseName,\n width: result.width!,\n })\n\n let imageName = imageNameWithDimensions\n\n if (!disableLocalStorage || shouldStageCloudFiles) {\n const prefix = (data as Record<string, unknown>)?.prefix as string | undefined\n\n while (true) {\n imageName = await getSafeFileName({\n collectionSlug: collectionConfig.slug,\n desiredFilename: imageName,\n prefix,\n req,\n staticPath: disableLocalStorage ? undefined : staticPath!,\n })\n if (plannedSizeBuffers.get(imageName)?.equals(sizeBuffer)) {\n break\n }\n if (!plannedNames.has(imageName)) {\n break\n }\n imageName = incrementName(imageName)\n }\n plannedNames.add(imageName)\n }\n\n const imagePath = `${staticPath}/${imageName}`\n\n sizes[sizeName] = {\n _objectKey: newObjectKey,\n filename: imageName,\n filesize: sizeBuffer.length,\n height: result.height!,\n mimeType: sizeMimeType,\n prefix: providerOriginal?.prefix ?? currentFileData?.prefix,\n url: null,\n width: result.width!,\n }\n\n if (!plannedSizeBuffers.has(imageName)) {\n plannedSizeBuffers.set(imageName, sizeBuffer)\n filesToSave.push({\n buffer: sizeBuffer,\n path: imagePath,\n })\n }\n }\n\n fileData.variants = sizes\n }\n } catch (err) {\n req.payload.logger.error(err)\n throw new FileUploadError(req.t)\n }\n\n newData = {\n ...newData,\n ...fileData,\n ...(draft ? { _status: 'draft' } : {}),\n }\n\n return {\n data: newData,\n files: filesToSave,\n }\n}\n\n/**\n * Parse upload edits from req or incoming data\n */\nfunction parseUploadEditsFromReqOrIncomingData(args: {\n data: unknown\n isDuplicating?: boolean\n operation: 'create' | 'update'\n originalDoc: unknown\n req: PayloadRequest\n}): UploadEdits {\n const { data, isDuplicating, operation, originalDoc, req } = args\n\n // Get intended focal point change from query string or incoming data\n const uploadEdits =\n req.query?.uploadEdits && typeof req.query.uploadEdits === 'object'\n ? (req.query.uploadEdits as UploadEdits)\n : {}\n\n if (uploadEdits.focalPoint) {\n return uploadEdits\n }\n\n const incomingData = data as FileData\n const origDoc = originalDoc as FileData\n\n if (origDoc && 'focalX' in origDoc && 'focalY' in origDoc) {\n // Admin always resends the current focal point, so treat an unchanged value as no edit.\n if (incomingData?.focalX === origDoc.focalX && incomingData?.focalY === origDoc.focalY) {\n return undefined!\n }\n\n if (isDuplicating) {\n uploadEdits.focalPoint = {\n x: incomingData?.focalX || origDoc.focalX!,\n y: incomingData?.focalY || origDoc.focalY!,\n }\n return uploadEdits\n }\n }\n\n if (incomingData?.focalX && incomingData?.focalY) {\n uploadEdits.focalPoint = {\n x: incomingData.focalX,\n y: incomingData.focalY,\n }\n return uploadEdits\n }\n\n // If no focal point is set, default to center\n if (operation === 'create') {\n uploadEdits.focalPoint = {\n x: 50,\n y: 50,\n }\n }\n\n return uploadEdits\n}\n"],"names":["fileTypeFromBuffer","fs","randomUUID","openAsBlob","FileRetrievalError","FileUploadError","Forbidden","MissingFile","formatAdminURL","isNumber","canResizeImage","checkFileRestrictions","downloadFileToBuffer","getOriginalFilename","generateImageSizeFilename","getFileByPath","getFileExtension","getSanitizedUploadFilename","getImageSize","getSafeFileName","incrementName","hasCropOrResizeEdit","hasFullFileContents","isProcessableImage","parseFilename","planTransformerPipeline","transformUploadFile","getUploadTransformerInternal","setUploadFilePath","shouldReupload","uploadEdits","fileData","focalPoint","incomingFocalX","x","incomingFocalY","y","currentFocalX","focalX","currentFocalY","focalY","isEqual","resolveTempFileHandling","disableLocalStorage","hasProcessedBuffer","tempFilePath","type","sourcePath","generateFileData","collection","config","collectionConfig","data","draft","externalUploadSource","isDuplicating","operation","originalDoc","overwriteExistingFiles","req","throwOnMissingFile","upload","files","serverURL","payload","file","undefined","parseUploadEditsFromReqOrIncomingData","focalPointEnabled","staticDir","hasManagedCloudStorage","Boolean","fileOperations","uploadReference","hasProviderDirectReference","verifiedOriginal","context","_payloadVerifiedProviderOriginal","providerOriginal","signedReceipt","adapter","_objectKey","filename","key","prefix","shouldStageCloudFiles","staticPath","incomingFileData","currentFileData","retainedOriginal","original","url","fileSourceData","isLocalFile","includes","t","startsWith","filePath","response","retrieveFileResponse","doc","ok","Error","buffer","Buffer","from","arrayBuffer","name","mimetype","mimeType","size","length","uploadConfig","err","message","detectedFileType","shouldUseDetectedFileType","mime","mkdir","recursive","newData","filesToSave","crop","isResettingCrop","unit","Number","width","height","widthInPixels","heightInPixels","hasFocalPointChange","editsForTransformer","pipeline","args","collectionSlug","slug","capability","transformers","canRunTransformers","bridgeTransformers","filter","transformer","prepareUpload","bridgeTransformer","find","handlesCollection","bridgeTaskPipeline","originalWebFile","mainWebFile","hasDimensionsFromBridge","sizeResults","fileContents","File","bridge","results","transform","task","options","mainResult","result","fieldPath","Math","round","fileWasTransformed","hasReusableOriginalMain","filesize","variants","_status","mainBuffer","outputName","ext","typeResult","probed","fsSafeName","isDuplicatingAnOriginal","isUnverifiedProviderReference","desiredFilename","hasGeneratedProviderRepresentations","some","newObjectKey","originalFilename","apiRoute","routes","api","path","encodeURIComponent","relative","dimensions","push","writeFile","tempFileHandling","bufferToSave","readFile","fileDataIsPartialView","payloadUploadSizes","sizes","baseName","baseExt","plannedNames","Set","plannedSizeBuffers","Map","sizeName","slice","sizeBuffer","sizeTypeResult","sizeExt","sizeMimeType","imageSizeConfig","imageSize","imageNameWithDimensions","generateImageName","extension","originalName","outputImageName","imageName","get","equals","has","add","imagePath","set","logger","error","query","incomingData","origDoc"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/generateFileData.ts"],"sourcesContent":["import { fileTypeFromBuffer } from 'file-type'\nimport fs from 'fs/promises'\nimport { randomUUID } from 'node:crypto'\nimport { openAsBlob } from 'node:fs'\n\nimport type { Collection, TypeWithID } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { Document, PayloadRequest } from '../types/index.js'\nimport type { ExternalUploadSource } from './sanitizeUploadData.js'\nimport type { PreparedUploadTransformation } from './transformers/uploadTransformerBridge.js'\nimport type { FileData, FileSizes, FileToSave, UploadEdits } from './types.js'\n\nimport { FileRetrievalError, FileUploadError, Forbidden, MissingFile } from '../errors/index.js'\nimport { formatAdminURL } from '../utilities/formatAdminURL.js'\nimport { isNumber } from '../utilities/isNumber.js'\nimport { canResizeImage } from './canResizeImage.js'\nimport { checkFileRestrictions } from './checkFileRestrictions.js'\nimport { downloadFileToBuffer } from './downloadFileToBuffer.js'\nimport { getOriginalFilename } from './fileVersioning/naming.js'\nimport { generateImageSizeFilename } from './generateImageSizeFilename.js'\nimport { getFileByPath } from './getFileByPath.js'\nimport { getFileExtension, getSanitizedUploadFilename } from './getFileTypeIdentity.js'\nimport { getImageSize } from './getImageSize.js'\nimport { getSafeFileName, incrementName } from './getSafeFilename.js'\nimport { hasCropOrResizeEdit } from './hasCropOrResizeEdit.js'\nimport { hasFullFileContents } from './hasFullFileContents.js'\nimport { isProcessableImage } from './isProcessableImage.js'\nimport { parseFilename } from './parseFilename.js'\nimport { planTransformerPipeline } from './transformers/planTransformerPipeline.js'\nimport { transformUploadFile } from './transformers/transformUploadFile.js'\nimport {\n getUploadTransformerInternal,\n setUploadFilePath,\n} from './transformers/uploadTransformerBridge.js'\ntype Args<T> = {\n collection: Collection\n config: SanitizedConfig\n data: T\n draft?: boolean\n externalUploadSource?: ExternalUploadSource\n isDuplicating?: boolean\n operation: 'create' | 'update'\n originalDoc?: T\n overwriteExistingFiles?: boolean\n req: PayloadRequest\n throwOnMissingFile?: boolean\n}\n\ntype Result<T> = Promise<{\n data: T\n files: FileToSave[]\n}>\n\nconst shouldReupload = (\n uploadEdits: undefined | UploadEdits,\n fileData: Record<string, unknown> | undefined,\n) => {\n if (!fileData || !uploadEdits) {\n return false\n }\n\n if (hasCropOrResizeEdit(uploadEdits)) {\n return true\n }\n\n // Since uploadEdits always has focalPoint, compare to the value in the data if it was changed\n if (uploadEdits.focalPoint) {\n const incomingFocalX = uploadEdits.focalPoint.x\n const incomingFocalY = uploadEdits.focalPoint.y\n\n const currentFocalX = 'focalX' in fileData && fileData.focalX\n const currentFocalY = 'focalY' in fileData && fileData.focalY\n\n const isEqual = incomingFocalX === currentFocalX && incomingFocalY === currentFocalY\n return !isEqual\n }\n\n return false\n}\n\nexport type TempFileHandling =\n | { sourcePath: string; type: 'copyFromTempFile' }\n | { type: 'skip' }\n | { type: 'useBuffer' }\n\n/**\n * Decides how to get a file's bytes onto disk when no transformer rewrote it (a transformed\n * file is already an in-memory buffer, so it always takes the `useBuffer` path). Copies straight\n * from the temp file when possible, rather than reading a potentially large temp file into memory\n * just to write it back out - see the `generateFileData` function doc for why.\n */\nexport const resolveTempFileHandling = ({\n disableLocalStorage,\n hasProcessedBuffer,\n tempFilePath,\n}: {\n disableLocalStorage: boolean\n hasProcessedBuffer: boolean\n tempFilePath: string | undefined\n}): TempFileHandling => {\n if (hasProcessedBuffer || !tempFilePath) {\n return { type: 'useBuffer' }\n }\n\n return disableLocalStorage\n ? { type: 'skip' }\n : { type: 'copyFromTempFile', sourcePath: tempFilePath }\n}\n\n/**\n * Builds the document's file metadata and the list of files to write to disk.\n *\n * A large client upload may arrive as a temp file instead of an in-memory buffer (see\n * getFileFromUploadInstructions.ts), and `file.data` can hold only a partial probe rather than\n * the full file. To avoid loading such files into memory unnecessarily, no transformer runs\n * unless the full bytes are available, this skips reading a temp file entirely when local\n * storage is disabled, and copies it straight to its destination when local storage is enabled.\n */\nexport const generateFileData = async <T>({\n collection: { config: collectionConfig },\n data,\n draft,\n externalUploadSource,\n isDuplicating,\n operation,\n originalDoc,\n overwriteExistingFiles,\n req,\n throwOnMissingFile,\n}: Args<T>): Result<T> => {\n if (!collectionConfig.upload) {\n return {\n data,\n files: [],\n }\n }\n\n const { serverURL } = req.payload.config\n\n let file = isDuplicating ? undefined : req.file\n\n const uploadEdits = parseUploadEditsFromReqOrIncomingData({\n data,\n isDuplicating,\n operation,\n // Only a duplication source informs edit parsing. Updates now also pass `originalDoc` so the\n // stored file can be reprocessed, and that must not change which edits are applied.\n originalDoc: isDuplicating ? originalDoc : undefined,\n req,\n })\n\n const {\n disableLocalStorage,\n focalPoint: focalPointEnabled = true,\n staticDir,\n } = collectionConfig.upload\n const hasManagedCloudStorage = Boolean(collectionConfig.upload.fileOperations)\n const uploadReference = file?.uploadReference\n const hasProviderDirectReference =\n uploadReference && typeof uploadReference === 'object' && !('uploadId' in uploadReference)\n const verifiedOriginal = req.context?._payloadVerifiedProviderOriginal as\n | {\n _objectKey?: string\n filename: string\n key: string\n prefix?: string\n signedReceipt: string\n }\n | undefined\n const providerOriginal =\n hasProviderDirectReference &&\n 'signedReceipt' in uploadReference &&\n uploadReference.signedReceipt === verifiedOriginal?.signedReceipt &&\n verifiedOriginal &&\n typeof collectionConfig.upload.adapter === 'string'\n ? {\n _objectKey: verifiedOriginal._objectKey,\n filename: verifiedOriginal.filename,\n key: verifiedOriginal.key,\n prefix: verifiedOriginal.prefix,\n }\n : undefined\n const shouldStageCloudFiles = hasManagedCloudStorage && !hasProviderDirectReference\n\n const staticPath = staticDir\n\n const incomingFileData: Document = isDuplicating ? originalDoc : data\n const currentFileData = (operation === 'update' ? originalDoc : incomingFileData) as\n | FileData\n | undefined\n const retainedOriginal =\n operation === 'update' &&\n !file &&\n !externalUploadSource &&\n typeof currentFileData?.original?.filename === 'string' &&\n typeof currentFileData.original.url === 'string'\n ? currentFileData.original\n : undefined\n const fileSourceData = externalUploadSource ?? retainedOriginal ?? currentFileData\n let isLocalFile = false\n\n if (\n !file &&\n fileSourceData &&\n (externalUploadSource ||\n isDuplicating ||\n shouldReupload(uploadEdits, incomingFileData as Record<string, unknown>))\n ) {\n const { filename, url } = fileSourceData\n if (filename && (filename.includes('../') || filename.includes('..\\\\'))) {\n throw new Forbidden(req.t)\n }\n\n if ((serverURL && url?.startsWith(serverURL)) || url?.startsWith('/')) {\n isLocalFile = true\n }\n\n try {\n if (!externalUploadSource && !disableLocalStorage && isLocalFile) {\n // File is stored locally\n const filePath = `${staticPath}/${filename}`\n const response = await getFileByPath(filePath)\n file = response\n overwriteExistingFiles = true\n } else if (filename && retainedOriginal && hasManagedCloudStorage) {\n const { retrieveFileResponse } = await import('./endpoints/getFile.js')\n const response = await retrieveFileResponse({\n collection: { config: collectionConfig },\n doc: originalDoc as TypeWithID,\n filename,\n operation: 'transform',\n req,\n })\n if (!response.ok) {\n throw new Error(`Unable to read retained original ${filename}`)\n }\n const buffer = Buffer.from(await response.arrayBuffer())\n file = {\n name: filename,\n data: buffer,\n mimetype: retainedOriginal.mimeType,\n size: buffer.length,\n }\n overwriteExistingFiles = true\n } else if (filename && url) {\n // File is remote\n file = await downloadFileToBuffer({\n data: fileSourceData,\n req,\n uploadConfig: collectionConfig.upload,\n })\n overwriteExistingFiles = !externalUploadSource\n }\n } catch (err: unknown) {\n throw new FileRetrievalError(req.t, err instanceof Error ? err.message : undefined)\n }\n\n if (file && retainedOriginal && currentFileData?.filename) {\n file = { ...file, name: currentFileData.filename }\n }\n }\n\n if (isDuplicating) {\n overwriteExistingFiles = false\n }\n\n if (!file) {\n if (throwOnMissingFile) {\n throw new MissingFile(req.t)\n }\n\n return {\n data: incomingFileData!,\n files: [],\n }\n }\n\n const detectedFileType = await checkFileRestrictions({\n collection: collectionConfig,\n file,\n req,\n })\n\n const shouldUseDetectedFileType =\n detectedFileType &&\n (isProcessableImage(file.mimetype) || isProcessableImage(detectedFileType.mime))\n\n if (shouldUseDetectedFileType && detectedFileType.mime !== file.mimetype) {\n file = { ...file, mimetype: detectedFileType.mime }\n }\n\n if (!disableLocalStorage) {\n await fs.mkdir(staticPath!, { recursive: true })\n }\n\n let newData = incomingFileData as T\n const filesToSave: FileToSave[] = []\n const fileData: Partial<FileData> = {}\n const crop = uploadEdits?.crop\n const isResettingCrop =\n retainedOriginal &&\n crop?.unit === '%' &&\n Number(crop.width) === 100 &&\n Number(crop.height) === 100 &&\n Number(crop.x) === 0 &&\n Number(crop.y) === 0 &&\n (uploadEdits.widthInPixels === undefined ||\n Number(uploadEdits.widthInPixels) === retainedOriginal.width) &&\n (uploadEdits.heightInPixels === undefined ||\n Number(uploadEdits.heightInPixels) === retainedOriginal.height)\n const hasFocalPointChange =\n uploadEdits?.focalPoint &&\n (Number(uploadEdits.focalPoint.x) !== (currentFileData?.focalX ?? 50) ||\n Number(uploadEdits.focalPoint.y) !== (currentFileData?.focalY ?? 50))\n const editsForTransformer = isResettingCrop\n ? { ...uploadEdits, crop: undefined, heightInPixels: undefined, widthInPixels: undefined }\n : uploadEdits\n\n try {\n const pipeline = await planTransformerPipeline({\n args: {\n collectionSlug: collectionConfig.slug,\n mimeType: file.mimetype,\n operation: 'upload',\n req,\n },\n capability: 'transformFile',\n transformers: req.payload.config.upload?.transformers ?? [],\n })\n\n // A large client upload can arrive as a bounded probe alongside a temp file. Transformers\n // need the whole file, so leave such an upload untouched rather than buffering it.\n const canRunTransformers = pipeline.length > 0 && hasFullFileContents(file)\n\n const bridgeTransformers = canRunTransformers\n ? pipeline.filter((transformer) =>\n Boolean(getUploadTransformerInternal(transformer)?.prepareUpload),\n )\n : []\n\n const bridgeTransformer =\n bridgeTransformers.find((transformer) =>\n getUploadTransformerInternal(transformer)!.handlesCollection?.({\n collectionSlug: collectionConfig.slug,\n }),\n ) ?? bridgeTransformers[0]\n\n // The chosen bridge's task options are private to it, so other bridges must not see them.\n const bridgeTaskPipeline = pipeline.filter(\n (transformer) =>\n transformer === bridgeTransformer || !bridgeTransformers.includes(transformer),\n )\n\n let originalWebFile: File | undefined\n let mainWebFile: File | undefined\n let hasDimensionsFromBridge = false\n let sizeResults: PreparedUploadTransformation[] = []\n\n if (canRunTransformers) {\n const fileContents = file.tempFilePath ? await openAsBlob(file.tempFilePath) : file.data\n originalWebFile = new File([fileContents], file.name, { type: file.mimetype })\n if (file.tempFilePath) {\n setUploadFilePath(originalWebFile, file.tempFilePath)\n }\n\n if (bridgeTransformer) {\n const bridge = getUploadTransformerInternal(bridgeTransformer)!\n\n const results = await bridge.prepareUpload!({\n collectionSlug: collectionConfig.slug,\n file: originalWebFile,\n req,\n transform: (task) =>\n transformUploadFile({\n collectionSlug: collectionConfig.slug,\n file: task.file ?? originalWebFile!,\n options: task.options,\n pipeline: bridgeTaskPipeline,\n req,\n }),\n uploadEdits: editsForTransformer,\n })\n\n const mainResult = results.find((result) => result.fieldPath === 'filename')\n\n mainWebFile = mainResult?.file ?? originalWebFile\n fileData.width = mainResult?.width\n fileData.height = mainResult?.height\n hasDimensionsFromBridge = true\n sizeResults = results.filter((result) => result.fieldPath !== 'filename')\n } else {\n mainWebFile = await transformUploadFile({\n collectionSlug: collectionConfig.slug,\n file: originalWebFile,\n options: undefined,\n pipeline,\n req,\n })\n }\n }\n\n // Saved for any resizable image, not just one a transformer processed, so it's kept with no\n // transformer registered and on a header-only client upload.\n if (\n focalPointEnabled &&\n uploadEdits?.focalPoint &&\n (hasDimensionsFromBridge || canResizeImage(file.mimetype))\n ) {\n fileData.focalX = isNumber(uploadEdits.focalPoint.x)\n ? Math.round(uploadEdits.focalPoint.x)\n : 50\n fileData.focalY = isNumber(uploadEdits.focalPoint.y)\n ? Math.round(uploadEdits.focalPoint.y)\n : 50\n }\n\n const fileWasTransformed = Boolean(mainWebFile && mainWebFile !== originalWebFile)\n const hasReusableOriginalMain = Boolean(\n isResettingCrop && !fileWasTransformed && retainedOriginal,\n )\n if (hasReusableOriginalMain && !hasFocalPointChange && retainedOriginal) {\n return {\n data: {\n ...incomingFileData,\n _objectKey: retainedOriginal._objectKey,\n filename: retainedOriginal.filename,\n filesize: retainedOriginal.filesize,\n height: retainedOriginal.height,\n mimeType: retainedOriginal.mimeType,\n original: retainedOriginal,\n prefix: retainedOriginal.prefix,\n url: retainedOriginal.url,\n variants: currentFileData?.variants,\n width: retainedOriginal.width,\n ...(draft ? { _status: 'draft' } : {}),\n } as T,\n files: [],\n }\n }\n const mainBuffer = fileWasTransformed\n ? Buffer.from(await mainWebFile!.arrayBuffer())\n : undefined\n\n // A transformed file is named after what the transformer returned, not the upload.\n const outputName = hasReusableOriginalMain\n ? retainedOriginal!.filename\n : (fileWasTransformed && mainWebFile!.name) || file.name\n\n let mimeType: string\n let ext: string | undefined\n\n if (mainBuffer) {\n // Detected bytes win for binary formats (Sharp keeps the input's name and type on a\n // converted output), but text-like output such as CSV has no signature to detect, so\n // fall back to the type and extension the transformer declared on the returned File.\n const typeResult = await fileTypeFromBuffer(mainBuffer)\n ext =\n typeResult?.ext ?? (getFileExtension(getSanitizedUploadFilename(outputName)) || undefined)\n mimeType = typeResult?.mime ?? (mainWebFile!.type || file.mimetype)\n } else {\n mimeType = file.mimetype\n ext = getFileExtension(getSanitizedUploadFilename(file.name))\n }\n\n // Adjust SVG mime type. fromBuffer modifies it.\n if (mimeType === 'application/xml' && ext === 'svg') {\n mimeType = 'image/svg+xml'\n }\n fileData.mimeType = mimeType\n fileData.filesize = mainBuffer ? mainBuffer.length : file.size\n\n // Only probe formats that could carry dimensions - probing reads the file, and a large\n // non-image upload may only exist as a temp file we deliberately never buffer.\n if (!hasDimensionsFromBridge && isProcessableImage(mimeType)) {\n try {\n const probed = await getImageSize({\n file: mainBuffer ? { ...file, data: mainBuffer, tempFilePath: undefined } : file,\n })\n fileData.width = probed.width\n fileData.height = probed.height\n } catch {\n // Not a recognized image format — leave width/height unset.\n }\n }\n\n let fsSafeName = getSanitizedUploadFilename(outputName, ext)\n const isDuplicatingAnOriginal =\n isDuplicating && file.name === (originalDoc as FileData | undefined)?.original?.filename\n\n // A provider reference without a receipt names an object the client already stored; renaming\n // it would point the document at a key that was never uploaded.\n const isUnverifiedProviderReference = Boolean(hasProviderDirectReference && !providerOriginal)\n\n if (\n !fileWasTransformed &&\n !retainedOriginal &&\n !providerOriginal &&\n !isDuplicatingAnOriginal &&\n !isUnverifiedProviderReference\n ) {\n fsSafeName = getOriginalFilename({ filename: fsSafeName })\n }\n\n if (hasReusableOriginalMain) {\n fsSafeName = retainedOriginal!.filename\n } else if (\n !overwriteExistingFiles ||\n !disableLocalStorage ||\n (shouldStageCloudFiles && retainedOriginal)\n ) {\n // Extract prefix if present (added by plugin-cloud-storage)\n const prefix = (data as Record<string, unknown>)?.prefix as string | undefined\n fsSafeName = await getSafeFileName({\n collectionSlug: collectionConfig.slug,\n desiredFilename: fsSafeName,\n prefix,\n req,\n staticPath: staticPath!,\n })\n }\n\n fileData.filename = fsSafeName\n if (hasReusableOriginalMain) {\n fileData.url = retainedOriginal!.url\n }\n\n const hasGeneratedProviderRepresentations = Boolean(\n providerOriginal &&\n (fileWasTransformed || sizeResults.some((result) => Boolean(result.file))),\n )\n const newObjectKey =\n hasManagedCloudStorage && (shouldStageCloudFiles || hasGeneratedProviderRepresentations)\n ? randomUUID()\n : undefined\n if (newObjectKey) {\n fileData._objectKey = newObjectKey\n }\n if (providerOriginal && !fileWasTransformed) {\n fileData._objectKey = providerOriginal._objectKey\n fileData.prefix = providerOriginal.prefix\n }\n if (hasReusableOriginalMain && retainedOriginal) {\n fileData._objectKey = retainedOriginal._objectKey\n fileData.prefix = retainedOriginal.prefix\n }\n\n if (!disableLocalStorage || shouldStageCloudFiles || providerOriginal) {\n const originalFilename =\n retainedOriginal?.filename ??\n providerOriginal?.filename ??\n (fileWasTransformed\n ? await getSafeFileName({\n collectionSlug: collectionConfig.slug,\n desiredFilename: getOriginalFilename({\n filename: getSanitizedUploadFilename(file.name),\n }),\n req,\n staticPath: staticPath!,\n })\n : fsSafeName)\n const original = retainedOriginal ?? {\n _objectKey: providerOriginal ? providerOriginal._objectKey : newObjectKey,\n filename: originalFilename,\n filesize: file.size,\n mimeType: file.mimetype,\n prefix: providerOriginal?.prefix ?? currentFileData?.prefix,\n url: formatAdminURL({\n apiRoute: req.payload.config.routes.api,\n path: `/${collectionConfig.slug}/file/${encodeURIComponent(originalFilename)}`,\n relative: true,\n serverURL: req.payload.config.serverURL,\n }),\n }\n\n if (!retainedOriginal && isProcessableImage(file.mimetype)) {\n try {\n const dimensions = await getImageSize({ file })\n original.width = dimensions.width\n original.height = dimensions.height\n } catch {\n // Files with an image MIME type may not have readable dimensions.\n }\n }\n\n fileData.original = original\n\n if (providerOriginal) {\n if (!fileWasTransformed) {\n fileData.filename = originalFilename\n }\n }\n\n if (fileWasTransformed && !retainedOriginal && !providerOriginal) {\n filesToSave.push({\n buffer: Buffer.from(await originalWebFile!.arrayBuffer()),\n path: `${staticPath}/${originalFilename}`,\n })\n }\n }\n\n if (mainBuffer) {\n // The stored bytes are no longer the ones the client uploaded, so the client's upload\n // reference must not be reused for them.\n delete file.uploadReference\n\n filesToSave.push({\n buffer: mainBuffer,\n path: `${staticPath}/${fsSafeName}`,\n })\n\n if (file.tempFilePath) {\n await fs.writeFile(file.tempFilePath, mainBuffer)\n } else {\n req.file = {\n ...file,\n data: mainBuffer,\n size: mainBuffer.length,\n }\n }\n } else if (!hasReusableOriginalMain) {\n // file.data is empty when useTempFiles is on, so the real content lives at\n // file.tempFilePath instead (see the function doc for why we avoid buffering it).\n const tempFileHandling = resolveTempFileHandling({\n disableLocalStorage: Boolean(disableLocalStorage) && !shouldStageCloudFiles,\n hasProcessedBuffer: false,\n tempFilePath: file.tempFilePath,\n })\n\n if (tempFileHandling.type === 'copyFromTempFile') {\n filesToSave.push({\n path: `${staticPath}/${fsSafeName}`,\n sourcePath: tempFileHandling.sourcePath,\n })\n } else if (tempFileHandling.type === 'useBuffer') {\n const bufferToSave = file.tempFilePath ? await fs.readFile(file.tempFilePath) : file.data\n\n // A 'header'/'none' content requirement (see getFileContentRequirement.ts) means\n // file.data is only a partial probe, not the real content - never save it as-is.\n const fileDataIsPartialView = !file.tempFilePath && bufferToSave.length !== file.size\n\n if (!fileDataIsPartialView) {\n filesToSave.push({\n buffer: bufferToSave,\n path: `${staticPath}/${fsSafeName}`,\n })\n\n if (bufferToSave.length > 0) {\n if (file.tempFilePath) {\n await fs.writeFile(file.tempFilePath, bufferToSave)\n } else {\n // Keep req.file in sync, since downstream hooks/plugins may read it.\n req.file = {\n ...file,\n data: bufferToSave,\n size: bufferToSave.length,\n }\n }\n }\n }\n }\n }\n\n if (sizeResults.length > 0) {\n req.payloadUploadSizes = {}\n const sizes: FileSizes = {}\n const { name: baseName, ext: baseExt } = parseFilename(fsSafeName)\n const plannedNames = new Set([fileData.original?.filename, fsSafeName])\n const plannedSizeBuffers = new Map<string, Buffer>()\n\n for (const result of sizeResults) {\n const sizeName = result.fieldPath.slice('variants.'.length)\n\n if (!result.file) {\n sizes[sizeName] = {\n filename: null,\n filesize: null,\n height: null,\n mimeType: null,\n url: null,\n width: null,\n }\n continue\n }\n\n const sizeBuffer = Buffer.from(await result.file.arrayBuffer())\n const sizeTypeResult = await fileTypeFromBuffer(sizeBuffer)\n const sizeExt = sizeTypeResult?.ext || baseExt\n const sizeMimeType = sizeTypeResult?.mime || result.mimeType || fileData.mimeType\n\n req.payloadUploadSizes[sizeName] = sizeBuffer\n\n const imageSizeConfig = collectionConfig.upload.variants?.find(\n (imageSize) => imageSize.name === sizeName,\n )\n\n const imageNameWithDimensions = imageSizeConfig?.generateImageName\n ? imageSizeConfig.generateImageName({\n extension: sizeExt,\n height: result.height!,\n originalName: baseName,\n sizeName,\n width: result.width!,\n })\n : generateImageSizeFilename({\n extension: sizeExt,\n height: result.height!,\n outputImageName: baseName,\n width: result.width!,\n })\n\n let imageName = imageNameWithDimensions\n\n if (!disableLocalStorage || shouldStageCloudFiles) {\n const prefix = (data as Record<string, unknown>)?.prefix as string | undefined\n\n while (true) {\n imageName = await getSafeFileName({\n collectionSlug: collectionConfig.slug,\n desiredFilename: imageName,\n prefix,\n req,\n staticPath: disableLocalStorage ? undefined : staticPath!,\n })\n if (plannedSizeBuffers.get(imageName)?.equals(sizeBuffer)) {\n break\n }\n if (!plannedNames.has(imageName)) {\n break\n }\n imageName = incrementName(imageName)\n }\n plannedNames.add(imageName)\n }\n\n const imagePath = `${staticPath}/${imageName}`\n\n sizes[sizeName] = {\n _objectKey: newObjectKey,\n filename: imageName,\n filesize: sizeBuffer.length,\n height: result.height!,\n mimeType: sizeMimeType,\n prefix: providerOriginal?.prefix ?? currentFileData?.prefix,\n url: null,\n width: result.width!,\n }\n\n if (!plannedSizeBuffers.has(imageName)) {\n plannedSizeBuffers.set(imageName, sizeBuffer)\n filesToSave.push({\n buffer: sizeBuffer,\n path: imagePath,\n })\n }\n }\n\n fileData.variants = sizes\n }\n } catch (err) {\n req.payload.logger.error(err)\n throw new FileUploadError(req.t)\n }\n\n newData = {\n ...newData,\n ...fileData,\n ...(draft ? { _status: 'draft' } : {}),\n }\n\n return {\n data: newData,\n files: filesToSave,\n }\n}\n\n/**\n * Parse upload edits from req or incoming data\n */\nfunction parseUploadEditsFromReqOrIncomingData(args: {\n data: unknown\n isDuplicating?: boolean\n operation: 'create' | 'update'\n originalDoc: unknown\n req: PayloadRequest\n}): UploadEdits {\n const { data, isDuplicating, operation, originalDoc, req } = args\n\n // Get intended focal point change from query string or incoming data\n const uploadEdits =\n req.query?.uploadEdits && typeof req.query.uploadEdits === 'object'\n ? (req.query.uploadEdits as UploadEdits)\n : {}\n\n if (uploadEdits.focalPoint) {\n return uploadEdits\n }\n\n const incomingData = data as FileData\n const origDoc = originalDoc as FileData\n\n if (origDoc && 'focalX' in origDoc && 'focalY' in origDoc) {\n // Admin always resends the current focal point, so treat an unchanged value as no edit.\n if (incomingData?.focalX === origDoc.focalX && incomingData?.focalY === origDoc.focalY) {\n return undefined!\n }\n\n if (isDuplicating) {\n uploadEdits.focalPoint = {\n x: incomingData?.focalX || origDoc.focalX!,\n y: incomingData?.focalY || origDoc.focalY!,\n }\n return uploadEdits\n }\n }\n\n if (incomingData?.focalX && incomingData?.focalY) {\n uploadEdits.focalPoint = {\n x: incomingData.focalX,\n y: incomingData.focalY,\n }\n return uploadEdits\n }\n\n // If no focal point is set, default to center\n if (operation === 'create') {\n uploadEdits.focalPoint = {\n x: 50,\n y: 50,\n }\n }\n\n return uploadEdits\n}\n"],"names":["fileTypeFromBuffer","fs","randomUUID","openAsBlob","FileRetrievalError","FileUploadError","Forbidden","MissingFile","formatAdminURL","isNumber","canResizeImage","checkFileRestrictions","downloadFileToBuffer","getOriginalFilename","generateImageSizeFilename","getFileByPath","getFileExtension","getSanitizedUploadFilename","getImageSize","getSafeFileName","incrementName","hasCropOrResizeEdit","hasFullFileContents","isProcessableImage","parseFilename","planTransformerPipeline","transformUploadFile","getUploadTransformerInternal","setUploadFilePath","shouldReupload","uploadEdits","fileData","focalPoint","incomingFocalX","x","incomingFocalY","y","currentFocalX","focalX","currentFocalY","focalY","isEqual","resolveTempFileHandling","disableLocalStorage","hasProcessedBuffer","tempFilePath","type","sourcePath","generateFileData","collection","config","collectionConfig","data","draft","externalUploadSource","isDuplicating","operation","originalDoc","overwriteExistingFiles","req","throwOnMissingFile","upload","files","serverURL","payload","file","undefined","parseUploadEditsFromReqOrIncomingData","focalPointEnabled","staticDir","hasManagedCloudStorage","Boolean","fileOperations","uploadReference","hasProviderDirectReference","verifiedOriginal","context","_payloadVerifiedProviderOriginal","providerOriginal","signedReceipt","adapter","_objectKey","filename","key","prefix","shouldStageCloudFiles","staticPath","incomingFileData","currentFileData","retainedOriginal","original","url","fileSourceData","isLocalFile","includes","t","startsWith","filePath","response","retrieveFileResponse","doc","ok","Error","buffer","Buffer","from","arrayBuffer","name","mimetype","mimeType","size","length","uploadConfig","err","message","detectedFileType","shouldUseDetectedFileType","mime","mkdir","recursive","newData","filesToSave","crop","isResettingCrop","unit","Number","width","height","widthInPixels","heightInPixels","hasFocalPointChange","editsForTransformer","pipeline","args","collectionSlug","slug","capability","transformers","canRunTransformers","bridgeTransformers","filter","transformer","prepareUpload","bridgeTransformer","find","handlesCollection","bridgeTaskPipeline","originalWebFile","mainWebFile","hasDimensionsFromBridge","sizeResults","fileContents","File","bridge","results","transform","task","options","mainResult","result","fieldPath","Math","round","fileWasTransformed","hasReusableOriginalMain","filesize","variants","_status","mainBuffer","outputName","ext","typeResult","probed","fsSafeName","isDuplicatingAnOriginal","isUnverifiedProviderReference","desiredFilename","hasGeneratedProviderRepresentations","some","newObjectKey","originalFilename","apiRoute","routes","api","path","encodeURIComponent","relative","dimensions","push","writeFile","tempFileHandling","bufferToSave","readFile","fileDataIsPartialView","payloadUploadSizes","sizes","baseName","baseExt","plannedNames","Set","plannedSizeBuffers","Map","sizeName","slice","sizeBuffer","sizeTypeResult","sizeExt","sizeMimeType","imageSizeConfig","imageSize","imageNameWithDimensions","generateImageName","extension","originalName","outputImageName","imageName","get","equals","has","add","imagePath","set","logger","error","query","incomingData","origDoc"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/uploads/getFileContentRequirement.ts"],"sourcesContent":["import type { SanitizedUploadConfig } from './types.js'\n\nimport { canResizeImage } from './canResizeImage.js'\nimport { isAnimatedImage } from './isAnimatedImage.js'\nimport { isImage } from './isImage.js'\n\n/**\n * Bytes read from the start of a file to sniff its mime type and, for images, probe its\n * dimensions. Generous enough to cover real-world header/metadata layouts (EXIF, ICC\n * profiles, etc.) while staying tiny next to a multi-gigabyte upload.\n */\nexport const HEADER_PROBE_BYTE_LENGTH = 1024 * 1024\n\nexport type FileContentRequirement = 'full' | 'header' | 'none'\n\n/**\n * Decides how much of an uploaded file's content, if any, is needed to save the document -\n * so a client upload (e.g. Azure's chunkLargeFiles) only pays for what post-processing\n * actually reads instead of always being re-downloaded in full.\n *\n * - `full`: local storage needs the real bytes, or a registered file transformer will adjust\n * the image (`upload.hasImageAdjustments`), or a custom `transformFile` transformer will\n * process the file (`hasTransformFileStages`), or the file is animated, or additional image\n * sizes will be generated from it, or the collection restricts mime types (which also runs\n * SVG/PDF content-safety checks that must see the whole file), or the request itself carries\n * a crop/resize edit (`uploadEdits`) that will be applied to the fetched bytes.\n * - `header`: the file is an image and only its dimensions are needed.\n * - `none`: nothing downstream reads file content at all.\n */\nexport function getFileContentRequirement({\n hasSizeEdits,\n hasTransformFileStages,\n mimeType,\n uploadConfig,\n}: {\n /**\n * Whether the request's `uploadEdits` (crop, heightInPixels, widthInPixels) will resize the\n * fetched file - if so, the full file is needed even when the collection config alone would\n * only require a header probe.\n */\n hasSizeEdits?: boolean\n /**\n * Whether a registered transformer without its own content projection (anything other than a\n * built-in bridge transformer like `sharpTransformer`) will run `transformFile` on this file.\n * Such a transformer reads the whole file, so neither a header probe nor no content is enough.\n */\n hasTransformFileStages?: boolean\n mimeType: string\n uploadConfig: SanitizedUploadConfig\n}): FileContentRequirement {\n if (!uploadConfig.disableLocalStorage) {\n return 'full'\n }\n\n const hasMimeTypeAllowList =\n Array.isArray(uploadConfig.mimeTypes) && uploadConfig.mimeTypes.length > 0\n\n if (hasMimeTypeAllowList || hasTransformFileStages) {\n return 'full'\n }\n\n const isResizableImage = canResizeImage(mimeType)\n // `hasImageAdjustments` and `variants` are the transformer-agnostic projection a file\n // transformer writes back onto the sanitized upload config at startup (see\n // `@payloadcms/transformer-sharp`'s `initSharpCollections`), so core can make this decision\n // without knowing which transformer is registered or how it is configured.\n const hasConfiguredAdjustments = Boolean(\n uploadConfig.hasImageAdjustments ||\n
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/getFileContentRequirement.ts"],"sourcesContent":["import type { SanitizedUploadConfig } from './types.js'\n\nimport { canResizeImage } from './canResizeImage.js'\nimport { isAnimatedImage } from './isAnimatedImage.js'\nimport { isImage } from './isImage.js'\n\n/**\n * Bytes read from the start of a file to sniff its mime type and, for images, probe its\n * dimensions. Generous enough to cover real-world header/metadata layouts (EXIF, ICC\n * profiles, etc.) while staying tiny next to a multi-gigabyte upload.\n */\nexport const HEADER_PROBE_BYTE_LENGTH = 1024 * 1024\n\nexport type FileContentRequirement = 'full' | 'header' | 'none'\n\n/**\n * Decides how much of an uploaded file's content, if any, is needed to save the document -\n * so a client upload (e.g. Azure's chunkLargeFiles) only pays for what post-processing\n * actually reads instead of always being re-downloaded in full.\n *\n * - `full`: local storage needs the real bytes, or a registered file transformer will adjust\n * the image (`upload.hasImageAdjustments`), or a custom `transformFile` transformer will\n * process the file (`hasTransformFileStages`), or the file is animated, or additional image\n * sizes will be generated from it, or the collection restricts mime types (which also runs\n * SVG/PDF content-safety checks that must see the whole file), or the request itself carries\n * a crop/resize edit (`uploadEdits`) that will be applied to the fetched bytes.\n * - `header`: the file is an image and only its dimensions are needed.\n * - `none`: nothing downstream reads file content at all.\n */\nexport function getFileContentRequirement({\n hasSizeEdits,\n hasTransformFileStages,\n mimeType,\n uploadConfig,\n}: {\n /**\n * Whether the request's `uploadEdits` (crop, heightInPixels, widthInPixels) will resize the\n * fetched file - if so, the full file is needed even when the collection config alone would\n * only require a header probe.\n */\n hasSizeEdits?: boolean\n /**\n * Whether a registered transformer without its own content projection (anything other than a\n * built-in bridge transformer like `sharpTransformer`) will run `transformFile` on this file.\n * Such a transformer reads the whole file, so neither a header probe nor no content is enough.\n */\n hasTransformFileStages?: boolean\n mimeType: string\n uploadConfig: SanitizedUploadConfig\n}): FileContentRequirement {\n if (!uploadConfig.disableLocalStorage) {\n return 'full'\n }\n\n const hasMimeTypeAllowList =\n Array.isArray(uploadConfig.mimeTypes) && uploadConfig.mimeTypes.length > 0\n\n if (hasMimeTypeAllowList || hasTransformFileStages) {\n return 'full'\n }\n\n const isResizableImage = canResizeImage(mimeType)\n // `hasImageAdjustments` and `variants` are the transformer-agnostic projection a file\n // transformer writes back onto the sanitized upload config at startup (see\n // `@payloadcms/transformer-sharp`'s `initSharpCollections`), so core can make this decision\n // without knowing which transformer is registered or how it is configured.\n const hasConfiguredAdjustments = Boolean(\n uploadConfig.hasImageAdjustments ||\n (Array.isArray(uploadConfig.variants) && uploadConfig.variants.length > 0),\n )\n\n if (hasSizeEdits || (isResizableImage && hasConfiguredAdjustments) || isAnimatedImage(mimeType)) {\n return 'full'\n }\n\n if (isResizableImage || isImage(mimeType)) {\n return 'header'\n }\n\n return 'none'\n}\n"],"names":["canResizeImage","isAnimatedImage","isImage","HEADER_PROBE_BYTE_LENGTH","getFileContentRequirement","hasSizeEdits","hasTransformFileStages","mimeType","uploadConfig","disableLocalStorage","hasMimeTypeAllowList","Array","isArray","mimeTypes","length","isResizableImage","hasConfiguredAdjustments","Boolean","hasImageAdjustments","variants"],"mappings":"AAEA,SAASA,cAAc,QAAQ,sBAAqB;AACpD,SAASC,eAAe,QAAQ,uBAAsB;AACtD,SAASC,OAAO,QAAQ,eAAc;AAEtC;;;;CAIC,GACD,OAAO,MAAMC,2BAA2B,OAAO,KAAI;AAInD;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC,0BAA0B,EACxCC,YAAY,EACZC,sBAAsB,EACtBC,QAAQ,EACRC,YAAY,EAgBb;IACC,IAAI,CAACA,aAAaC,mBAAmB,EAAE;QACrC,OAAO;IACT;IAEA,MAAMC,uBACJC,MAAMC,OAAO,CAACJ,aAAaK,SAAS,KAAKL,aAAaK,SAAS,CAACC,MAAM,GAAG;IAE3E,IAAIJ,wBAAwBJ,wBAAwB;QAClD,OAAO;IACT;IAEA,MAAMS,mBAAmBf,eAAeO;IACxC,sFAAsF;IACtF,2EAA2E;IAC3E,4FAA4F;IAC5F,2EAA2E;IAC3E,MAAMS,2BAA2BC,QAC/BT,aAAaU,mBAAmB,IAC/BP,MAAMC,OAAO,CAACJ,aAAaW,QAAQ,KAAKX,aAAaW,QAAQ,CAACL,MAAM,GAAG;IAG1E,IAAIT,gBAAiBU,oBAAoBC,4BAA6Bf,gBAAgBM,WAAW;QAC/F,OAAO;IACT;IAEA,IAAIQ,oBAAoBb,QAAQK,WAAW;QACzC,OAAO;IACT;IAEA,OAAO;AACT"}
|