@payloadcms/plugin-cloud-storage 4.0.0-internal.688c4d0 → 4.0.0-internal.77191e5

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.
Files changed (85) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +2 -0
  3. package/dist/client/createClientUploadHandler.d.ts +8 -7
  4. package/dist/client/createClientUploadHandler.d.ts.map +1 -1
  5. package/dist/client/createClientUploadHandler.js +26 -22
  6. package/dist/client/createClientUploadHandler.js.map +1 -1
  7. package/dist/exports/client.d.ts +2 -0
  8. package/dist/exports/client.d.ts.map +1 -1
  9. package/dist/exports/client.js +2 -0
  10. package/dist/exports/client.js.map +1 -1
  11. package/dist/exports/utilities.d.ts +1 -2
  12. package/dist/exports/utilities.d.ts.map +1 -1
  13. package/dist/exports/utilities.js +1 -2
  14. package/dist/exports/utilities.js.map +1 -1
  15. package/dist/fields/getFields.d.ts +1 -5
  16. package/dist/fields/getFields.d.ts.map +1 -1
  17. package/dist/fields/getFields.js +41 -18
  18. package/dist/fields/getFields.js.map +1 -1
  19. package/dist/hooks/afterChange.d.ts +3 -1
  20. package/dist/hooks/afterChange.d.ts.map +1 -1
  21. package/dist/hooks/afterChange.js +79 -22
  22. package/dist/hooks/afterChange.js.map +1 -1
  23. package/dist/hooks/afterDelete.d.ts +3 -1
  24. package/dist/hooks/afterDelete.d.ts.map +1 -1
  25. package/dist/hooks/afterDelete.js +16 -2
  26. package/dist/hooks/afterDelete.js.map +1 -1
  27. package/dist/hooks/afterRead.d.ts.map +1 -1
  28. package/dist/hooks/afterRead.js +15 -2
  29. package/dist/hooks/afterRead.js.map +1 -1
  30. package/dist/hooks/beforeChange.d.ts.map +1 -1
  31. package/dist/hooks/beforeChange.js +12 -1
  32. package/dist/hooks/beforeChange.js.map +1 -1
  33. package/dist/hooks/normalizeUploadPrefix.d.ts +11 -0
  34. package/dist/hooks/normalizeUploadPrefix.d.ts.map +1 -0
  35. package/dist/hooks/normalizeUploadPrefix.js +42 -0
  36. package/dist/hooks/normalizeUploadPrefix.js.map +1 -0
  37. package/dist/plugin.d.ts.map +1 -1
  38. package/dist/plugin.js +178 -128
  39. package/dist/plugin.js.map +1 -1
  40. package/dist/types.d.ts +35 -21
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/types.js.map +1 -1
  43. package/dist/utilities/buildPrefixWithObjectKey.d.ts +8 -0
  44. package/dist/utilities/buildPrefixWithObjectKey.d.ts.map +1 -0
  45. package/dist/utilities/buildPrefixWithObjectKey.js +13 -0
  46. package/dist/utilities/buildPrefixWithObjectKey.js.map +1 -0
  47. package/dist/utilities/buildStoragePathData.d.ts +49 -0
  48. package/dist/utilities/buildStoragePathData.d.ts.map +1 -0
  49. package/dist/utilities/buildStoragePathData.js +67 -0
  50. package/dist/utilities/buildStoragePathData.js.map +1 -0
  51. package/dist/utilities/getFilePrefix.d.ts +19 -11
  52. package/dist/utilities/getFilePrefix.d.ts.map +1 -1
  53. package/dist/utilities/getFilePrefix.js +70 -30
  54. package/dist/utilities/getFilePrefix.js.map +1 -1
  55. package/dist/utilities/getIncomingFiles.js +2 -2
  56. package/dist/utilities/getIncomingFiles.js.map +1 -1
  57. package/dist/utilities/resolveSignedURLKey.d.ts +13 -2
  58. package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
  59. package/dist/utilities/resolveSignedURLKey.js +43 -9
  60. package/dist/utilities/resolveSignedURLKey.js.map +1 -1
  61. package/dist/utilities/sanitizePrefix.d.ts +1 -9
  62. package/dist/utilities/sanitizePrefix.d.ts.map +1 -1
  63. package/dist/utilities/sanitizePrefix.js +1 -21
  64. package/dist/utilities/sanitizePrefix.js.map +1 -1
  65. package/package.json +4 -4
  66. package/dist/admin/fields/getFields.d.ts +0 -17
  67. package/dist/admin/fields/getFields.d.ts.map +0 -1
  68. package/dist/admin/fields/getFields.js +0 -98
  69. package/dist/admin/fields/getFields.js.map +0 -1
  70. package/dist/admin/index.d.ts +0 -4
  71. package/dist/admin/index.d.ts.map +0 -1
  72. package/dist/admin/index.js +0 -34
  73. package/dist/admin/index.js.map +0 -1
  74. package/dist/utilities/getFileKey.d.ts +0 -22
  75. package/dist/utilities/getFileKey.d.ts.map +0 -1
  76. package/dist/utilities/getFileKey.js +0 -23
  77. package/dist/utilities/getFileKey.js.map +0 -1
  78. package/dist/utilities/getFileKey.spec.js +0 -174
  79. package/dist/utilities/getFileKey.spec.js.map +0 -1
  80. package/dist/utilities/getFilePrefix.spec.js +0 -105
  81. package/dist/utilities/getFilePrefix.spec.js.map +0 -1
  82. package/dist/utilities/initClientUploads.d.ts +0 -13
  83. package/dist/utilities/initClientUploads.d.ts.map +0 -1
  84. package/dist/utilities/initClientUploads.js +0 -63
  85. package/dist/utilities/initClientUploads.js.map +0 -1
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018-2025 Payload CMS, Inc. <info@payloadcms.com>
3
+ Copyright (c) 2018-2026 Payload CMS, LLC <info@payloadcms.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
package/README.md CHANGED
@@ -98,6 +98,8 @@ Instead, all uploads will still be reached from the default `/:collectionSlug/fi
98
98
 
99
99
  If this does not apply to you (your upload collection has `read: () => true` or similar) you can disable this functionality by setting `disablePayloadAccessControl` to `true`. When this setting is in place, this plugin will update your file URLs to point directly to your cloud host.
100
100
 
101
+ `disablePayloadAccessControl` does not disable safe outbound fetching. If Payload needs to fetch files from a private or internal storage endpoint, configure the upload collection's [`skipSafeFetch`](https://payloadcms.com/docs/upload/overview#skip-safe-fetch) option with an explicit allowlist for the trusted destination. Set `skipSafeFetch: true` only when every URL accepted by the collection is trusted.
102
+
101
103
  ## Credit
102
104
 
103
105
  This plugin was created with significant help, and code, from [Alex Bechmann](https://github.com/alexbechmann) and [Richard VanBergen](https://github.com/richardvanbergen). Thank you!!
@@ -3,23 +3,24 @@ import { type ReactNode } from 'react';
3
3
  type ClientUploadHandlerProps<T extends Record<string, unknown>> = {
4
4
  children: ReactNode;
5
5
  collectionSlug: UploadCollectionSlug;
6
- enabled?: boolean;
7
- extra: T;
6
+ endpointPath?: `/${string}`;
8
7
  prefix?: string;
9
- serverHandlerPath: `/${string}`;
8
+ props: T;
10
9
  };
11
- export declare const createClientUploadHandler: <T extends Record<string, unknown>>({ handler, }: {
10
+ export declare const createClientUploadHandler: <T extends Record<string, unknown>>({ name, handler, }: {
12
11
  handler: (args: {
13
12
  apiRoute: string;
14
13
  collectionSlug: UploadCollectionSlug;
14
+ data?: unknown;
15
15
  docPrefix?: string;
16
- extra: T;
16
+ endpointPath?: `/${string}`;
17
17
  file: File;
18
18
  prefix?: string;
19
- serverHandlerPath: `/${string}`;
19
+ props: T;
20
20
  serverURL: string;
21
21
  updateFilename: (value: string) => void;
22
22
  }) => Promise<unknown>;
23
- }) => ({ children, collectionSlug, enabled, extra, prefix, serverHandlerPath, }: ClientUploadHandlerProps<T>) => import("react").JSX.Element;
23
+ name: string;
24
+ }) => ({ children, collectionSlug, endpointPath, prefix, props, }: ClientUploadHandlerProps<T>) => import("react").JSX.Element;
24
25
  export {};
25
26
  //# sourceMappingURL=createClientUploadHandler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createClientUploadHandler.d.ts","sourceRoot":"","sources":["../../src/client/createClientUploadHandler.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAGnD,OAAO,EAAY,KAAK,SAAS,EAAa,MAAM,OAAO,CAAA;AAE3D,KAAK,wBAAwB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACjE,QAAQ,EAAE,SAAS,CAAA;IACnB,cAAc,EAAE,oBAAoB,CAAA;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,CAAC,CAAA;IACR,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iBAAiB,EAAE,IAAI,MAAM,EAAE,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,cAE1E;IACD,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,QAAQ,EAAE,MAAM,CAAA;QAChB,cAAc,EAAE,oBAAoB,CAAA;QACpC,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,CAAC,CAAA;QACR,IAAI,EAAE,IAAI,CAAA;QACV,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,iBAAiB,EAAE,IAAI,MAAM,EAAE,CAAA;QAC/B,SAAS,EAAE,MAAM,CAAA;QACjB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;KACxC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACvB,MACqC,0EAOjC,wBAAwB,CAAC,CAAC,CAAC,gCAoC/B,CAAA"}
1
+ {"version":3,"file":"createClientUploadHandler.d.ts","sourceRoot":"","sources":["../../src/client/createClientUploadHandler.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAGnD,OAAO,EAAY,KAAK,SAAS,EAAa,MAAM,OAAO,CAAA;AAE3D,KAAK,wBAAwB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACjE,QAAQ,EAAE,SAAS,CAAA;IACnB,cAAc,EAAE,oBAAoB,CAAA;IACpC,YAAY,CAAC,EAAE,IAAI,MAAM,EAAE,CAAA;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,CAAC,CAAA;CACT,CAAA;AAED,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,sBAGxE;IACD,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,QAAQ,EAAE,MAAM,CAAA;QAChB,cAAc,EAAE,oBAAoB,CAAA;QACpC,IAAI,CAAC,EAAE,OAAO,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,IAAI,MAAM,EAAE,CAAA;QAC3B,IAAI,EAAE,IAAI,CAAA;QACV,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,EAAE,CAAC,CAAA;QACR,SAAS,EAAE,MAAM,CAAA;QACjB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;KACxC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;CACb,kEAOI,wBAAwB,CAAC,CAAC,CAAC,gCAmD/B,CAAA"}
@@ -1,33 +1,37 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { useConfig, useEffectEvent, useUploadHandlers } from '@payloadcms/ui';
3
+ import { useConfig, useEffectEvent } from '@payloadcms/ui';
4
4
  import { Fragment, useEffect } from 'react';
5
- export const createClientUploadHandler = ({ handler })=>{
6
- return function ClientUploadHandler({ children, collectionSlug, enabled, extra, prefix, serverHandlerPath }) {
7
- const { setUploadHandler } = useUploadHandlers();
5
+ export const createClientUploadHandler = ({ name, handler })=>{
6
+ return function ClientUploadHandler({ children, collectionSlug, endpointPath, prefix, props }) {
8
7
  const { config: { routes: { api: apiRoute }, serverURL } } = useConfig();
9
8
  const initializeHandler = useEffectEvent(()=>{
10
- if (enabled) {
11
- setUploadHandler({
9
+ const listener = (event)=>{
10
+ const customEvent = event;
11
+ if (customEvent.detail.collectionSlug !== collectionSlug) {
12
+ return;
13
+ }
14
+ customEvent.preventDefault();
15
+ void handler({
16
+ apiRoute,
12
17
  collectionSlug,
13
- handler: ({ docPrefix, file, updateFilename })=>{
14
- return handler({
15
- apiRoute,
16
- collectionSlug,
17
- docPrefix,
18
- extra,
19
- file,
20
- prefix,
21
- serverHandlerPath,
22
- serverURL,
23
- updateFilename
24
- });
25
- }
26
- });
27
- }
18
+ data: customEvent.detail.data,
19
+ docPrefix: customEvent.detail.docPrefix,
20
+ endpointPath,
21
+ file: customEvent.detail.file,
22
+ prefix,
23
+ props,
24
+ serverURL,
25
+ updateFilename: customEvent.detail.updateFilename
26
+ }).then(customEvent.detail.resolve, customEvent.detail.reject);
27
+ };
28
+ const eventName = `payload:upload:${name}`;
29
+ const eventTarget = globalThis;
30
+ eventTarget.addEventListener(eventName, listener);
31
+ return ()=>eventTarget.removeEventListener(eventName, listener);
28
32
  });
29
33
  useEffect(()=>{
30
- initializeHandler();
34
+ return initializeHandler();
31
35
  }, []);
32
36
  return /*#__PURE__*/ _jsx(Fragment, {
33
37
  children: children
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/createClientUploadHandler.tsx"],"sourcesContent":["'use client'\n\nimport type { UploadCollectionSlug } from 'payload'\n\nimport { useConfig, useEffectEvent, useUploadHandlers } from '@payloadcms/ui'\nimport { Fragment, type ReactNode, useEffect } from 'react'\n\ntype ClientUploadHandlerProps<T extends Record<string, unknown>> = {\n children: ReactNode\n collectionSlug: UploadCollectionSlug\n enabled?: boolean\n extra: T\n prefix?: string\n serverHandlerPath: `/${string}`\n}\n\nexport const createClientUploadHandler = <T extends Record<string, unknown>>({\n handler,\n}: {\n handler: (args: {\n apiRoute: string\n collectionSlug: UploadCollectionSlug\n docPrefix?: string\n extra: T\n file: File\n prefix?: string\n serverHandlerPath: `/${string}`\n serverURL: string\n updateFilename: (value: string) => void\n }) => Promise<unknown>\n}) => {\n return function ClientUploadHandler({\n children,\n collectionSlug,\n enabled,\n extra,\n prefix,\n serverHandlerPath,\n }: ClientUploadHandlerProps<T>) {\n const { setUploadHandler } = useUploadHandlers()\n const {\n config: {\n routes: { api: apiRoute },\n serverURL,\n },\n } = useConfig()\n\n const initializeHandler = useEffectEvent(() => {\n if (enabled) {\n setUploadHandler({\n collectionSlug,\n handler: ({ docPrefix, file, updateFilename }) => {\n return handler({\n apiRoute,\n collectionSlug,\n docPrefix,\n extra,\n file,\n prefix,\n serverHandlerPath,\n serverURL,\n updateFilename,\n })\n },\n })\n }\n })\n\n useEffect(() => {\n initializeHandler()\n }, [])\n\n return <Fragment>{children}</Fragment>\n }\n}\n"],"names":["useConfig","useEffectEvent","useUploadHandlers","Fragment","useEffect","createClientUploadHandler","handler","ClientUploadHandler","children","collectionSlug","enabled","extra","prefix","serverHandlerPath","setUploadHandler","config","routes","api","apiRoute","serverURL","initializeHandler","docPrefix","file","updateFilename"],"mappings":"AAAA;;AAIA,SAASA,SAAS,EAAEC,cAAc,EAAEC,iBAAiB,QAAQ,iBAAgB;AAC7E,SAASC,QAAQ,EAAkBC,SAAS,QAAQ,QAAO;AAW3D,OAAO,MAAMC,4BAA4B,CAAoC,EAC3EC,OAAO,EAaR;IACC,OAAO,SAASC,oBAAoB,EAClCC,QAAQ,EACRC,cAAc,EACdC,OAAO,EACPC,KAAK,EACLC,MAAM,EACNC,iBAAiB,EACW;QAC5B,MAAM,EAAEC,gBAAgB,EAAE,GAAGZ;QAC7B,MAAM,EACJa,QAAQ,EACNC,QAAQ,EAAEC,KAAKC,QAAQ,EAAE,EACzBC,SAAS,EACV,EACF,GAAGnB;QAEJ,MAAMoB,oBAAoBnB,eAAe;YACvC,IAAIS,SAAS;gBACXI,iBAAiB;oBACfL;oBACAH,SAAS,CAAC,EAAEe,SAAS,EAAEC,IAAI,EAAEC,cAAc,EAAE;wBAC3C,OAAOjB,QAAQ;4BACbY;4BACAT;4BACAY;4BACAV;4BACAW;4BACAV;4BACAC;4BACAM;4BACAI;wBACF;oBACF;gBACF;YACF;QACF;QAEAnB,UAAU;YACRgB;QACF,GAAG,EAAE;QAEL,qBAAO,KAACjB;sBAAUK;;IACpB;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/client/createClientUploadHandler.tsx"],"sourcesContent":["'use client'\n\nimport type { UploadCollectionSlug } from 'payload'\n\nimport { useConfig, useEffectEvent } from '@payloadcms/ui'\nimport { Fragment, type ReactNode, useEffect } from 'react'\n\ntype ClientUploadHandlerProps<T extends Record<string, unknown>> = {\n children: ReactNode\n collectionSlug: UploadCollectionSlug\n endpointPath?: `/${string}`\n prefix?: string\n props: T\n}\n\nexport const createClientUploadHandler = <T extends Record<string, unknown>>({\n name,\n handler,\n}: {\n handler: (args: {\n apiRoute: string\n collectionSlug: UploadCollectionSlug\n data?: unknown\n docPrefix?: string\n endpointPath?: `/${string}`\n file: File\n prefix?: string\n props: T\n serverURL: string\n updateFilename: (value: string) => void\n }) => Promise<unknown>\n name: string\n}) => {\n return function ClientUploadHandler({\n children,\n collectionSlug,\n endpointPath,\n prefix,\n props,\n }: ClientUploadHandlerProps<T>) {\n const {\n config: {\n routes: { api: apiRoute },\n serverURL,\n },\n } = useConfig()\n\n const initializeHandler = useEffectEvent(() => {\n const listener = (event: Event) => {\n const customEvent = event as CustomEvent<{\n collectionSlug: UploadCollectionSlug\n data?: unknown\n docPrefix?: string\n file: File\n reject: (reason?: unknown) => void\n resolve: (value: unknown) => void\n updateFilename: (value: string) => void\n }>\n\n if (customEvent.detail.collectionSlug !== collectionSlug) {\n return\n }\n\n customEvent.preventDefault()\n void handler({\n apiRoute,\n collectionSlug,\n data: customEvent.detail.data,\n docPrefix: customEvent.detail.docPrefix,\n endpointPath,\n file: customEvent.detail.file,\n prefix,\n props,\n serverURL,\n updateFilename: customEvent.detail.updateFilename,\n }).then(customEvent.detail.resolve, customEvent.detail.reject)\n }\n\n const eventName = `payload:upload:${name}`\n const eventTarget = globalThis as unknown as EventTarget\n eventTarget.addEventListener(eventName, listener)\n return () => eventTarget.removeEventListener(eventName, listener)\n })\n\n useEffect(() => {\n return initializeHandler()\n }, [])\n\n return <Fragment>{children}</Fragment>\n }\n}\n"],"names":["useConfig","useEffectEvent","Fragment","useEffect","createClientUploadHandler","name","handler","ClientUploadHandler","children","collectionSlug","endpointPath","prefix","props","config","routes","api","apiRoute","serverURL","initializeHandler","listener","event","customEvent","detail","preventDefault","data","docPrefix","file","updateFilename","then","resolve","reject","eventName","eventTarget","globalThis","addEventListener","removeEventListener"],"mappings":"AAAA;;AAIA,SAASA,SAAS,EAAEC,cAAc,QAAQ,iBAAgB;AAC1D,SAASC,QAAQ,EAAkBC,SAAS,QAAQ,QAAO;AAU3D,OAAO,MAAMC,4BAA4B,CAAoC,EAC3EC,IAAI,EACJC,OAAO,EAeR;IACC,OAAO,SAASC,oBAAoB,EAClCC,QAAQ,EACRC,cAAc,EACdC,YAAY,EACZC,MAAM,EACNC,KAAK,EACuB;QAC5B,MAAM,EACJC,QAAQ,EACNC,QAAQ,EAAEC,KAAKC,QAAQ,EAAE,EACzBC,SAAS,EACV,EACF,GAAGjB;QAEJ,MAAMkB,oBAAoBjB,eAAe;YACvC,MAAMkB,WAAW,CAACC;gBAChB,MAAMC,cAAcD;gBAUpB,IAAIC,YAAYC,MAAM,CAACb,cAAc,KAAKA,gBAAgB;oBACxD;gBACF;gBAEAY,YAAYE,cAAc;gBAC1B,KAAKjB,QAAQ;oBACXU;oBACAP;oBACAe,MAAMH,YAAYC,MAAM,CAACE,IAAI;oBAC7BC,WAAWJ,YAAYC,MAAM,CAACG,SAAS;oBACvCf;oBACAgB,MAAML,YAAYC,MAAM,CAACI,IAAI;oBAC7Bf;oBACAC;oBACAK;oBACAU,gBAAgBN,YAAYC,MAAM,CAACK,cAAc;gBACnD,GAAGC,IAAI,CAACP,YAAYC,MAAM,CAACO,OAAO,EAAER,YAAYC,MAAM,CAACQ,MAAM;YAC/D;YAEA,MAAMC,YAAY,CAAC,eAAe,EAAE1B,MAAM;YAC1C,MAAM2B,cAAcC;YACpBD,YAAYE,gBAAgB,CAACH,WAAWZ;YACxC,OAAO,IAAMa,YAAYG,mBAAmB,CAACJ,WAAWZ;QAC1D;QAEAhB,UAAU;YACR,OAAOe;QACT,GAAG,EAAE;QAEL,qBAAO,KAAChB;sBAAUM;;IACpB;AACF,EAAC"}
@@ -1,2 +1,4 @@
1
1
  export { createClientUploadHandler } from '../client/createClientUploadHandler.js';
2
+ export { buildStoragePathData, buildUploadStoragePathData, } from '../utilities/buildStoragePathData.js';
3
+ export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
2
4
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAA"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAA;AAClF,OAAO,EACL,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA"}
@@ -1,3 +1,5 @@
1
1
  export { createClientUploadHandler } from '../client/createClientUploadHandler.js';
2
+ export { buildStoragePathData, buildUploadStoragePathData } from '../utilities/buildStoragePathData.js';
3
+ export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
2
4
 
3
5
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { createClientUploadHandler } from '../client/createClientUploadHandler.js'\n"],"names":["createClientUploadHandler"],"mappings":"AAAA,SAASA,yBAAyB,QAAQ,yCAAwC"}
1
+ {"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { createClientUploadHandler } from '../client/createClientUploadHandler.js'\nexport {\n buildStoragePathData,\n buildUploadStoragePathData,\n} from '../utilities/buildStoragePathData.js'\nexport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n"],"names":["createClientUploadHandler","buildStoragePathData","buildUploadStoragePathData","sanitizePrefix"],"mappings":"AAAA,SAASA,yBAAyB,QAAQ,yCAAwC;AAClF,SACEC,oBAAoB,EACpBC,0BAA0B,QACrB,uCAAsC;AAC7C,SAASC,cAAc,QAAQ,iCAAgC"}
@@ -1,6 +1,5 @@
1
- export { getFileKey } from '../utilities/getFileKey.js';
1
+ export { buildStoragePathData, buildUploadStoragePathData, isStoragePathWithinCollectionPrefix, } from '../utilities/buildStoragePathData.js';
2
2
  export { getFilePrefix } from '../utilities/getFilePrefix.js';
3
- export { initClientUploads } from '../utilities/initClientUploads.js';
4
3
  export { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js';
5
4
  export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
6
5
  //# sourceMappingURL=utilities.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../../src/exports/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAA;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA"}
1
+ {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../../src/exports/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,mCAAmC,GACpC,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA"}
@@ -1,6 +1,5 @@
1
- export { getFileKey } from '../utilities/getFileKey.js';
1
+ export { buildStoragePathData, buildUploadStoragePathData, isStoragePathWithinCollectionPrefix } from '../utilities/buildStoragePathData.js';
2
2
  export { getFilePrefix } from '../utilities/getFilePrefix.js';
3
- export { initClientUploads } from '../utilities/initClientUploads.js';
4
3
  export { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js';
5
4
  export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
6
5
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/exports/utilities.ts"],"sourcesContent":["export { getFileKey } from '../utilities/getFileKey.js'\nexport { getFilePrefix } from '../utilities/getFilePrefix.js'\nexport { initClientUploads } from '../utilities/initClientUploads.js'\nexport { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js'\nexport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n"],"names":["getFileKey","getFilePrefix","initClientUploads","resolveSignedURLKey","sanitizePrefix"],"mappings":"AAAA,SAASA,UAAU,QAAQ,6BAA4B;AACvD,SAASC,aAAa,QAAQ,gCAA+B;AAC7D,SAASC,iBAAiB,QAAQ,oCAAmC;AACrE,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,cAAc,QAAQ,iCAAgC"}
1
+ {"version":3,"sources":["../../src/exports/utilities.ts"],"sourcesContent":["export {\n buildStoragePathData,\n buildUploadStoragePathData,\n isStoragePathWithinCollectionPrefix,\n} from '../utilities/buildStoragePathData.js'\nexport { getFilePrefix } from '../utilities/getFilePrefix.js'\nexport { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js'\nexport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n"],"names":["buildStoragePathData","buildUploadStoragePathData","isStoragePathWithinCollectionPrefix","getFilePrefix","resolveSignedURLKey","sanitizePrefix"],"mappings":"AAAA,SACEA,oBAAoB,EACpBC,0BAA0B,EAC1BC,mCAAmC,QAC9B,uCAAsC;AAC7C,SAASC,aAAa,QAAQ,gCAA+B;AAC7D,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,cAAc,QAAQ,iCAAgC"}
@@ -2,10 +2,6 @@ import type { CollectionConfig, Field } from 'payload';
2
2
  import type { GeneratedAdapter, GenerateFileURL } from '../types.js';
3
3
  interface Args {
4
4
  adapter?: GeneratedAdapter;
5
- /**
6
- * When true, always insert the prefix field regardless of whether a prefix is configured.
7
- */
8
- alwaysInsertFields?: boolean;
9
5
  collection: CollectionConfig;
10
6
  disablePayloadAccessControl?: true;
11
7
  generateFileURL?: GenerateFileURL;
@@ -16,6 +12,6 @@ interface Args {
16
12
  */
17
13
  useCompositePrefixes?: boolean;
18
14
  }
19
- export declare const getFields: ({ adapter, alwaysInsertFields, collection, disablePayloadAccessControl, generateFileURL, prefix, useCompositePrefixes, }: Args) => Field[];
15
+ export declare const getFields: ({ adapter, collection, disablePayloadAccessControl, generateFileURL, prefix, useCompositePrefixes, }: Args) => Field[];
20
16
  export {};
21
17
  //# sourceMappingURL=getFields.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getFields.d.ts","sourceRoot":"","sources":["../../src/fields/getFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAyB,MAAM,SAAS,CAAA;AAI7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAKpE,UAAU,IAAI;IACZ,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,UAAU,EAAE,gBAAgB,CAAA;IAC5B,2BAA2B,CAAC,EAAE,IAAI,CAAA;IAClC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,SAAS,GAAI,0HAQvB,IAAI,KAAG,KAAK,EA+Kd,CAAA"}
1
+ {"version":3,"file":"getFields.d.ts","sourceRoot":"","sources":["../../src/fields/getFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAyB,MAAM,SAAS,CAAA;AAI7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAMpE,UAAU,IAAI;IACZ,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,UAAU,EAAE,gBAAgB,CAAA;IAC5B,2BAA2B,CAAC,EAAE,IAAI,CAAA;IAClC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,SAAS,yGAOnB,IAAI,KAAG,KAAK,EAqMd,CAAA"}
@@ -1,7 +1,8 @@
1
1
  import path from 'path';
2
2
  import { getAfterReadHook } from '../hooks/afterRead.js';
3
3
  import { getBeforeChangeHook } from '../hooks/beforeChange.js';
4
- export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayloadAccessControl, generateFileURL, prefix, useCompositePrefixes = false })=>{
4
+ import { getNormalizeUploadPrefixFieldHook } from '../hooks/normalizeUploadPrefix.js';
5
+ export const getFields = ({ adapter, collection, disablePayloadAccessControl, generateFileURL, prefix, useCompositePrefixes = false })=>{
5
6
  const baseURLField = {
6
7
  name: 'url',
7
8
  type: 'text',
@@ -19,6 +20,12 @@ export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayl
19
20
  readOnly: true
20
21
  }
21
22
  };
23
+ // Server-owned key segment; hidden from the API and admin, read internally via showHiddenFields.
24
+ const baseObjectKeyField = {
25
+ name: '_objectKey',
26
+ type: 'text',
27
+ hidden: true
28
+ };
22
29
  const fields = [
23
30
  ...collection.fields,
24
31
  ...adapter?.fields || []
@@ -132,25 +139,41 @@ export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayl
132
139
  };
133
140
  fields.push(sizesField);
134
141
  }
135
- // If prefix is enabled or alwaysInsertFields is true, save it to db
136
- if (typeof prefix !== 'undefined' || alwaysInsertFields) {
137
- let existingPrefixFieldIndex = -1;
138
- const existingPrefixField = fields.find((existingField, i)=>{
139
- if ('name' in existingField && existingField.name === 'prefix') {
140
- existingPrefixFieldIndex = i;
141
- return true;
142
- }
143
- return false;
144
- });
145
- if (existingPrefixFieldIndex > -1) {
146
- fields.splice(existingPrefixFieldIndex, 1);
142
+ // Always insert the prefix field so the schema stays consistent regardless of
143
+ // whether the plugin is enabled or a prefix is configured.
144
+ let existingPrefixFieldIndex = -1;
145
+ const existingPrefixField = fields.find((existingField, i)=>{
146
+ if ('name' in existingField && existingField.name === 'prefix') {
147
+ existingPrefixFieldIndex = i;
148
+ return true;
147
149
  }
148
- fields.push({
149
- ...basePrefixField,
150
- ...existingPrefixField || {},
151
- defaultValue: existingPrefixField?.defaultValue ?? (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : '')
152
- });
150
+ return false;
151
+ });
152
+ if (existingPrefixFieldIndex > -1) {
153
+ fields.splice(existingPrefixFieldIndex, 1);
153
154
  }
155
+ fields.push({
156
+ ...basePrefixField,
157
+ ...existingPrefixField || {},
158
+ defaultValue: existingPrefixField?.defaultValue ?? (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : ''),
159
+ hooks: {
160
+ ...existingPrefixField?.hooks,
161
+ beforeChange: [
162
+ ...existingPrefixField?.hooks?.beforeChange || [],
163
+ getNormalizeUploadPrefixFieldHook({
164
+ collectionPrefix: prefix,
165
+ useCompositePrefixes
166
+ })
167
+ ]
168
+ }
169
+ });
170
+ const existingObjectKeyFieldIndex = fields.findIndex((existingField)=>'name' in existingField && existingField.name === '_objectKey');
171
+ if (existingObjectKeyFieldIndex > -1) {
172
+ fields.splice(existingObjectKeyFieldIndex, 1);
173
+ }
174
+ fields.push({
175
+ ...baseObjectKeyField
176
+ });
154
177
  return fields;
155
178
  };
156
179
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fields/getFields.ts"],"sourcesContent":["import type { CollectionConfig, Field, GroupField, TextField } from 'payload'\n\nimport path from 'path'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { getAfterReadHook } from '../hooks/afterRead.js'\nimport { getBeforeChangeHook } from '../hooks/beforeChange.js'\n\ninterface Args {\n adapter?: GeneratedAdapter\n /**\n * When true, always insert the prefix field regardless of whether a prefix is configured.\n */\n alwaysInsertFields?: boolean\n collection: CollectionConfig\n disablePayloadAccessControl?: true\n generateFileURL?: GenerateFileURL\n prefix?: string\n /**\n * When true, do not default the `prefix` field to the collection prefix; the\n * document field holds only the document-level segment.\n */\n useCompositePrefixes?: boolean\n}\n\nexport const getFields = ({\n adapter,\n alwaysInsertFields,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n prefix,\n useCompositePrefixes = false,\n}: Args): Field[] => {\n const baseURLField: TextField = {\n name: 'url',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n label: 'URL',\n }\n\n const basePrefixField: TextField = {\n name: 'prefix',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n }\n\n const fields = [...collection.fields, ...(adapter?.fields || [])]\n\n // Inject a hook into all URL fields to generate URLs\n\n let existingURLFieldIndex = -1\n\n const existingURLField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'url') {\n existingURLFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingURLFieldIndex > -1) {\n fields.splice(existingURLFieldIndex, 1)\n }\n\n // Only add afterRead hook if adapter is provided\n if (adapter) {\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n hooks: {\n afterRead: [\n getAfterReadHook({ adapter, collection, disablePayloadAccessControl, generateFileURL }),\n ...(existingURLField?.hooks?.afterRead || []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n }),\n ...(existingURLField?.hooks?.beforeChange || []),\n ],\n },\n } as TextField)\n } else {\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n } as TextField)\n }\n\n if (typeof collection.upload === 'object' && collection.upload.imageSizes) {\n let existingSizesFieldIndex = -1\n\n const existingSizesField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'sizes') {\n existingSizesFieldIndex = i\n return true\n }\n\n return false\n }) as GroupField\n\n if (existingSizesFieldIndex > -1) {\n fields.splice(existingSizesFieldIndex, 1)\n }\n\n const sizesField: Field = {\n ...(existingSizesField || {}),\n name: 'sizes',\n type: 'group',\n admin: {\n hidden: true,\n },\n fields: collection.upload.imageSizes.map((size) => {\n const existingSizeField = existingSizesField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === size.name,\n ) as GroupField\n\n const existingSizeURLField = existingSizeField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === 'url',\n ) as TextField\n\n // Only add afterRead hook if adapter is provided\n const sizeURLField: TextField = adapter\n ? ({\n ...(existingSizeURLField || {}),\n ...baseURLField,\n hooks: {\n afterRead: [\n getAfterReadHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n size,\n }),\n ...((typeof existingSizeURLField === 'object' &&\n 'hooks' in existingSizeURLField &&\n existingSizeURLField?.hooks?.afterRead) ||\n []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n size,\n }),\n ...((typeof existingSizeURLField === 'object' &&\n 'hooks' in existingSizeURLField &&\n existingSizeURLField?.hooks?.beforeChange) ||\n []),\n ],\n },\n } as TextField)\n : ({\n ...(existingSizeURLField || {}),\n ...baseURLField,\n } as TextField)\n\n return {\n ...existingSizeField,\n name: size.name,\n type: 'group',\n fields: [...(adapter?.fields || []), sizeURLField],\n } as Field\n }),\n }\n\n fields.push(sizesField)\n }\n\n // If prefix is enabled or alwaysInsertFields is true, save it to db\n if (typeof prefix !== 'undefined' || alwaysInsertFields) {\n let existingPrefixFieldIndex = -1\n\n const existingPrefixField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'prefix') {\n existingPrefixFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingPrefixFieldIndex > -1) {\n fields.splice(existingPrefixFieldIndex, 1)\n }\n\n fields.push({\n ...basePrefixField,\n ...(existingPrefixField || {}),\n defaultValue:\n existingPrefixField?.defaultValue ??\n (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : ''),\n } as TextField)\n }\n\n return fields\n}\n"],"names":["path","getAfterReadHook","getBeforeChangeHook","getFields","adapter","alwaysInsertFields","collection","disablePayloadAccessControl","generateFileURL","prefix","useCompositePrefixes","baseURLField","name","type","admin","hidden","readOnly","label","basePrefixField","fields","existingURLFieldIndex","existingURLField","find","existingField","i","splice","push","hooks","afterRead","beforeChange","upload","imageSizes","existingSizesFieldIndex","existingSizesField","sizesField","map","size","existingSizeField","existingSizeURLField","sizeURLField","existingPrefixFieldIndex","existingPrefixField","defaultValue","posix","join"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/fields/getFields.ts"],"sourcesContent":["import type { CollectionConfig, Field, GroupField, TextField } from 'payload'\n\nimport path from 'path'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { getAfterReadHook } from '../hooks/afterRead.js'\nimport { getBeforeChangeHook } from '../hooks/beforeChange.js'\nimport { getNormalizeUploadPrefixFieldHook } from '../hooks/normalizeUploadPrefix.js'\n\ninterface Args {\n adapter?: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: true\n generateFileURL?: GenerateFileURL\n prefix?: string\n /**\n * When true, do not default the `prefix` field to the collection prefix; the\n * document field holds only the document-level segment.\n */\n useCompositePrefixes?: boolean\n}\n\nexport const getFields = ({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n prefix,\n useCompositePrefixes = false,\n}: Args): Field[] => {\n const baseURLField: TextField = {\n name: 'url',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n label: 'URL',\n }\n\n const basePrefixField: TextField = {\n name: 'prefix',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n }\n\n // Server-owned key segment; hidden from the API and admin, read internally via showHiddenFields.\n const baseObjectKeyField: TextField = {\n name: '_objectKey',\n type: 'text',\n hidden: true,\n }\n\n const fields = [...collection.fields, ...(adapter?.fields || [])]\n\n // Inject a hook into all URL fields to generate URLs\n\n let existingURLFieldIndex = -1\n\n const existingURLField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'url') {\n existingURLFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingURLFieldIndex > -1) {\n fields.splice(existingURLFieldIndex, 1)\n }\n\n // Only add afterRead hook if adapter is provided\n if (adapter) {\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n hooks: {\n afterRead: [\n getAfterReadHook({ adapter, collection, disablePayloadAccessControl, generateFileURL }),\n ...(existingURLField?.hooks?.afterRead || []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n }),\n ...(existingURLField?.hooks?.beforeChange || []),\n ],\n },\n } as TextField)\n } else {\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n } as TextField)\n }\n\n if (typeof collection.upload === 'object' && collection.upload.imageSizes) {\n let existingSizesFieldIndex = -1\n\n const existingSizesField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'sizes') {\n existingSizesFieldIndex = i\n return true\n }\n\n return false\n }) as GroupField\n\n if (existingSizesFieldIndex > -1) {\n fields.splice(existingSizesFieldIndex, 1)\n }\n\n const sizesField: Field = {\n ...(existingSizesField || {}),\n name: 'sizes',\n type: 'group',\n admin: {\n hidden: true,\n },\n fields: collection.upload.imageSizes.map((size) => {\n const existingSizeField = existingSizesField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === size.name,\n ) as GroupField\n\n const existingSizeURLField = existingSizeField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === 'url',\n ) as TextField\n\n // Only add afterRead hook if adapter is provided\n const sizeURLField: TextField = adapter\n ? ({\n ...(existingSizeURLField || {}),\n ...baseURLField,\n hooks: {\n afterRead: [\n getAfterReadHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n size,\n }),\n ...((typeof existingSizeURLField === 'object' &&\n 'hooks' in existingSizeURLField &&\n existingSizeURLField?.hooks?.afterRead) ||\n []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n size,\n }),\n ...((typeof existingSizeURLField === 'object' &&\n 'hooks' in existingSizeURLField &&\n existingSizeURLField?.hooks?.beforeChange) ||\n []),\n ],\n },\n } as TextField)\n : ({\n ...(existingSizeURLField || {}),\n ...baseURLField,\n } as TextField)\n\n return {\n ...existingSizeField,\n name: size.name,\n type: 'group',\n fields: [...(adapter?.fields || []), sizeURLField],\n } as Field\n }),\n }\n\n fields.push(sizesField)\n }\n\n // Always insert the prefix field so the schema stays consistent regardless of\n // whether the plugin is enabled or a prefix is configured.\n let existingPrefixFieldIndex = -1\n\n const existingPrefixField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'prefix') {\n existingPrefixFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingPrefixFieldIndex > -1) {\n fields.splice(existingPrefixFieldIndex, 1)\n }\n\n fields.push({\n ...basePrefixField,\n ...(existingPrefixField || {}),\n defaultValue:\n existingPrefixField?.defaultValue ??\n (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : ''),\n hooks: {\n ...existingPrefixField?.hooks,\n beforeChange: [\n ...(existingPrefixField?.hooks?.beforeChange || []),\n getNormalizeUploadPrefixFieldHook({ collectionPrefix: prefix, useCompositePrefixes }),\n ],\n },\n } as TextField)\n\n const existingObjectKeyFieldIndex = fields.findIndex(\n (existingField) => 'name' in existingField && existingField.name === '_objectKey',\n )\n if (existingObjectKeyFieldIndex > -1) {\n fields.splice(existingObjectKeyFieldIndex, 1)\n }\n\n fields.push({ ...baseObjectKeyField } as TextField)\n\n return fields\n}\n"],"names":["path","getAfterReadHook","getBeforeChangeHook","getNormalizeUploadPrefixFieldHook","getFields","adapter","collection","disablePayloadAccessControl","generateFileURL","prefix","useCompositePrefixes","baseURLField","name","type","admin","hidden","readOnly","label","basePrefixField","baseObjectKeyField","fields","existingURLFieldIndex","existingURLField","find","existingField","i","splice","push","hooks","afterRead","beforeChange","upload","imageSizes","existingSizesFieldIndex","existingSizesField","sizesField","map","size","existingSizeField","existingSizeURLField","sizeURLField","existingPrefixFieldIndex","existingPrefixField","defaultValue","posix","join","collectionPrefix","existingObjectKeyFieldIndex","findIndex"],"mappings":"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"}
@@ -3,7 +3,9 @@ import type { GeneratedAdapter } from '../types.js';
3
3
  interface Args {
4
4
  adapter: GeneratedAdapter;
5
5
  collection: CollectionConfig;
6
+ collectionPrefix?: string;
7
+ useCompositePrefixes?: boolean;
6
8
  }
7
- export declare const getAfterChangeHook: ({ adapter, collection }: Args) => CollectionAfterChangeHook<FileData & TypeWithID>;
9
+ export declare const getAfterChangeHook: ({ adapter, collection, collectionPrefix, useCompositePrefixes, }: Args) => CollectionAfterChangeHook<FileData & TypeWithID>;
8
10
  export {};
9
11
  //# sourceMappingURL=afterChange.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"afterChange.d.ts","sourceRoot":"","sources":["../../src/hooks/afterChange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAInD,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;CAC7B;AAED,eAAO,MAAM,kBAAkB,GAC5B,yBAAyB,IAAI,KAAG,yBAAyB,CAAC,QAAQ,GAAG,UAAU,CAqH/E,CAAA"}
1
+ {"version":3,"file":"afterChange.d.ts","sourceRoot":"","sources":["../../src/hooks/afterChange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAIhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AASnD,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAQD,eAAO,MAAM,kBAAkB,qEAM1B,IAAI,KAAG,yBAAyB,CAAC,QAAQ,GAAG,UAAU,CA6KxD,CAAA"}
@@ -1,26 +1,54 @@
1
+ import { deepMergeWithSourceArrays } from 'payload';
2
+ import { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js';
3
+ import { buildStoragePathData, buildUploadStoragePathData } from '../utilities/buildStoragePathData.js';
1
4
  import { getIncomingFiles } from '../utilities/getIncomingFiles.js';
2
- export const getAfterChangeHook = ({ adapter, collection })=>async ({ doc, operation, previousDoc, req })=>{
5
+ // The object's folder: semantic prefix + `_objectKey` segment.
6
+ const getObjectFolder = (data)=>{
7
+ const record = data ?? {};
8
+ return buildPrefixWithObjectKey({
9
+ objectKey: record._objectKey,
10
+ prefix: record.prefix
11
+ });
12
+ };
13
+ export const getAfterChangeHook = ({ adapter, collection, collectionPrefix, useCompositePrefixes })=>async ({ data, doc, operation, previousDoc, req, select })=>{
3
14
  // Skip if this is an internal update to prevent infinite loop
4
15
  if (req.context?.skipCloudStorage) {
5
16
  return doc;
6
17
  }
18
+ // Restore upload metadata removed by select, including partially selected image sizes.
19
+ const uploadData = select ? deepMergeWithSourceArrays(data, doc) : doc;
20
+ const isDraftSave = uploadData._status === 'draft';
21
+ const isDraftOverPublished = isDraftSave && previousDoc?._status === 'published';
7
22
  try {
8
23
  const files = getIncomingFiles({
9
- data: doc,
24
+ data: uploadData,
10
25
  req
11
26
  });
12
27
  if (files.length > 0) {
13
- const uploadResults = await Promise.all(files.filter((file)=>!file.clientUploadContext).map((file)=>adapter.handleUpload({
14
- clientUploadContext: file.clientUploadContext,
28
+ // Fold `_objectKey` so generated sizes land in the same folder as the original.
29
+ const dataForUpload = {
30
+ ...uploadData,
31
+ prefix: getObjectFolder(uploadData)
32
+ };
33
+ const uploadResults = await Promise.all(files.filter((file)=>!file.uploadReference).map((file)=>adapter.handleUpload({
15
34
  collection,
16
- data: doc,
35
+ data: dataForUpload,
17
36
  file,
18
- req
37
+ req,
38
+ storageFilePath: buildUploadStoragePathData({
39
+ collectionPrefix,
40
+ docPrefix: dataForUpload.prefix,
41
+ filename: file.filename,
42
+ useCompositePrefixes
43
+ }).storageFilePath
19
44
  })));
20
45
  const uploadMetadata = uploadResults.filter((result)=>result != null && typeof result === 'object').reduce((acc, metadata)=>({
21
46
  ...acc,
22
47
  ...metadata
23
48
  }), {});
49
+ // Adapters may echo `data` back as metadata; keep the document's own `prefix`/`_objectKey`.
50
+ delete uploadMetadata.prefix;
51
+ delete uploadMetadata._objectKey;
24
52
  let docWithMetadata = doc;
25
53
  if (Object.keys(uploadMetadata).length > 0) {
26
54
  if (!req.context) {
@@ -31,26 +59,32 @@ export const getAfterChangeHook = ({ adapter, collection })=>async ({ doc, opera
31
59
  req.file = undefined;
32
60
  req.payloadUploadSizes = undefined;
33
61
  try {
34
- await req.payload.update({
62
+ const updatedDoc = await req.payload.update({
35
63
  id: doc.id,
36
64
  collection: collection.slug,
37
65
  data: uploadMetadata,
38
66
  depth: 0,
39
- req
67
+ draft: isDraftSave,
68
+ req,
69
+ select
40
70
  });
71
+ // Persist all adapter metadata, but do not add unselected fields to the response.
72
+ docWithMetadata = select ? {
73
+ ...doc,
74
+ ...updatedDoc
75
+ } : {
76
+ ...doc,
77
+ ...uploadMetadata
78
+ };
41
79
  } finally{
42
80
  delete req.context.skipCloudStorage;
43
81
  }
44
- docWithMetadata = {
45
- ...doc,
46
- ...uploadMetadata
47
- };
48
82
  }
49
83
  // Delete previous files only after the new upload and metadata
50
84
  // persistence have succeeded. Deleting earlier would orphan the
51
85
  // record if a later step throws (e.g. a user-defined afterChange
52
86
  // hook on the same collection).
53
- if (previousDoc && operation === 'update') {
87
+ if (previousDoc && operation === 'update' && !isDraftOverPublished) {
54
88
  let filesToDelete = [];
55
89
  if (typeof previousDoc?.filename === 'string') {
56
90
  filesToDelete.push(previousDoc.filename);
@@ -58,27 +92,50 @@ export const getAfterChangeHook = ({ adapter, collection })=>async ({ doc, opera
58
92
  if (typeof previousDoc.sizes === 'object') {
59
93
  filesToDelete = filesToDelete.concat(Object.values(previousDoc?.sizes || []).map((resizedFileData)=>resizedFileData?.filename));
60
94
  }
61
- // Collect new filenames (main + sizes) so we don't delete a
62
- // file that the new upload reused (e.g. same filename on reupload
63
- // where Payload overwrites in place).
95
+ // Compare full locations: a replacement can reuse a filename while moving
96
+ // a legacy object beneath the collection prefix.
97
+ const newFileData = {
98
+ ...uploadData,
99
+ ...uploadMetadata
100
+ };
64
101
  const newFilenames = new Set();
65
- if (typeof docWithMetadata.filename === 'string') {
66
- newFilenames.add(docWithMetadata.filename);
102
+ if (typeof newFileData.filename === 'string') {
103
+ newFilenames.add(newFileData.filename);
67
104
  }
68
- if (typeof docWithMetadata.sizes === 'object') {
69
- for (const size of Object.values(docWithMetadata.sizes || {})){
105
+ if (typeof newFileData.sizes === 'object') {
106
+ for (const size of Object.values(newFileData.sizes || {})){
70
107
  if (size?.filename && typeof size.filename === 'string') {
71
108
  newFilenames.add(size.filename);
72
109
  }
73
110
  }
74
111
  }
112
+ const resolveKey = ({ data, filename })=>buildStoragePathData({
113
+ collectionPrefix,
114
+ docPrefix: getObjectFolder(data),
115
+ filename,
116
+ useCompositePrefixes
117
+ }).storageFilePath;
118
+ const newKeys = new Set([
119
+ ...newFilenames
120
+ ].map((filename)=>resolveKey({
121
+ data: newFileData,
122
+ filename
123
+ })));
75
124
  const deletionPromises = filesToDelete.map(async (filename)=>{
76
- if (filename && !newFilenames.has(filename)) {
125
+ if (!filename) {
126
+ return;
127
+ }
128
+ const storageFilePath = resolveKey({
129
+ data: previousDoc,
130
+ filename
131
+ });
132
+ if (!newKeys.has(storageFilePath)) {
77
133
  await adapter.handleDelete({
78
134
  collection,
79
135
  doc: previousDoc,
80
136
  filename,
81
- req
137
+ req,
138
+ storageFilePath
82
139
  });
83
140
  }
84
141
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/afterChange.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter } from '../types.js'\n\nimport { getIncomingFiles } from '../utilities/getIncomingFiles.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n}\n\nexport const getAfterChangeHook =\n ({ adapter, collection }: Args): CollectionAfterChangeHook<FileData & TypeWithID> =>\n async ({ doc, operation, previousDoc, req }) => {\n // Skip if this is an internal update to prevent infinite loop\n if (req.context?.skipCloudStorage) {\n return doc\n }\n\n try {\n const files = getIncomingFiles({ data: doc, req })\n\n if (files.length > 0) {\n const uploadResults = await Promise.all(\n files\n .filter((file) => !file.clientUploadContext)\n .map((file) =>\n adapter.handleUpload({\n clientUploadContext: file.clientUploadContext,\n collection,\n data: doc,\n file,\n req,\n }),\n ),\n )\n\n const uploadMetadata = uploadResults\n .filter(\n (result): result is Partial<FileData & TypeWithID> =>\n result != null && typeof result === 'object',\n )\n .reduce(\n (acc, metadata) => ({ ...acc, ...metadata }),\n {} as Partial<FileData & TypeWithID>,\n )\n\n let docWithMetadata = doc\n\n if (Object.keys(uploadMetadata).length > 0) {\n if (!req.context) {\n req.context = {}\n }\n req.context.skipCloudStorage = true\n\n // Clear to prevent re-processing\n req.file = undefined\n req.payloadUploadSizes = undefined\n\n try {\n await req.payload.update({\n id: doc.id,\n collection: collection.slug,\n data: uploadMetadata,\n depth: 0,\n req,\n })\n } finally {\n delete req.context.skipCloudStorage\n }\n\n docWithMetadata = { ...doc, ...uploadMetadata }\n }\n\n // Delete previous files only after the new upload and metadata\n // persistence have succeeded. Deleting earlier would orphan the\n // record if a later step throws (e.g. a user-defined afterChange\n // hook on the same collection).\n if (previousDoc && operation === 'update') {\n let filesToDelete: string[] = []\n\n if (typeof previousDoc?.filename === 'string') {\n filesToDelete.push(previousDoc.filename)\n }\n\n if (typeof previousDoc.sizes === 'object') {\n filesToDelete = filesToDelete.concat(\n Object.values(previousDoc?.sizes || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n )\n }\n\n // Collect new filenames (main + sizes) so we don't delete a\n // file that the new upload reused (e.g. same filename on reupload\n // where Payload overwrites in place).\n const newFilenames = new Set<string>()\n if (typeof docWithMetadata.filename === 'string') {\n newFilenames.add(docWithMetadata.filename)\n }\n if (typeof docWithMetadata.sizes === 'object') {\n for (const size of Object.values(docWithMetadata.sizes || {})) {\n if (size?.filename && typeof size.filename === 'string') {\n newFilenames.add(size.filename)\n }\n }\n }\n\n const deletionPromises = filesToDelete.map(async (filename) => {\n if (filename && !newFilenames.has(filename)) {\n await adapter.handleDelete({ collection, doc: previousDoc, filename, req })\n }\n })\n\n await Promise.all(deletionPromises)\n }\n\n if (docWithMetadata !== doc) {\n return docWithMetadata\n }\n }\n } catch (err: unknown) {\n req.payload.logger.error(\n `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${doc.filename}:`,\n )\n req.payload.logger.error({ err })\n throw err\n }\n return doc\n }\n"],"names":["getIncomingFiles","getAfterChangeHook","adapter","collection","doc","operation","previousDoc","req","context","skipCloudStorage","files","data","length","uploadResults","Promise","all","filter","file","clientUploadContext","map","handleUpload","uploadMetadata","result","reduce","acc","metadata","docWithMetadata","Object","keys","undefined","payloadUploadSizes","payload","update","id","slug","depth","filesToDelete","filename","push","sizes","concat","values","resizedFileData","newFilenames","Set","add","size","deletionPromises","has","handleDelete","err","logger","error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/hooks/afterChange.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport { deepMergeWithSourceArrays } from 'payload'\n\nimport type { GeneratedAdapter } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\nimport {\n buildStoragePathData,\n buildUploadStoragePathData,\n} from '../utilities/buildStoragePathData.js'\nimport { getIncomingFiles } from '../utilities/getIncomingFiles.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n collectionPrefix?: string\n useCompositePrefixes?: boolean\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (data: unknown): string => {\n const record = (data ?? {}) as { _objectKey?: string; prefix?: string }\n return buildPrefixWithObjectKey({ objectKey: record._objectKey, prefix: record.prefix })\n}\n\nexport const getAfterChangeHook =\n ({\n adapter,\n collection,\n collectionPrefix,\n useCompositePrefixes,\n }: Args): CollectionAfterChangeHook<FileData & TypeWithID> =>\n async ({ data, doc, operation, previousDoc, req, select }) => {\n // Skip if this is an internal update to prevent infinite loop\n if (req.context?.skipCloudStorage) {\n return doc\n }\n\n // Restore upload metadata removed by select, including partially selected image sizes.\n const uploadData = select ? deepMergeWithSourceArrays<FileData & TypeWithID>(data, doc) : doc\n const isDraftSave = (uploadData as { _status?: string })._status === 'draft'\n const isDraftOverPublished =\n isDraftSave && (previousDoc as { _status?: string } | undefined)?._status === 'published'\n\n try {\n const files = getIncomingFiles({ data: uploadData, req })\n\n if (files.length > 0) {\n // Fold `_objectKey` so generated sizes land in the same folder as the original.\n const dataForUpload = { ...uploadData, prefix: getObjectFolder(uploadData) }\n\n const uploadResults = await Promise.all(\n files\n .filter((file) => !file.uploadReference)\n .map((file) =>\n adapter.handleUpload({\n collection,\n data: dataForUpload,\n file,\n req,\n storageFilePath: buildUploadStoragePathData({\n collectionPrefix,\n docPrefix: dataForUpload.prefix,\n filename: file.filename,\n useCompositePrefixes,\n }).storageFilePath,\n }),\n ),\n )\n\n const uploadMetadata = uploadResults\n .filter(\n (result): result is Partial<FileData & TypeWithID> =>\n result != null && typeof result === 'object',\n )\n .reduce(\n (acc, metadata) => ({ ...acc, ...metadata }),\n {} as Partial<FileData & TypeWithID>,\n )\n\n // Adapters may echo `data` back as metadata; keep the document's own `prefix`/`_objectKey`.\n delete (uploadMetadata as Record<string, unknown>).prefix\n delete (uploadMetadata as Record<string, unknown>)._objectKey\n\n let docWithMetadata = doc\n\n if (Object.keys(uploadMetadata).length > 0) {\n if (!req.context) {\n req.context = {}\n }\n req.context.skipCloudStorage = true\n\n // Clear to prevent re-processing\n req.file = undefined\n req.payloadUploadSizes = undefined\n\n try {\n const updatedDoc = await req.payload.update({\n id: doc.id,\n collection: collection.slug,\n data: uploadMetadata,\n depth: 0,\n draft: isDraftSave,\n req,\n select,\n })\n\n // Persist all adapter metadata, but do not add unselected fields to the response.\n docWithMetadata = select ? { ...doc, ...updatedDoc } : { ...doc, ...uploadMetadata }\n } finally {\n delete req.context.skipCloudStorage\n }\n }\n\n // Delete previous files only after the new upload and metadata\n // persistence have succeeded. Deleting earlier would orphan the\n // record if a later step throws (e.g. a user-defined afterChange\n // hook on the same collection).\n if (previousDoc && operation === 'update' && !isDraftOverPublished) {\n let filesToDelete: string[] = []\n\n if (typeof previousDoc?.filename === 'string') {\n filesToDelete.push(previousDoc.filename)\n }\n\n if (typeof previousDoc.sizes === 'object') {\n filesToDelete = filesToDelete.concat(\n Object.values(previousDoc?.sizes || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n )\n }\n\n // Compare full locations: a replacement can reuse a filename while moving\n // a legacy object beneath the collection prefix.\n const newFileData = { ...uploadData, ...uploadMetadata }\n const newFilenames = new Set<string>()\n if (typeof newFileData.filename === 'string') {\n newFilenames.add(newFileData.filename)\n }\n if (typeof newFileData.sizes === 'object') {\n for (const size of Object.values(newFileData.sizes || {})) {\n if (size?.filename && typeof size.filename === 'string') {\n newFilenames.add(size.filename)\n }\n }\n }\n\n const resolveKey = ({\n data,\n filename,\n }: {\n data: { _objectKey?: string; prefix?: string }\n filename: string\n }) =>\n buildStoragePathData({\n collectionPrefix,\n docPrefix: getObjectFolder(data),\n filename,\n useCompositePrefixes,\n }).storageFilePath\n const newKeys = new Set(\n [...newFilenames].map((filename) =>\n resolveKey({\n data: newFileData as { _objectKey?: string; prefix?: string },\n filename,\n }),\n ),\n )\n\n const deletionPromises = filesToDelete.map(async (filename) => {\n if (!filename) {\n return\n }\n const storageFilePath = resolveKey({\n data: previousDoc as { _objectKey?: string; prefix?: string },\n filename,\n })\n if (!newKeys.has(storageFilePath)) {\n await adapter.handleDelete({\n collection,\n doc: previousDoc,\n filename,\n req,\n storageFilePath,\n })\n }\n })\n\n await Promise.all(deletionPromises)\n }\n\n if (docWithMetadata !== doc) {\n return docWithMetadata\n }\n }\n } catch (err: unknown) {\n req.payload.logger.error(\n `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${doc.filename}:`,\n )\n req.payload.logger.error({ err })\n throw err\n }\n return doc\n }\n"],"names":["deepMergeWithSourceArrays","buildPrefixWithObjectKey","buildStoragePathData","buildUploadStoragePathData","getIncomingFiles","getObjectFolder","data","record","objectKey","_objectKey","prefix","getAfterChangeHook","adapter","collection","collectionPrefix","useCompositePrefixes","doc","operation","previousDoc","req","select","context","skipCloudStorage","uploadData","isDraftSave","_status","isDraftOverPublished","files","length","dataForUpload","uploadResults","Promise","all","filter","file","uploadReference","map","handleUpload","storageFilePath","docPrefix","filename","uploadMetadata","result","reduce","acc","metadata","docWithMetadata","Object","keys","undefined","payloadUploadSizes","updatedDoc","payload","update","id","slug","depth","draft","filesToDelete","push","sizes","concat","values","resizedFileData","newFileData","newFilenames","Set","add","size","resolveKey","newKeys","deletionPromises","has","handleDelete","err","logger","error"],"mappings":"AAEA,SAASA,yBAAyB,QAAQ,UAAS;AAInD,SAASC,wBAAwB,QAAQ,2CAA0C;AACnF,SACEC,oBAAoB,EACpBC,0BAA0B,QACrB,uCAAsC;AAC7C,SAASC,gBAAgB,QAAQ,mCAAkC;AASnE,+DAA+D;AAC/D,MAAMC,kBAAkB,CAACC;IACvB,MAAMC,SAAUD,QAAQ,CAAC;IACzB,OAAOL,yBAAyB;QAAEO,WAAWD,OAAOE,UAAU;QAAEC,QAAQH,OAAOG,MAAM;IAAC;AACxF;AAEA,OAAO,MAAMC,qBACX,CAAC,EACCC,OAAO,EACPC,UAAU,EACVC,gBAAgB,EAChBC,oBAAoB,EACf,GACP,OAAO,EAAET,IAAI,EAAEU,GAAG,EAAEC,SAAS,EAAEC,WAAW,EAAEC,GAAG,EAAEC,MAAM,EAAE;QACvD,8DAA8D;QAC9D,IAAID,IAAIE,OAAO,EAAEC,kBAAkB;YACjC,OAAON;QACT;QAEA,uFAAuF;QACvF,MAAMO,aAAaH,SAASpB,0BAAiDM,MAAMU,OAAOA;QAC1F,MAAMQ,cAAc,AAACD,WAAoCE,OAAO,KAAK;QACrE,MAAMC,uBACJF,eAAe,AAACN,aAAkDO,YAAY;QAEhF,IAAI;YACF,MAAME,QAAQvB,iBAAiB;gBAAEE,MAAMiB;gBAAYJ;YAAI;YAEvD,IAAIQ,MAAMC,MAAM,GAAG,GAAG;gBACpB,gFAAgF;gBAChF,MAAMC,gBAAgB;oBAAE,GAAGN,UAAU;oBAAEb,QAAQL,gBAAgBkB;gBAAY;gBAE3E,MAAMO,gBAAgB,MAAMC,QAAQC,GAAG,CACrCL,MACGM,MAAM,CAAC,CAACC,OAAS,CAACA,KAAKC,eAAe,EACtCC,GAAG,CAAC,CAACF,OACJtB,QAAQyB,YAAY,CAAC;wBACnBxB;wBACAP,MAAMuB;wBACNK;wBACAf;wBACAmB,iBAAiBnC,2BAA2B;4BAC1CW;4BACAyB,WAAWV,cAAcnB,MAAM;4BAC/B8B,UAAUN,KAAKM,QAAQ;4BACvBzB;wBACF,GAAGuB,eAAe;oBACpB;gBAIN,MAAMG,iBAAiBX,cACpBG,MAAM,CACL,CAACS,SACCA,UAAU,QAAQ,OAAOA,WAAW,UAEvCC,MAAM,CACL,CAACC,KAAKC,WAAc,CAAA;wBAAE,GAAGD,GAAG;wBAAE,GAAGC,QAAQ;oBAAC,CAAA,GAC1C,CAAC;gBAGL,4FAA4F;gBAC5F,OAAO,AAACJ,eAA2C/B,MAAM;gBACzD,OAAO,AAAC+B,eAA2ChC,UAAU;gBAE7D,IAAIqC,kBAAkB9B;gBAEtB,IAAI+B,OAAOC,IAAI,CAACP,gBAAgBb,MAAM,GAAG,GAAG;oBAC1C,IAAI,CAACT,IAAIE,OAAO,EAAE;wBAChBF,IAAIE,OAAO,GAAG,CAAC;oBACjB;oBACAF,IAAIE,OAAO,CAACC,gBAAgB,GAAG;oBAE/B,iCAAiC;oBACjCH,IAAIe,IAAI,GAAGe;oBACX9B,IAAI+B,kBAAkB,GAAGD;oBAEzB,IAAI;wBACF,MAAME,aAAa,MAAMhC,IAAIiC,OAAO,CAACC,MAAM,CAAC;4BAC1CC,IAAItC,IAAIsC,EAAE;4BACVzC,YAAYA,WAAW0C,IAAI;4BAC3BjD,MAAMmC;4BACNe,OAAO;4BACPC,OAAOjC;4BACPL;4BACAC;wBACF;wBAEA,kFAAkF;wBAClF0B,kBAAkB1B,SAAS;4BAAE,GAAGJ,GAAG;4BAAE,GAAGmC,UAAU;wBAAC,IAAI;4BAAE,GAAGnC,GAAG;4BAAE,GAAGyB,cAAc;wBAAC;oBACrF,SAAU;wBACR,OAAOtB,IAAIE,OAAO,CAACC,gBAAgB;oBACrC;gBACF;gBAEA,+DAA+D;gBAC/D,gEAAgE;gBAChE,iEAAiE;gBACjE,gCAAgC;gBAChC,IAAIJ,eAAeD,cAAc,YAAY,CAACS,sBAAsB;oBAClE,IAAIgC,gBAA0B,EAAE;oBAEhC,IAAI,OAAOxC,aAAasB,aAAa,UAAU;wBAC7CkB,cAAcC,IAAI,CAACzC,YAAYsB,QAAQ;oBACzC;oBAEA,IAAI,OAAOtB,YAAY0C,KAAK,KAAK,UAAU;wBACzCF,gBAAgBA,cAAcG,MAAM,CAClCd,OAAOe,MAAM,CAAC5C,aAAa0C,SAAS,EAAE,EAAExB,GAAG,CACzC,CAAC2B,kBAAoBA,iBAAiBvB;oBAG5C;oBAEA,0EAA0E;oBAC1E,iDAAiD;oBACjD,MAAMwB,cAAc;wBAAE,GAAGzC,UAAU;wBAAE,GAAGkB,cAAc;oBAAC;oBACvD,MAAMwB,eAAe,IAAIC;oBACzB,IAAI,OAAOF,YAAYxB,QAAQ,KAAK,UAAU;wBAC5CyB,aAAaE,GAAG,CAACH,YAAYxB,QAAQ;oBACvC;oBACA,IAAI,OAAOwB,YAAYJ,KAAK,KAAK,UAAU;wBACzC,KAAK,MAAMQ,QAAQrB,OAAOe,MAAM,CAACE,YAAYJ,KAAK,IAAI,CAAC,GAAI;4BACzD,IAAIQ,MAAM5B,YAAY,OAAO4B,KAAK5B,QAAQ,KAAK,UAAU;gCACvDyB,aAAaE,GAAG,CAACC,KAAK5B,QAAQ;4BAChC;wBACF;oBACF;oBAEA,MAAM6B,aAAa,CAAC,EAClB/D,IAAI,EACJkC,QAAQ,EAIT,GACCtC,qBAAqB;4BACnBY;4BACAyB,WAAWlC,gBAAgBC;4BAC3BkC;4BACAzB;wBACF,GAAGuB,eAAe;oBACpB,MAAMgC,UAAU,IAAIJ,IAClB;2BAAID;qBAAa,CAAC7B,GAAG,CAAC,CAACI,WACrB6B,WAAW;4BACT/D,MAAM0D;4BACNxB;wBACF;oBAIJ,MAAM+B,mBAAmBb,cAActB,GAAG,CAAC,OAAOI;wBAChD,IAAI,CAACA,UAAU;4BACb;wBACF;wBACA,MAAMF,kBAAkB+B,WAAW;4BACjC/D,MAAMY;4BACNsB;wBACF;wBACA,IAAI,CAAC8B,QAAQE,GAAG,CAAClC,kBAAkB;4BACjC,MAAM1B,QAAQ6D,YAAY,CAAC;gCACzB5D;gCACAG,KAAKE;gCACLsB;gCACArB;gCACAmB;4BACF;wBACF;oBACF;oBAEA,MAAMP,QAAQC,GAAG,CAACuC;gBACpB;gBAEA,IAAIzB,oBAAoB9B,KAAK;oBAC3B,OAAO8B;gBACT;YACF;QACF,EAAE,OAAO4B,KAAc;YACrBvD,IAAIiC,OAAO,CAACuB,MAAM,CAACC,KAAK,CACtB,CAAC,yEAAyE,EAAE/D,WAAW0C,IAAI,CAAC,eAAe,EAAEvC,IAAIwB,QAAQ,CAAC,CAAC,CAAC;YAE9HrB,IAAIiC,OAAO,CAACuB,MAAM,CAACC,KAAK,CAAC;gBAAEF;YAAI;YAC/B,MAAMA;QACR;QACA,OAAO1D;IACT,EAAC"}
@@ -3,7 +3,9 @@ import type { GeneratedAdapter, TypeWithPrefix } from '../types.js';
3
3
  interface Args {
4
4
  adapter: GeneratedAdapter;
5
5
  collection: CollectionConfig;
6
+ collectionPrefix?: string;
7
+ useCompositePrefixes?: boolean;
6
8
  }
7
- export declare const getAfterDeleteHook: ({ adapter, collection, }: Args) => CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix>;
9
+ export declare const getAfterDeleteHook: ({ adapter, collection, collectionPrefix, useCompositePrefixes, }: Args) => CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix>;
8
10
  export {};
9
11
  //# sourceMappingURL=afterDelete.d.ts.map