payload 4.0.0-internal.e55ccef → 4.0.0-internal.e7d4ebc

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 (52) hide show
  1. package/dist/admin/functions/index.d.ts +0 -7
  2. package/dist/admin/functions/index.d.ts.map +1 -1
  3. package/dist/admin/functions/index.js.map +1 -1
  4. package/dist/admin/types.d.ts +1 -1
  5. package/dist/admin/types.d.ts.map +1 -1
  6. package/dist/admin/types.js.map +1 -1
  7. package/dist/collections/config/client.d.ts +8 -2
  8. package/dist/collections/config/client.d.ts.map +1 -1
  9. package/dist/collections/config/client.js +6 -1
  10. package/dist/collections/config/client.js.map +1 -1
  11. package/dist/config/sanitize.d.ts.map +1 -1
  12. package/dist/config/sanitize.js +4 -0
  13. package/dist/config/sanitize.js.map +1 -1
  14. package/dist/exports/internal.d.ts +2 -0
  15. package/dist/exports/internal.d.ts.map +1 -1
  16. package/dist/exports/internal.js +3 -1
  17. package/dist/exports/internal.js.map +1 -1
  18. package/dist/fields/baseFields/slug/generateSlug.d.ts +16 -5
  19. package/dist/fields/baseFields/slug/generateSlug.d.ts.map +1 -1
  20. package/dist/fields/baseFields/slug/generateSlug.js +22 -26
  21. package/dist/fields/baseFields/slug/generateSlug.js.map +1 -1
  22. package/dist/index.bundled.d.ts +3907 -3862
  23. package/dist/types/index.d.ts +1 -4
  24. package/dist/types/index.d.ts.map +1 -1
  25. package/dist/types/index.js.map +1 -1
  26. package/dist/uploads/checkFileRestrictions.d.ts +1 -1
  27. package/dist/uploads/checkFileRestrictions.d.ts.map +1 -1
  28. package/dist/uploads/checkFileRestrictions.js +15 -1
  29. package/dist/uploads/checkFileRestrictions.js.map +1 -1
  30. package/dist/uploads/endpoints/uploadInstructions.d.ts +15 -0
  31. package/dist/uploads/endpoints/uploadInstructions.d.ts.map +1 -0
  32. package/dist/uploads/endpoints/uploadInstructions.js +84 -0
  33. package/dist/uploads/endpoints/uploadInstructions.js.map +1 -0
  34. package/dist/uploads/getFileFromUploadInstructions.d.ts +8 -0
  35. package/dist/uploads/getFileFromUploadInstructions.d.ts.map +1 -0
  36. package/dist/uploads/getFileFromUploadInstructions.js +62 -0
  37. package/dist/uploads/getFileFromUploadInstructions.js.map +1 -0
  38. package/dist/uploads/stagedUpload.d.ts +27 -0
  39. package/dist/uploads/stagedUpload.d.ts.map +1 -0
  40. package/dist/uploads/stagedUpload.js +197 -0
  41. package/dist/uploads/stagedUpload.js.map +1 -0
  42. package/dist/uploads/types.d.ts +53 -1
  43. package/dist/uploads/types.d.ts.map +1 -1
  44. package/dist/uploads/types.js.map +1 -1
  45. package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
  46. package/dist/utilities/addDataAndFileToRequest.js +12 -45
  47. package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
  48. package/package.json +2 -2
  49. package/dist/fields/baseFields/slug/countVersions.d.ts +0 -13
  50. package/dist/fields/baseFields/slug/countVersions.d.ts.map +0 -1
  51. package/dist/fields/baseFields/slug/countVersions.js +0 -27
  52. package/dist/fields/baseFields/slug/countVersions.js.map +0 -1
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * Modules exported here are not part of the public API and are subject to change without notice and without a major version bump.
3
3
  */
4
+ export { getUploadInstructions } from '../uploads/endpoints/uploadInstructions.js';
4
5
  export { getExternalFile } from '../uploads/getExternalFile.js';
6
+ export { getFileFromUploadInstructions } from '../uploads/getFileFromUploadInstructions.js';
5
7
  export { getRangeRequestInfo } from '../uploads/getRangeRequestInfo.js';
6
8
  export { getSafeFileName } from '../uploads/getSafeFilename.js';
7
9
  export { parseRangeHeader } from '../uploads/parseRangeHeader.js';
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/exports/internal.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2DAA2D,CAAA;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/exports/internal.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAA;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,6BAA6B,EAAE,MAAM,6CAA6C,CAAA;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2DAA2D,CAAA;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA"}
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Modules exported here are not part of the public API and are subject to change without notice and without a major version bump.
3
- */ export { getExternalFile } from '../uploads/getExternalFile.js';
3
+ */ export { getUploadInstructions } from '../uploads/endpoints/uploadInstructions.js';
4
+ export { getExternalFile } from '../uploads/getExternalFile.js';
5
+ export { getFileFromUploadInstructions } from '../uploads/getFileFromUploadInstructions.js';
4
6
  export { getRangeRequestInfo } from '../uploads/getRangeRequestInfo.js';
5
7
  export { getSafeFileName } from '../uploads/getSafeFilename.js';
6
8
  export { parseRangeHeader } from '../uploads/parseRangeHeader.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/exports/internal.ts"],"sourcesContent":["/**\n * Modules exported here are not part of the public API and are subject to change without notice and without a major version bump.\n */\n\nexport { getExternalFile } from '../uploads/getExternalFile.js'\nexport { getRangeRequestInfo } from '../uploads/getRangeRequestInfo.js'\nexport { getSafeFileName } from '../uploads/getSafeFilename.js'\nexport { parseRangeHeader } from '../uploads/parseRangeHeader.js'\nexport { getEntityPermissions } from '../utilities/getEntityPermissions/getEntityPermissions.js'\nexport { isURLAllowed } from '../utilities/isURLAllowed.js'\nexport { sanitizePermissions } from '../utilities/sanitizePermissions.js'\nexport { sendTelemetryEvent } from '../utilities/telemetry/index.js'\n"],"names":["getExternalFile","getRangeRequestInfo","getSafeFileName","parseRangeHeader","getEntityPermissions","isURLAllowed","sanitizePermissions","sendTelemetryEvent"],"mappings":"AAAA;;CAEC,GAED,SAASA,eAAe,QAAQ,gCAA+B;AAC/D,SAASC,mBAAmB,QAAQ,oCAAmC;AACvE,SAASC,eAAe,QAAQ,gCAA+B;AAC/D,SAASC,gBAAgB,QAAQ,iCAAgC;AACjE,SAASC,oBAAoB,QAAQ,4DAA2D;AAChG,SAASC,YAAY,QAAQ,+BAA8B;AAC3D,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,kBAAkB,QAAQ,kCAAiC"}
1
+ {"version":3,"sources":["../../src/exports/internal.ts"],"sourcesContent":["/**\n * Modules exported here are not part of the public API and are subject to change without notice and without a major version bump.\n */\n\nexport { getUploadInstructions } from '../uploads/endpoints/uploadInstructions.js'\nexport { getExternalFile } from '../uploads/getExternalFile.js'\nexport { getFileFromUploadInstructions } from '../uploads/getFileFromUploadInstructions.js'\nexport { getRangeRequestInfo } from '../uploads/getRangeRequestInfo.js'\nexport { getSafeFileName } from '../uploads/getSafeFilename.js'\nexport { parseRangeHeader } from '../uploads/parseRangeHeader.js'\nexport { getEntityPermissions } from '../utilities/getEntityPermissions/getEntityPermissions.js'\nexport { isURLAllowed } from '../utilities/isURLAllowed.js'\nexport { sanitizePermissions } from '../utilities/sanitizePermissions.js'\nexport { sendTelemetryEvent } from '../utilities/telemetry/index.js'\n"],"names":["getUploadInstructions","getExternalFile","getFileFromUploadInstructions","getRangeRequestInfo","getSafeFileName","parseRangeHeader","getEntityPermissions","isURLAllowed","sanitizePermissions","sendTelemetryEvent"],"mappings":"AAAA;;CAEC,GAED,SAASA,qBAAqB,QAAQ,6CAA4C;AAClF,SAASC,eAAe,QAAQ,gCAA+B;AAC/D,SAASC,6BAA6B,QAAQ,8CAA6C;AAC3F,SAASC,mBAAmB,QAAQ,oCAAmC;AACvE,SAASC,eAAe,QAAQ,gCAA+B;AAC/D,SAASC,gBAAgB,QAAQ,iCAAgC;AACjE,SAASC,oBAAoB,QAAQ,4DAA2D;AAChG,SAASC,YAAY,QAAQ,+BAA8B;AAC3D,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,kBAAkB,QAAQ,kCAAiC"}
@@ -7,12 +7,23 @@ type Args = {
7
7
  };
8
8
  /**
9
9
  * Field `beforeChange` hook for the native `slug` field. Returns the slug value.
10
+ * - The slug value is derived from the `useAsSlug` source field,
11
+ * but can be manually overridden by the admin.
12
+ * - To protect live URLs, the slug is frozen after initial generation
13
+ * unless the admin explicitly overwrites it.
10
14
  *
11
- * Auto-tracking is derived statelessly: the slug follows its source while it is
12
- * empty or still equals `slugify(storedSource)`. Once it diverges (the admin
13
- * overwrites it), it freezes — and stays frozen, because the stored value keeps
14
- * differing from `slugify(source)`. Re-aligning (the UI generate button) resumes
15
- * tracking.
15
+ * This is expressed as follows:
16
+ *
17
+ * Non-versioned and versioned-but-non-autosave collections:
18
+ * - On create, generate from the source, keeping an explicitly provided value.
19
+ * - On update, regenerate only while the stored slug is empty.
20
+ * - Freeze on the first non-empty value, whether generated or manually provided.
21
+ *
22
+ * Autosave drafts:
23
+ * - On every draft save (create and autosave) before publish, generate freely — a new
24
+ * document gets a natural, live-updating slug while the admin is still entering content.
25
+ * - Freeze on the first manual overwrite or the first publish. A mid-draft overwrite wins
26
+ * immediately and is preserved across later autosaves.
16
27
  */
17
28
  export declare const generateSlug: ({ name, slugify: customSlugify, useAsSlug }: Args) => FieldHook;
18
29
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"generateSlug.d.ts","sourceRoot":"","sources":["../../../../src/fields/baseFields/slug/generateSlug.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAMzC,KAAK,IAAI,GAAG;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,gDACuB,IAAI,KAAG,SA+DpD,CAAA"}
1
+ {"version":3,"file":"generateSlug.d.ts","sourceRoot":"","sources":["../../../../src/fields/baseFields/slug/generateSlug.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAKzC,KAAK,IAAI,GAAG;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,YAAY,gDACuB,IAAI,KAAG,SA8CpD,CAAA"}
@@ -1,14 +1,24 @@
1
1
  import { hasAutosaveEnabled } from '../../../utilities/getVersionsConfig.js';
2
2
  import { slugify as defaultSlugify } from '../../../utilities/slugify.js';
3
- import { countVersions } from './countVersions.js';
4
3
  /**
5
4
  * Field `beforeChange` hook for the native `slug` field. Returns the slug value.
5
+ * - The slug value is derived from the `useAsSlug` source field,
6
+ * but can be manually overridden by the admin.
7
+ * - To protect live URLs, the slug is frozen after initial generation
8
+ * unless the admin explicitly overwrites it.
6
9
  *
7
- * Auto-tracking is derived statelessly: the slug follows its source while it is
8
- * empty or still equals `slugify(storedSource)`. Once it diverges (the admin
9
- * overwrites it), it freezes — and stays frozen, because the stored value keeps
10
- * differing from `slugify(source)`. Re-aligning (the UI generate button) resumes
11
- * tracking.
10
+ * This is expressed as follows:
11
+ *
12
+ * Non-versioned and versioned-but-non-autosave collections:
13
+ * - On create, generate from the source, keeping an explicitly provided value.
14
+ * - On update, regenerate only while the stored slug is empty.
15
+ * - Freeze on the first non-empty value, whether generated or manually provided.
16
+ *
17
+ * Autosave drafts:
18
+ * - On every draft save (create and autosave) before publish, generate freely — a new
19
+ * document gets a natural, live-updating slug while the admin is still entering content.
20
+ * - Freeze on the first manual overwrite or the first publish. A mid-draft overwrite wins
21
+ * immediately and is preserved across later autosaves.
12
22
  */ export const generateSlug = ({ name, slugify: customSlugify, useAsSlug })=>async ({ collection, data, global, operation, originalDoc, req, value })=>{
13
23
  const source = data?.[useAsSlug];
14
24
  const slugify = (valueToSlugify)=>customSlugify ? customSlugify({
@@ -18,17 +28,14 @@ import { countVersions } from './countVersions.js';
18
28
  }) : defaultSlugify(valueToSlugify);
19
29
  const entity = collection || global;
20
30
  if (operation === 'create') {
21
- // Autosave drafts: do not auto-generate on the initial draft the user is still entering content.
22
- // Keep the explicit non-slugified value (if any); generation begins on a later autosave.
23
- if (hasAutosaveEnabled(entity) && data?._status === 'draft') {
24
- return value || null;
25
- }
26
- // Keep an explicitly provided slug; otherwise generate from the source.
31
+ // Generate from the source (keeping an explicitly provided slug). On an autosave
32
+ // collection the initial draft is created empty, so this yields an empty slug and
33
+ // begins tracking as soon as content is entered.
27
34
  return await slugify(value || source);
28
35
  }
29
36
  const storedSlug = originalDoc?.[name];
30
37
  const originalSource = originalDoc?.[useAsSlug];
31
- // User explicitly edited the slug (or cleared the value): respect it.
38
+ // User explicitly edited the slug (or cleared the value) this save: respect it.
32
39
  if (value !== undefined && value !== storedSlug) {
33
40
  return value;
34
41
  }
@@ -42,22 +49,11 @@ import { countVersions } from './countVersions.js';
42
49
  // Non-autosave: generate once while empty, then freeze.
43
50
  return storedSlug || await slugify(source);
44
51
  }
45
- // Autosave / drafts
46
- const priorVersions = await countVersions({
47
- collectionSlug: collection?.slug,
48
- globalSlug: global?.slug,
49
- parentID: originalDoc?.id,
50
- req
51
- });
52
- // Do not generate on the very first draft (no prior version yet).
53
- if (priorVersions === 0) {
54
- return storedSlug ?? null;
55
- }
56
- // Stabilize after publish to protect live URLs.
52
+ // Autosave drafts: freeze once the document has been published to protect the live URL.
57
53
  if (data?._status === 'published' || originalDoc?._status === 'published') {
58
54
  return storedSlug;
59
55
  }
60
- // Still auto-tracking an unpublished draft with content.
56
+ // Still an unpublished draft keep tracking the source freely.
61
57
  return source ? await slugify(source) : null;
62
58
  };
63
59
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/fields/baseFields/slug/generateSlug.ts"],"sourcesContent":["import type { TypeWithID } from '../../../collections/config/types.js'\nimport type { FieldHook } from '../../config/types.js'\nimport type { Slugify } from './types.js'\n\nimport { hasAutosaveEnabled } from '../../../utilities/getVersionsConfig.js'\nimport { slugify as defaultSlugify } from '../../../utilities/slugify.js'\nimport { countVersions } from './countVersions.js'\n\ntype Args = {\n name: string\n slugify?: Slugify\n useAsSlug: string\n}\n\n/**\n * Field `beforeChange` hook for the native `slug` field. Returns the slug value.\n *\n * Auto-tracking is derived statelessly: the slug follows its source while it is\n * empty or still equals `slugify(storedSource)`. Once it diverges (the admin\n * overwrites it), it freezes and stays frozen, because the stored value keeps\n * differing from `slugify(source)`. Re-aligning (the UI generate button) resumes\n * tracking.\n */\nexport const generateSlug =\n ({ name, slugify: customSlugify, useAsSlug }: Args): FieldHook =>\n async ({ collection, data, global, operation, originalDoc, req, value }) => {\n const source = data?.[useAsSlug]\n\n const slugify = (valueToSlugify: unknown) =>\n customSlugify\n ? customSlugify({ data: (data ?? {}) as TypeWithID, req, valueToSlugify })\n : defaultSlugify(valueToSlugify as string)\n\n const entity = collection || global!\n\n if (operation === 'create') {\n // Autosave drafts: do not auto-generate on the initial draft the user is still entering content.\n // Keep the explicit non-slugified value (if any); generation begins on a later autosave.\n if (hasAutosaveEnabled(entity) && data?._status === 'draft') {\n return value || null\n }\n\n // Keep an explicitly provided slug; otherwise generate from the source.\n return await slugify(value || source)\n }\n\n const storedSlug = originalDoc?.[name]\n const originalSource = originalDoc?.[useAsSlug]\n\n // User explicitly edited the slug (or cleared the value): respect it.\n if (value !== undefined && value !== storedSlug) {\n return value\n }\n\n // No explicit edit this save. If the stored slug doesn't match what its source\n // would generate, it was customized on an earlier save — keep it frozen.\n const storedSlugIsCustom = storedSlug && storedSlug !== (await slugify(originalSource))\n\n if (storedSlugIsCustom) {\n return storedSlug\n }\n\n if (!hasAutosaveEnabled(entity)) {\n // Non-autosave: generate once while empty, then freeze.\n return storedSlug || (await slugify(source))\n }\n\n // Autosave / drafts\n const priorVersions = await countVersions({\n collectionSlug: collection?.slug,\n globalSlug: global?.slug,\n parentID: originalDoc?.id,\n req,\n })\n\n // Do not generate on the very first draft (no prior version yet).\n if (priorVersions === 0) {\n return storedSlug ?? null\n }\n\n // Stabilize after publish to protect live URLs.\n if (data?._status === 'published' || originalDoc?._status === 'published') {\n return storedSlug\n }\n\n // Still auto-tracking an unpublished draft with content.\n return source ? await slugify(source) : null\n }\n"],"names":["hasAutosaveEnabled","slugify","defaultSlugify","countVersions","generateSlug","name","customSlugify","useAsSlug","collection","data","global","operation","originalDoc","req","value","source","valueToSlugify","entity","_status","storedSlug","originalSource","undefined","storedSlugIsCustom","priorVersions","collectionSlug","slug","globalSlug","parentID","id"],"mappings":"AAIA,SAASA,kBAAkB,QAAQ,0CAAyC;AAC5E,SAASC,WAAWC,cAAc,QAAQ,gCAA+B;AACzE,SAASC,aAAa,QAAQ,qBAAoB;AAQlD;;;;;;;;CAQC,GACD,OAAO,MAAMC,eACX,CAAC,EAAEC,IAAI,EAAEJ,SAASK,aAAa,EAAEC,SAAS,EAAQ,GAClD,OAAO,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAEC,SAAS,EAAEC,WAAW,EAAEC,GAAG,EAAEC,KAAK,EAAE;QACrE,MAAMC,SAASN,MAAM,CAACF,UAAU;QAEhC,MAAMN,UAAU,CAACe,iBACfV,gBACIA,cAAc;gBAAEG,MAAOA,QAAQ,CAAC;gBAAkBI;gBAAKG;YAAe,KACtEd,eAAec;QAErB,MAAMC,SAAST,cAAcE;QAE7B,IAAIC,cAAc,UAAU;YAC1B,mGAAmG;YACnG,yFAAyF;YACzF,IAAIX,mBAAmBiB,WAAWR,MAAMS,YAAY,SAAS;gBAC3D,OAAOJ,SAAS;YAClB;YAEA,wEAAwE;YACxE,OAAO,MAAMb,QAAQa,SAASC;QAChC;QAEA,MAAMI,aAAaP,aAAa,CAACP,KAAK;QACtC,MAAMe,iBAAiBR,aAAa,CAACL,UAAU;QAE/C,sEAAsE;QACtE,IAAIO,UAAUO,aAAaP,UAAUK,YAAY;YAC/C,OAAOL;QACT;QAEA,+EAA+E;QAC/E,yEAAyE;QACzE,MAAMQ,qBAAqBH,cAAcA,eAAgB,MAAMlB,QAAQmB;QAEvE,IAAIE,oBAAoB;YACtB,OAAOH;QACT;QAEA,IAAI,CAACnB,mBAAmBiB,SAAS;YAC/B,wDAAwD;YACxD,OAAOE,cAAe,MAAMlB,QAAQc;QACtC;QAEA,oBAAoB;QACpB,MAAMQ,gBAAgB,MAAMpB,cAAc;YACxCqB,gBAAgBhB,YAAYiB;YAC5BC,YAAYhB,QAAQe;YACpBE,UAAUf,aAAagB;YACvBf;QACF;QAEA,kEAAkE;QAClE,IAAIU,kBAAkB,GAAG;YACvB,OAAOJ,cAAc;QACvB;QAEA,gDAAgD;QAChD,IAAIV,MAAMS,YAAY,eAAeN,aAAaM,YAAY,aAAa;YACzE,OAAOC;QACT;QAEA,yDAAyD;QACzD,OAAOJ,SAAS,MAAMd,QAAQc,UAAU;IAC1C,EAAC"}
1
+ {"version":3,"sources":["../../../../src/fields/baseFields/slug/generateSlug.ts"],"sourcesContent":["import type { TypeWithID } from '../../../collections/config/types.js'\nimport type { FieldHook } from '../../config/types.js'\nimport type { Slugify } from './types.js'\n\nimport { hasAutosaveEnabled } from '../../../utilities/getVersionsConfig.js'\nimport { slugify as defaultSlugify } from '../../../utilities/slugify.js'\n\ntype Args = {\n name: string\n slugify?: Slugify\n useAsSlug: string\n}\n\n/**\n * Field `beforeChange` hook for the native `slug` field. Returns the slug value.\n * - The slug value is derived from the `useAsSlug` source field,\n * but can be manually overridden by the admin.\n * - To protect live URLs, the slug is frozen after initial generation\n * unless the admin explicitly overwrites it.\n *\n * This is expressed as follows:\n *\n * Non-versioned and versioned-but-non-autosave collections:\n * - On create, generate from the source, keeping an explicitly provided value.\n * - On update, regenerate only while the stored slug is empty.\n * - Freeze on the first non-empty value, whether generated or manually provided.\n *\n * Autosave drafts:\n * - On every draft save (create and autosave) before publish, generate freely — a new\n * document gets a natural, live-updating slug while the admin is still entering content.\n * - Freeze on the first manual overwrite or the first publish. A mid-draft overwrite wins\n * immediately and is preserved across later autosaves.\n */\nexport const generateSlug =\n ({ name, slugify: customSlugify, useAsSlug }: Args): FieldHook =>\n async ({ collection, data, global, operation, originalDoc, req, value }) => {\n const source = data?.[useAsSlug]\n\n const slugify = (valueToSlugify: unknown) =>\n customSlugify\n ? customSlugify({ data: (data ?? {}) as TypeWithID, req, valueToSlugify })\n : defaultSlugify(valueToSlugify as string)\n\n const entity = collection || global!\n\n if (operation === 'create') {\n // Generate from the source (keeping an explicitly provided slug). On an autosave\n // collection the initial draft is created empty, so this yields an empty slug and\n // begins tracking as soon as content is entered.\n return await slugify(value || source)\n }\n\n const storedSlug = originalDoc?.[name]\n const originalSource = originalDoc?.[useAsSlug]\n\n // User explicitly edited the slug (or cleared the value) this save: respect it.\n if (value !== undefined && value !== storedSlug) {\n return value\n }\n\n // No explicit edit this save. If the stored slug doesn't match what its source\n // would generate, it was customized on an earlier save — keep it frozen.\n const storedSlugIsCustom = storedSlug && storedSlug !== (await slugify(originalSource))\n\n if (storedSlugIsCustom) {\n return storedSlug\n }\n\n if (!hasAutosaveEnabled(entity)) {\n // Non-autosave: generate once while empty, then freeze.\n return storedSlug || (await slugify(source))\n }\n\n // Autosave drafts: freeze once the document has been published to protect the live URL.\n if (data?._status === 'published' || originalDoc?._status === 'published') {\n return storedSlug\n }\n\n // Still an unpublished draft keep tracking the source freely.\n return source ? await slugify(source) : null\n }\n"],"names":["hasAutosaveEnabled","slugify","defaultSlugify","generateSlug","name","customSlugify","useAsSlug","collection","data","global","operation","originalDoc","req","value","source","valueToSlugify","entity","storedSlug","originalSource","undefined","storedSlugIsCustom","_status"],"mappings":"AAIA,SAASA,kBAAkB,QAAQ,0CAAyC;AAC5E,SAASC,WAAWC,cAAc,QAAQ,gCAA+B;AAQzE;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,MAAMC,eACX,CAAC,EAAEC,IAAI,EAAEH,SAASI,aAAa,EAAEC,SAAS,EAAQ,GAClD,OAAO,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAEC,SAAS,EAAEC,WAAW,EAAEC,GAAG,EAAEC,KAAK,EAAE;QACrE,MAAMC,SAASN,MAAM,CAACF,UAAU;QAEhC,MAAML,UAAU,CAACc,iBACfV,gBACIA,cAAc;gBAAEG,MAAOA,QAAQ,CAAC;gBAAkBI;gBAAKG;YAAe,KACtEb,eAAea;QAErB,MAAMC,SAAST,cAAcE;QAE7B,IAAIC,cAAc,UAAU;YAC1B,iFAAiF;YACjF,kFAAkF;YAClF,iDAAiD;YACjD,OAAO,MAAMT,QAAQY,SAASC;QAChC;QAEA,MAAMG,aAAaN,aAAa,CAACP,KAAK;QACtC,MAAMc,iBAAiBP,aAAa,CAACL,UAAU;QAE/C,gFAAgF;QAChF,IAAIO,UAAUM,aAAaN,UAAUI,YAAY;YAC/C,OAAOJ;QACT;QAEA,+EAA+E;QAC/E,yEAAyE;QACzE,MAAMO,qBAAqBH,cAAcA,eAAgB,MAAMhB,QAAQiB;QAEvE,IAAIE,oBAAoB;YACtB,OAAOH;QACT;QAEA,IAAI,CAACjB,mBAAmBgB,SAAS;YAC/B,wDAAwD;YACxD,OAAOC,cAAe,MAAMhB,QAAQa;QACtC;QAEA,wFAAwF;QACxF,IAAIN,MAAMa,YAAY,eAAeV,aAAaU,YAAY,aAAa;YACzE,OAAOJ;QACT;QAEA,gEAAgE;QAChE,OAAOH,SAAS,MAAMb,QAAQa,UAAU;IAC1C,EAAC"}