@depup/payload 3.81.0-depup.0 → 3.82.0-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +4 -4
  2. package/changes.json +3 -3
  3. package/dist/bin/generateTypes.d.ts.map +1 -1
  4. package/dist/bin/generateTypes.js +8 -0
  5. package/dist/bin/generateTypes.js.map +1 -1
  6. package/dist/collections/config/sanitize.d.ts +2 -1
  7. package/dist/collections/config/sanitize.d.ts.map +1 -1
  8. package/dist/collections/config/sanitize.js +4 -1
  9. package/dist/collections/config/sanitize.js.map +1 -1
  10. package/dist/collections/operations/utilities/update.d.ts.map +1 -1
  11. package/dist/collections/operations/utilities/update.js +2 -1
  12. package/dist/collections/operations/utilities/update.js.map +1 -1
  13. package/dist/config/orderable/index.d.ts +2 -10
  14. package/dist/config/orderable/index.d.ts.map +1 -1
  15. package/dist/config/orderable/index.js +20 -67
  16. package/dist/config/orderable/index.js.map +1 -1
  17. package/dist/config/sanitize.d.ts.map +1 -1
  18. package/dist/config/sanitize.js +45 -5
  19. package/dist/config/sanitize.js.map +1 -1
  20. package/dist/config/types.d.ts +20 -0
  21. package/dist/config/types.d.ts.map +1 -1
  22. package/dist/config/types.js.map +1 -1
  23. package/dist/fields/config/sanitize.d.ts +54 -2
  24. package/dist/fields/config/sanitize.d.ts.map +1 -1
  25. package/dist/fields/config/sanitize.js +333 -285
  26. package/dist/fields/config/sanitize.js.map +1 -1
  27. package/dist/fields/config/sanitize.spec.js +82 -0
  28. package/dist/fields/config/sanitize.spec.js.map +1 -1
  29. package/dist/fields/config/sanitizeJoinField.d.ts +15 -1
  30. package/dist/fields/config/sanitizeJoinField.d.ts.map +1 -1
  31. package/dist/fields/config/sanitizeJoinField.js +17 -1
  32. package/dist/fields/config/sanitizeJoinField.js.map +1 -1
  33. package/dist/globals/operations/findOne.d.ts +1 -0
  34. package/dist/globals/operations/findOne.d.ts.map +1 -1
  35. package/dist/globals/operations/findOne.js +10 -3
  36. package/dist/globals/operations/findOne.js.map +1 -1
  37. package/dist/globals/operations/local/findOne.d.ts +8 -0
  38. package/dist/globals/operations/local/findOne.d.ts.map +1 -1
  39. package/dist/globals/operations/local/findOne.js +2 -1
  40. package/dist/globals/operations/local/findOne.js.map +1 -1
  41. package/dist/globals/operations/update.d.ts.map +1 -1
  42. package/dist/globals/operations/update.js +2 -1
  43. package/dist/globals/operations/update.js.map +1 -1
  44. package/dist/index.bundled.d.ts +112 -18
  45. package/dist/index.d.ts +3 -2
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +1 -1
  48. package/dist/index.js.map +1 -1
  49. package/dist/uploads/checkFileAccess.d.ts +2 -1
  50. package/dist/uploads/checkFileAccess.d.ts.map +1 -1
  51. package/dist/uploads/checkFileAccess.js +25 -14
  52. package/dist/uploads/checkFileAccess.js.map +1 -1
  53. package/dist/uploads/checkFileAccess.spec.js +109 -0
  54. package/dist/uploads/checkFileAccess.spec.js.map +1 -0
  55. package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
  56. package/dist/uploads/endpoints/getFile.js +4 -1
  57. package/dist/uploads/endpoints/getFile.js.map +1 -1
  58. package/dist/uploads/types.d.ts +2 -1
  59. package/dist/uploads/types.d.ts.map +1 -1
  60. package/dist/uploads/types.js.map +1 -1
  61. package/dist/utilities/slugify.d.ts.map +1 -1
  62. package/dist/utilities/slugify.js +1 -1
  63. package/dist/utilities/slugify.js.map +1 -1
  64. package/dist/utilities/validateTimezones.d.ts.map +1 -1
  65. package/dist/utilities/validateTimezones.js +7 -0
  66. package/dist/utilities/validateTimezones.js.map +1 -1
  67. package/dist/versions/types.d.ts +1 -1
  68. package/dist/versions/types.js.map +1 -1
  69. package/package.json +8 -8
@@ -0,0 +1,109 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ vi.mock('../auth/executeAccess.js', ()=>({
3
+ executeAccess: vi.fn()
4
+ }));
5
+ import { executeAccess } from '../auth/executeAccess.js';
6
+ import { checkFileAccess } from './checkFileAccess.js';
7
+ const makeFindOne = (result = {
8
+ id: '1',
9
+ filename: 'logo.png'
10
+ })=>vi.fn().mockResolvedValue(result);
11
+ const makeCollection = ()=>({
12
+ config: {
13
+ slug: 'test-media',
14
+ access: {
15
+ read: vi.fn()
16
+ },
17
+ upload: {}
18
+ }
19
+ });
20
+ const makeReq = (findOne)=>({
21
+ t: vi.fn(),
22
+ payload: {
23
+ db: {
24
+ findOne
25
+ }
26
+ }
27
+ });
28
+ describe('checkFileAccess', ()=>{
29
+ beforeEach(()=>{
30
+ vi.mocked(executeAccess).mockResolvedValue({});
31
+ });
32
+ describe('prefix filtering', ()=>{
33
+ it('should add prefix clause to where query when prefix is provided', async ()=>{
34
+ const findOne = makeFindOne();
35
+ const req = makeReq(findOne);
36
+ const collection = makeCollection();
37
+ await checkFileAccess({
38
+ collection,
39
+ filename: 'logo.png',
40
+ prefix: 'abc123',
41
+ req
42
+ });
43
+ const whereArg = findOne.mock.calls[0]?.[0]?.where;
44
+ expect(whereArg?.and).toEqual(expect.arrayContaining([
45
+ {
46
+ prefix: {
47
+ equals: 'abc123'
48
+ }
49
+ }
50
+ ]));
51
+ });
52
+ it('should not add prefix clause to where query when prefix is omitted', async ()=>{
53
+ const findOne = makeFindOne();
54
+ const req = makeReq(findOne);
55
+ const collection = makeCollection();
56
+ await checkFileAccess({
57
+ collection,
58
+ filename: 'logo.png',
59
+ req
60
+ });
61
+ const whereArg = findOne.mock.calls[0]?.[0]?.where;
62
+ const hasPrefixCondition = whereArg?.and?.some((clause)=>'prefix' in clause);
63
+ expect(hasPrefixCondition).toBeFalsy();
64
+ });
65
+ it('should still include filename in where query when prefix is provided', async ()=>{
66
+ const findOne = makeFindOne();
67
+ const req = makeReq(findOne);
68
+ const collection = makeCollection();
69
+ await checkFileAccess({
70
+ collection,
71
+ filename: 'logo.png',
72
+ prefix: 'abc123',
73
+ req
74
+ });
75
+ const whereArg = findOne.mock.calls[0]?.[0]?.where;
76
+ const filenameCondition = whereArg?.and?.[0];
77
+ expect(filenameCondition?.or).toEqual(expect.arrayContaining([
78
+ {
79
+ filename: {
80
+ equals: 'logo.png'
81
+ }
82
+ }
83
+ ]));
84
+ });
85
+ it('should throw when no doc matches the given prefix', async ()=>{
86
+ const findOne = makeFindOne(null);
87
+ const req = makeReq(findOne);
88
+ const collection = makeCollection();
89
+ await expect(checkFileAccess({
90
+ collection,
91
+ filename: 'logo.png',
92
+ prefix: 'nonexistent',
93
+ req
94
+ })).rejects.toThrow();
95
+ });
96
+ it('should throw when filename contains path traversal sequence', async ()=>{
97
+ const findOne = makeFindOne();
98
+ const req = makeReq(findOne);
99
+ const collection = makeCollection();
100
+ await expect(checkFileAccess({
101
+ collection,
102
+ filename: '../etc/passwd',
103
+ req
104
+ })).rejects.toThrow();
105
+ });
106
+ });
107
+ });
108
+
109
+ //# sourceMappingURL=checkFileAccess.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/checkFileAccess.spec.ts"],"sourcesContent":["import { beforeEach, describe, expect, it, vi } from 'vitest'\n\nimport type { Collection } from '../collections/config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nvi.mock('../auth/executeAccess.js', () => ({\n executeAccess: vi.fn(),\n}))\n\nimport { executeAccess } from '../auth/executeAccess.js'\n\nimport { checkFileAccess } from './checkFileAccess.js'\n\nconst makeFindOne = (result: unknown = { id: '1', filename: 'logo.png' }) =>\n vi.fn().mockResolvedValue(result)\n\nconst makeCollection = (): Collection =>\n ({\n config: {\n slug: 'test-media',\n access: { read: vi.fn() },\n upload: {},\n },\n }) as unknown as Collection\n\nconst makeReq = (findOne: ReturnType<typeof vi.fn>): PayloadRequest =>\n ({\n t: vi.fn(),\n payload: {\n db: { findOne },\n },\n }) as unknown as PayloadRequest\n\ndescribe('checkFileAccess', () => {\n beforeEach(() => {\n vi.mocked(executeAccess).mockResolvedValue({})\n })\n\n describe('prefix filtering', () => {\n it('should add prefix clause to where query when prefix is provided', async () => {\n const findOne = makeFindOne()\n const req = makeReq(findOne)\n const collection = makeCollection()\n\n await checkFileAccess({ collection, filename: 'logo.png', prefix: 'abc123', req })\n\n const whereArg = findOne.mock.calls[0]?.[0]?.where\n expect(whereArg?.and).toEqual(expect.arrayContaining([{ prefix: { equals: 'abc123' } }]))\n })\n\n it('should not add prefix clause to where query when prefix is omitted', async () => {\n const findOne = makeFindOne()\n const req = makeReq(findOne)\n const collection = makeCollection()\n\n await checkFileAccess({ collection, filename: 'logo.png', req })\n\n const whereArg = findOne.mock.calls[0]?.[0]?.where\n const hasPrefixCondition = whereArg?.and?.some(\n (clause: Record<string, unknown>) => 'prefix' in clause,\n )\n expect(hasPrefixCondition).toBeFalsy()\n })\n\n it('should still include filename in where query when prefix is provided', async () => {\n const findOne = makeFindOne()\n const req = makeReq(findOne)\n const collection = makeCollection()\n\n await checkFileAccess({ collection, filename: 'logo.png', prefix: 'abc123', req })\n\n const whereArg = findOne.mock.calls[0]?.[0]?.where\n const filenameCondition = whereArg?.and?.[0]\n expect(filenameCondition?.or).toEqual(\n expect.arrayContaining([{ filename: { equals: 'logo.png' } }]),\n )\n })\n\n it('should throw when no doc matches the given prefix', async () => {\n const findOne = makeFindOne(null)\n const req = makeReq(findOne)\n const collection = makeCollection()\n\n await expect(\n checkFileAccess({ collection, filename: 'logo.png', prefix: 'nonexistent', req }),\n ).rejects.toThrow()\n })\n\n it('should throw when filename contains path traversal sequence', async () => {\n const findOne = makeFindOne()\n const req = makeReq(findOne)\n const collection = makeCollection()\n\n await expect(\n checkFileAccess({ collection, filename: '../etc/passwd', req }),\n ).rejects.toThrow()\n })\n })\n})\n"],"names":["beforeEach","describe","expect","it","vi","mock","executeAccess","fn","checkFileAccess","makeFindOne","result","id","filename","mockResolvedValue","makeCollection","config","slug","access","read","upload","makeReq","findOne","t","payload","db","mocked","req","collection","prefix","whereArg","calls","where","and","toEqual","arrayContaining","equals","hasPrefixCondition","some","clause","toBeFalsy","filenameCondition","or","rejects","toThrow"],"mappings":"AAAA,SAASA,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAQ;AAK7DA,GAAGC,IAAI,CAAC,4BAA4B,IAAO,CAAA;QACzCC,eAAeF,GAAGG,EAAE;IACtB,CAAA;AAEA,SAASD,aAAa,QAAQ,2BAA0B;AAExD,SAASE,eAAe,QAAQ,uBAAsB;AAEtD,MAAMC,cAAc,CAACC,SAAkB;IAAEC,IAAI;IAAKC,UAAU;AAAW,CAAC,GACtER,GAAGG,EAAE,GAAGM,iBAAiB,CAACH;AAE5B,MAAMI,iBAAiB,IACpB,CAAA;QACCC,QAAQ;YACNC,MAAM;YACNC,QAAQ;gBAAEC,MAAMd,GAAGG,EAAE;YAAG;YACxBY,QAAQ,CAAC;QACX;IACF,CAAA;AAEF,MAAMC,UAAU,CAACC,UACd,CAAA;QACCC,GAAGlB,GAAGG,EAAE;QACRgB,SAAS;YACPC,IAAI;gBAAEH;YAAQ;QAChB;IACF,CAAA;AAEFpB,SAAS,mBAAmB;IAC1BD,WAAW;QACTI,GAAGqB,MAAM,CAACnB,eAAeO,iBAAiB,CAAC,CAAC;IAC9C;IAEAZ,SAAS,oBAAoB;QAC3BE,GAAG,mEAAmE;YACpE,MAAMkB,UAAUZ;YAChB,MAAMiB,MAAMN,QAAQC;YACpB,MAAMM,aAAab;YAEnB,MAAMN,gBAAgB;gBAAEmB;gBAAYf,UAAU;gBAAYgB,QAAQ;gBAAUF;YAAI;YAEhF,MAAMG,WAAWR,QAAQhB,IAAI,CAACyB,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAEC;YAC7C7B,OAAO2B,UAAUG,KAAKC,OAAO,CAAC/B,OAAOgC,eAAe,CAAC;gBAAC;oBAAEN,QAAQ;wBAAEO,QAAQ;oBAAS;gBAAE;aAAE;QACzF;QAEAhC,GAAG,sEAAsE;YACvE,MAAMkB,UAAUZ;YAChB,MAAMiB,MAAMN,QAAQC;YACpB,MAAMM,aAAab;YAEnB,MAAMN,gBAAgB;gBAAEmB;gBAAYf,UAAU;gBAAYc;YAAI;YAE9D,MAAMG,WAAWR,QAAQhB,IAAI,CAACyB,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAEC;YAC7C,MAAMK,qBAAqBP,UAAUG,KAAKK,KACxC,CAACC,SAAoC,YAAYA;YAEnDpC,OAAOkC,oBAAoBG,SAAS;QACtC;QAEApC,GAAG,wEAAwE;YACzE,MAAMkB,UAAUZ;YAChB,MAAMiB,MAAMN,QAAQC;YACpB,MAAMM,aAAab;YAEnB,MAAMN,gBAAgB;gBAAEmB;gBAAYf,UAAU;gBAAYgB,QAAQ;gBAAUF;YAAI;YAEhF,MAAMG,WAAWR,QAAQhB,IAAI,CAACyB,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAEC;YAC7C,MAAMS,oBAAoBX,UAAUG,KAAK,CAAC,EAAE;YAC5C9B,OAAOsC,mBAAmBC,IAAIR,OAAO,CACnC/B,OAAOgC,eAAe,CAAC;gBAAC;oBAAEtB,UAAU;wBAAEuB,QAAQ;oBAAW;gBAAE;aAAE;QAEjE;QAEAhC,GAAG,qDAAqD;YACtD,MAAMkB,UAAUZ,YAAY;YAC5B,MAAMiB,MAAMN,QAAQC;YACpB,MAAMM,aAAab;YAEnB,MAAMZ,OACJM,gBAAgB;gBAAEmB;gBAAYf,UAAU;gBAAYgB,QAAQ;gBAAeF;YAAI,IAC/EgB,OAAO,CAACC,OAAO;QACnB;QAEAxC,GAAG,+DAA+D;YAChE,MAAMkB,UAAUZ;YAChB,MAAMiB,MAAMN,QAAQC;YACpB,MAAMM,aAAab;YAEnB,MAAMZ,OACJM,gBAAgB;gBAAEmB;gBAAYf,UAAU;gBAAiBc;YAAI,IAC7DgB,OAAO,CAACC,OAAO;QACnB;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"getFile.d.ts","sourceRoot":"","sources":["../../../src/uploads/endpoints/getFile.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAU3D,eAAO,MAAM,cAAc,EAAE,cA0J5B,CAAA"}
1
+ {"version":3,"file":"getFile.d.ts","sourceRoot":"","sources":["../../../src/uploads/endpoints/getFile.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAU3D,eAAO,MAAM,cAAc,EAAE,cA6J5B,CAAA"}
@@ -12,12 +12,14 @@ import { headersWithCors } from '../../utilities/headersWithCors.js';
12
12
  export const getFileHandler = async (req)=>{
13
13
  const collection = getRequestCollection(req);
14
14
  const filename = req.routeParams?.filename;
15
+ const prefix = req.searchParams?.get('prefix') ?? undefined;
15
16
  if (!collection.config.upload) {
16
17
  throw new APIError(`This collection is not an upload collection: ${collection.config.slug}`, httpStatus.BAD_REQUEST);
17
18
  }
18
19
  const accessResult = await checkFileAccess({
19
20
  collection,
20
21
  filename,
22
+ prefix,
21
23
  req
22
24
  });
23
25
  if (accessResult instanceof Response) {
@@ -32,7 +34,8 @@ export const getFileHandler = async (req)=>{
32
34
  headers,
33
35
  params: {
34
36
  collection: collection.config.slug,
35
- filename
37
+ filename,
38
+ prefix
36
39
  }
37
40
  });
38
41
  if (customResponse && customResponse instanceof Response) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/uploads/endpoints/getFile.ts"],"sourcesContent":["import type { Stats } from 'fs'\n\nimport { fileTypeFromFile } from 'file-type'\nimport fsPromises from 'fs/promises'\nimport { status as httpStatus } from 'http-status'\nimport path from 'path'\n\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { APIError } from '../../errors/APIError.js'\nimport { checkFileAccess } from '../../uploads/checkFileAccess.js'\nimport { streamFile } from '../../uploads/fetchAPI-stream-file/index.js'\nimport { getFileTypeFallback } from '../../uploads/getFileTypeFallback.js'\nimport { parseRangeHeader } from '../../uploads/parseRangeHeader.js'\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\n\nexport const getFileHandler: PayloadHandler = async (req) => {\n const collection = getRequestCollection(req)\n\n const filename = req.routeParams?.filename as string\n\n if (!collection.config.upload) {\n throw new APIError(\n `This collection is not an upload collection: ${collection.config.slug}`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n const accessResult = (await checkFileAccess({\n collection,\n filename,\n req,\n }))!\n\n if (accessResult instanceof Response) {\n return accessResult\n }\n\n if (collection.config.upload.handlers?.length) {\n let customResponse: null | Response | void = null\n const headers = new Headers()\n\n for (const handler of collection.config.upload.handlers) {\n customResponse = await handler(req, {\n doc: accessResult,\n headers,\n params: {\n collection: collection.config.slug,\n filename,\n },\n })\n if (customResponse && customResponse instanceof Response) {\n break\n }\n }\n\n if (customResponse instanceof Response) {\n return customResponse\n }\n }\n\n // Local filesystem fallback — cloud storage handlers return a Response above\n // and have their own filename validation via sanitizeFilename.\n const fileDir = collection.config.upload?.staticDir || collection.config.slug\n const resolvedDir = path.resolve(fileDir)\n const filePath = path.resolve(resolvedDir, filename)\n\n if (!filePath.startsWith(resolvedDir + path.sep)) {\n throw new APIError('Invalid filename.', httpStatus.BAD_REQUEST)\n }\n\n let stats: Stats\n\n try {\n stats = await fsPromises.stat(filePath)\n } catch (err) {\n if ((err as { code?: string }).code === 'ENOENT') {\n req.payload.logger.error(\n `File ${filename} for collection ${collection.config.slug} is missing on the disk. Expected path: ${filePath}`,\n )\n\n // Omit going to the routeError handler by returning response instead of\n // throwing an error to cut down log noise. The response still matches what you get with APIError to not leak details to the user.\n return Response.json(\n {\n errors: [\n {\n message: 'Something went wrong.',\n },\n ],\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: 500,\n },\n )\n }\n\n throw err\n }\n\n const fileTypeResult = (await fileTypeFromFile(filePath)) || getFileTypeFallback(filePath)\n let mimeType = fileTypeResult.mime\n\n if (filePath.endsWith('.svg') && fileTypeResult.mime === 'application/xml') {\n mimeType = 'image/svg+xml'\n }\n\n // Parse Range header for byte range requests\n const rangeHeader = req.headers.get('range')\n const rangeResult = parseRangeHeader({\n fileSize: stats.size,\n rangeHeader,\n })\n\n if (rangeResult.type === 'invalid') {\n let headers = new Headers()\n headers.set('Content-Range', `bytes */${stats.size}`)\n headers = collection.config.upload?.modifyResponseHeaders\n ? collection.config.upload.modifyResponseHeaders({ headers }) || headers\n : headers\n\n return new Response(null, {\n headers: headersWithCors({\n headers,\n req,\n }),\n status: httpStatus.REQUESTED_RANGE_NOT_SATISFIABLE,\n })\n }\n\n let headers = new Headers()\n headers.set('Content-Type', mimeType)\n headers.set('Accept-Ranges', 'bytes')\n\n if (mimeType === 'image/svg+xml') {\n headers.set('Content-Security-Policy', \"script-src 'none'\")\n }\n\n let data: ReadableStream\n let status: number\n const isPartial = rangeResult.type === 'partial'\n const range = rangeResult.range\n\n if (isPartial && range) {\n const contentLength = range.end - range.start + 1\n headers.set('Content-Length', String(contentLength))\n headers.set('Content-Range', `bytes ${range.start}-${range.end}/${stats.size}`)\n data = streamFile({ filePath, options: { end: range.end, start: range.start } })\n status = httpStatus.PARTIAL_CONTENT\n } else {\n headers.set('Content-Length', String(stats.size))\n data = streamFile({ filePath })\n status = httpStatus.OK\n }\n\n headers = collection.config.upload?.modifyResponseHeaders\n ? collection.config.upload.modifyResponseHeaders({ headers }) || headers\n : headers\n\n return new Response(data, {\n headers: headersWithCors({\n headers,\n req,\n }),\n status,\n })\n}\n"],"names":["fileTypeFromFile","fsPromises","status","httpStatus","path","APIError","checkFileAccess","streamFile","getFileTypeFallback","parseRangeHeader","getRequestCollection","headersWithCors","getFileHandler","req","collection","filename","routeParams","config","upload","slug","BAD_REQUEST","accessResult","Response","handlers","length","customResponse","headers","Headers","handler","doc","params","fileDir","staticDir","resolvedDir","resolve","filePath","startsWith","sep","stats","stat","err","code","payload","logger","error","json","errors","message","fileTypeResult","mimeType","mime","endsWith","rangeHeader","get","rangeResult","fileSize","size","type","set","modifyResponseHeaders","REQUESTED_RANGE_NOT_SATISFIABLE","data","isPartial","range","contentLength","end","start","String","options","PARTIAL_CONTENT","OK"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/uploads/endpoints/getFile.ts"],"sourcesContent":["import type { Stats } from 'fs'\n\nimport { fileTypeFromFile } from 'file-type'\nimport fsPromises from 'fs/promises'\nimport { status as httpStatus } from 'http-status'\nimport path from 'path'\n\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { APIError } from '../../errors/APIError.js'\nimport { checkFileAccess } from '../../uploads/checkFileAccess.js'\nimport { streamFile } from '../../uploads/fetchAPI-stream-file/index.js'\nimport { getFileTypeFallback } from '../../uploads/getFileTypeFallback.js'\nimport { parseRangeHeader } from '../../uploads/parseRangeHeader.js'\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\n\nexport const getFileHandler: PayloadHandler = async (req) => {\n const collection = getRequestCollection(req)\n\n const filename = req.routeParams?.filename as string\n const prefix = req.searchParams?.get('prefix') ?? undefined\n\n if (!collection.config.upload) {\n throw new APIError(\n `This collection is not an upload collection: ${collection.config.slug}`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n const accessResult = (await checkFileAccess({\n collection,\n filename,\n prefix,\n req,\n }))!\n\n if (accessResult instanceof Response) {\n return accessResult\n }\n\n if (collection.config.upload.handlers?.length) {\n let customResponse: null | Response | void = null\n const headers = new Headers()\n\n for (const handler of collection.config.upload.handlers) {\n customResponse = await handler(req, {\n doc: accessResult,\n headers,\n params: {\n collection: collection.config.slug,\n filename,\n prefix,\n },\n })\n if (customResponse && customResponse instanceof Response) {\n break\n }\n }\n\n if (customResponse instanceof Response) {\n return customResponse\n }\n }\n\n // Local filesystem fallback — cloud storage handlers return a Response above\n // and have their own filename validation via sanitizeFilename.\n const fileDir = collection.config.upload?.staticDir || collection.config.slug\n const resolvedDir = path.resolve(fileDir)\n const filePath = path.resolve(resolvedDir, filename)\n\n if (!filePath.startsWith(resolvedDir + path.sep)) {\n throw new APIError('Invalid filename.', httpStatus.BAD_REQUEST)\n }\n\n let stats: Stats\n\n try {\n stats = await fsPromises.stat(filePath)\n } catch (err) {\n if ((err as { code?: string }).code === 'ENOENT') {\n req.payload.logger.error(\n `File ${filename} for collection ${collection.config.slug} is missing on the disk. Expected path: ${filePath}`,\n )\n\n // Omit going to the routeError handler by returning response instead of\n // throwing an error to cut down log noise. The response still matches what you get with APIError to not leak details to the user.\n return Response.json(\n {\n errors: [\n {\n message: 'Something went wrong.',\n },\n ],\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: 500,\n },\n )\n }\n\n throw err\n }\n\n const fileTypeResult = (await fileTypeFromFile(filePath)) || getFileTypeFallback(filePath)\n let mimeType = fileTypeResult.mime\n\n if (filePath.endsWith('.svg') && fileTypeResult.mime === 'application/xml') {\n mimeType = 'image/svg+xml'\n }\n\n // Parse Range header for byte range requests\n const rangeHeader = req.headers.get('range')\n const rangeResult = parseRangeHeader({\n fileSize: stats.size,\n rangeHeader,\n })\n\n if (rangeResult.type === 'invalid') {\n let headers = new Headers()\n headers.set('Content-Range', `bytes */${stats.size}`)\n headers = collection.config.upload?.modifyResponseHeaders\n ? collection.config.upload.modifyResponseHeaders({ headers }) || headers\n : headers\n\n return new Response(null, {\n headers: headersWithCors({\n headers,\n req,\n }),\n status: httpStatus.REQUESTED_RANGE_NOT_SATISFIABLE,\n })\n }\n\n let headers = new Headers()\n headers.set('Content-Type', mimeType)\n headers.set('Accept-Ranges', 'bytes')\n\n if (mimeType === 'image/svg+xml') {\n headers.set('Content-Security-Policy', \"script-src 'none'\")\n }\n\n let data: ReadableStream\n let status: number\n const isPartial = rangeResult.type === 'partial'\n const range = rangeResult.range\n\n if (isPartial && range) {\n const contentLength = range.end - range.start + 1\n headers.set('Content-Length', String(contentLength))\n headers.set('Content-Range', `bytes ${range.start}-${range.end}/${stats.size}`)\n data = streamFile({ filePath, options: { end: range.end, start: range.start } })\n status = httpStatus.PARTIAL_CONTENT\n } else {\n headers.set('Content-Length', String(stats.size))\n data = streamFile({ filePath })\n status = httpStatus.OK\n }\n\n headers = collection.config.upload?.modifyResponseHeaders\n ? collection.config.upload.modifyResponseHeaders({ headers }) || headers\n : headers\n\n return new Response(data, {\n headers: headersWithCors({\n headers,\n req,\n }),\n status,\n })\n}\n"],"names":["fileTypeFromFile","fsPromises","status","httpStatus","path","APIError","checkFileAccess","streamFile","getFileTypeFallback","parseRangeHeader","getRequestCollection","headersWithCors","getFileHandler","req","collection","filename","routeParams","prefix","searchParams","get","undefined","config","upload","slug","BAD_REQUEST","accessResult","Response","handlers","length","customResponse","headers","Headers","handler","doc","params","fileDir","staticDir","resolvedDir","resolve","filePath","startsWith","sep","stats","stat","err","code","payload","logger","error","json","errors","message","fileTypeResult","mimeType","mime","endsWith","rangeHeader","rangeResult","fileSize","size","type","set","modifyResponseHeaders","REQUESTED_RANGE_NOT_SATISFIABLE","data","isPartial","range","contentLength","end","start","String","options","PARTIAL_CONTENT","OK"],"mappings":"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"}
@@ -209,7 +209,7 @@ export type UploadConfig = {
209
209
  filesRequiredOnCreate?: boolean;
210
210
  /**
211
211
  * Enables focal point positioning for image manipulation.
212
- * @default false
212
+ * @default true
213
213
  */
214
214
  focalPoint?: boolean;
215
215
  /**
@@ -233,6 +233,7 @@ export type UploadConfig = {
233
233
  clientUploadContext?: unknown;
234
234
  collection: string;
235
235
  filename: string;
236
+ prefix?: string;
236
237
  };
237
238
  }) => Promise<Response> | Promise<void> | Response | void)[];
238
239
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/uploads/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/uploads/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/types.ts"],"sourcesContent":["import type { ResizeOptions, Sharp, SharpOptions } from 'sharp'\n\nimport type { CollectionConfig, TypeWithID } from '../collections/config/types.js'\nimport type { PayloadComponent } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { WithMetadata } from './optionallyAppendMetadata.js'\n\nexport type FileSize = {\n filename: null | string\n filesize: null | number\n height: null | number\n mimeType: null | string\n url?: null | string // TODO V4: make non-optional\n width: null | number\n}\n\n// TODO: deprecate in Payload v4.\n/**\n * FileSizeImproved is a more precise type, and will replace FileSize in Payload v4.\n * This type is for internal use only as it will be deprecated in the future.\n * @internal\n */\nexport type FileSizeImproved = {\n url: null | string\n} & FileSize\n\nexport type FileSizes = {\n [size: string]: FileSize\n}\n\nexport type FileData = {\n filename: string\n filesize: number\n focalX?: number\n focalY?: number\n height: number\n mimeType: string\n sizes: FileSizes\n tempFilePath?: string\n url?: string\n width: number\n}\n\nexport type ProbedImageSize = {\n height: number\n width: number\n}\n\n/**\n * Params sent to the sharp `toFormat()` function\n * @link https://sharp.pixelplumbing.com/api-output#toformat\n */\nexport type ImageUploadFormatOptions = {\n format: Parameters<Sharp['toFormat']>[0]\n options?: Parameters<Sharp['toFormat']>[1]\n}\n\n/**\n * Params sent to the sharp trim() function\n * @link https://sharp.pixelplumbing.com/api-resize#trim\n */\nexport type ImageUploadTrimOptions = Parameters<Sharp['trim']>[0]\n\nexport type GenerateImageName = (args: {\n extension: string\n height: number\n originalName: string\n sizeName: string\n width: number\n}) => string\n\nexport type ImageSize = {\n /**\n * Admin UI options that control how this image size appears in list views.\n *\n * NOTE: In Payload v4, these options (`disableGroupBy`, `disableListColumn` and `disableListFilter`)\n * should default to `true` so image size subfields are hidden from list columns\n * and filters by default, reducing noise in the admin UI.\n */\n admin?: {\n /**\n * If set to true, this image size will not be available\n * as a selectable groupBy option in the collection list view.\n * @default false\n */\n disableGroupBy?: boolean\n /**\n * If set to true, this image size will not be available\n * as a selectable column in the collection list view.\n * @default false\n */\n disableListColumn?: boolean\n /**\n * If set to true, this image size will not be available\n * as a filter option in the collection list view.\n * @default false\n */\n disableListFilter?: boolean\n }\n /**\n * @deprecated prefer position\n */\n crop?: string // comes from sharp package\n formatOptions?: ImageUploadFormatOptions\n /**\n * Generate a custom name for the file of this image size.\n */\n generateImageName?: GenerateImageName\n name: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * When an uploaded image is smaller than the defined image size, we have 3 options:\n *\n * `undefined | false | true`\n *\n * 1. `undefined` [default]: uploading images with smaller width AND height than the image size will return null\n * 2. `false`: always enlarge images to the image size\n * 3. `true`: if the image is smaller than the image size, return the original image\n */\n withoutEnlargement?: ResizeOptions['withoutEnlargement']\n} & Omit<ResizeOptions, 'withoutEnlargement'>\n\nexport type GetAdminThumbnail = (args: { doc: Record<string, unknown> }) => false | null | string\n\nexport type AllowList = Array<{\n hostname: string\n pathname?: string\n port?: string\n protocol?: 'http' | 'https'\n search?: string\n}>\n\nexport type FileAllowList = Array<{\n extensions: string[]\n mimeType: string\n}>\n\ntype Admin = {\n components?: {\n /**\n * The Controls component to extend the upload controls in the admin panel.\n */\n controls?: PayloadComponent[]\n }\n}\n\nexport type UploadConfig = {\n /**\n * The adapter name to use for uploads. Used for storage adapter telemetry.\n * @default undefined\n */\n adapter?: string\n /**\n * The admin configuration for the upload field.\n */\n admin?: Admin\n /**\n * Represents an admin thumbnail, which can be either a React component or a string.\n * - If a string, it should be one of the image size names.\n * - A function that generates a fully qualified URL for the thumbnail, receives the doc as the only argument.\n **/\n adminThumbnail?: GetAdminThumbnail | string\n /**\n * Allow restricted file types known to be problematic.\n * - If set to `true`, it will allow all file types.\n * - If set to `false`, it will not allow file types and extensions known to be problematic.\n * - This setting is overriden by the `mimeTypes` option.\n * @default false\n */\n allowRestrictedFileTypes?: boolean\n /**\n * Enables bulk upload of files from the list view.\n * @default true\n */\n bulkUpload?: boolean\n /**\n * Appends a cache tag to the image URL when fetching the thumbnail in the admin panel. It may be desirable to disable this when hosting via CDNs with strict parameters.\n *\n * @default true\n */\n cacheTags?: boolean\n /**\n * Sharp constructor options to be passed to the uploaded file.\n * @link https://sharp.pixelplumbing.com/api-constructor/#sharp\n */\n constructorOptions?: SharpOptions\n /**\n * Enables cropping of images.\n * @default true\n */\n crop?: boolean\n /**\n * Disable the ability to save files to disk.\n * @default false\n */\n disableLocalStorage?: boolean\n /**\n * Enable displaying preview of the uploaded file in Upload fields related to this Collection.\n * Can be locally overridden by `displayPreview` option in Upload field.\n * @default false\n */\n displayPreview?: boolean\n /**\n *\n * Accepts existing headers and returns the headers after filtering or modifying.\n * If using this option, you should handle the removal of any sensitive cookies\n * (like payload-prefixed cookies) to prevent leaking session information to external\n * services. By default, Payload automatically filters out payload-prefixed cookies\n * when this option is NOT defined.\n *\n * Useful for adding custom headers to fetch from external providers.\n * @default undefined\n */\n externalFileHeaderFilter?: (headers: Record<string, string>) => Record<string, string>\n /**\n * Field slugs to use for a compound index instead of the default filename index.\n */\n filenameCompoundIndex?: string[]\n /**\n * Require files to be uploaded when creating a document.\n * @default true\n */\n filesRequiredOnCreate?: boolean\n /**\n * Enables focal point positioning for image manipulation.\n * @default false\n */\n focalPoint?: boolean\n /**\n * Format options for the uploaded file. Formatting image sizes needs to be done within each formatOptions individually.\n */\n formatOptions?: ImageUploadFormatOptions\n /**\n * Custom handlers to run when a file is fetched.\n *\n * - If a handler returns a Response, the response will be sent to the client and no further handlers will be run.\n * - If a handler returns null, the next handler will be run.\n * - If no handlers return a response the file will be returned by default.\n *\n * @link https://sharp.pixelplumbing.com/api-output/#toformat\n * @default undefined\n */\n handlers?: ((\n req: PayloadRequest,\n args: {\n doc: TypeWithID\n headers?: Headers\n params: { clientUploadContext?: unknown; collection: string; filename: string }\n },\n ) => Promise<Response> | Promise<void> | Response | void)[]\n /**\n * Set to `true` to prevent the admin UI from showing file inputs during document creation, useful for programmatic file generation.\n */\n hideFileInputOnCreate?: boolean\n /**\n * Set to `true` to prevent the admin UI having a way to remove an existing file while editing.\n */\n hideRemoveFile?: boolean\n imageSizes?: ImageSize[]\n /**\n * Restrict mimeTypes in the file picker. Array of valid mime types or mimetype wildcards\n * @example ['image/*', 'application/pdf']\n * @default undefined\n */\n mimeTypes?: string[]\n /**\n * Ability to modify the response headers fetching a file.\n * @default undefined\n */\n modifyResponseHeaders?: ({ headers }: { headers: Headers }) => Headers | void\n /**\n * Controls the behavior of pasting/uploading files from URLs.\n * If set to `false`, fetching from remote URLs is disabled.\n * If an `allowList` is provided, server-side fetching will be enabled for specified URLs.\n *\n * @default true (client-side fetching enabled)\n */\n pasteURL?:\n | {\n allowList: AllowList\n }\n | false\n /**\n * Sharp resize options for the original image.\n * @link https://sharp.pixelplumbing.com/api-resize#resize\n * @default undefined\n */\n resizeOptions?: ResizeOptions\n /**\n * Skip safe fetch when using server-side fetching for external files from these URLs.\n * @default false\n */\n skipSafeFetch?: AllowList | boolean\n /**\n * The directory to serve static files from. Defaults to collection slug.\n * @default undefined\n */\n staticDir?: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * Optionally append metadata to the image during processing.\n *\n * Can be a boolean or a function.\n *\n * If true, metadata will be appended to the image.\n * If false, no metadata will be appended.\n * If a function, it will receive an object containing the metadata and should return a boolean indicating whether to append the metadata.\n * @default false\n */\n withMetadata?: WithMetadata\n}\nexport type checkFileRestrictionsParams = {\n collection: CollectionConfig\n file: File\n req: PayloadRequest\n}\n\nexport type SanitizedUploadConfig = {\n staticDir: UploadConfig['staticDir']\n} & UploadConfig\n\nexport type File = {\n /**\n * The buffer of the file.\n */\n data: Buffer\n /**\n * The mimetype of the file.\n */\n mimetype: string\n /**\n * The name of the file.\n */\n name: string\n /**\n * The size of the file in bytes.\n */\n size: number\n}\n\nexport type FileToSave = {\n /**\n * The buffer of the file.\n */\n buffer: Buffer\n /**\n * The path to save the file.\n */\n path: string\n}\n\ntype Crop = {\n height: number\n unit: '%' | 'px'\n width: number\n x: number\n y: number\n}\n\nexport type FocalPoint = {\n x: number\n y: number\n}\n\nexport type UploadEdits = {\n crop?: Crop\n focalPoint?: FocalPoint\n heightInPixels?: number\n widthInPixels?: number\n}\n"],"names":[],"mappings":"AA4WA,WAKC"}
1
+ {"version":3,"sources":["../../src/uploads/types.ts"],"sourcesContent":["import type { ResizeOptions, Sharp, SharpOptions } from 'sharp'\n\nimport type { CollectionConfig, TypeWithID } from '../collections/config/types.js'\nimport type { PayloadComponent } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { WithMetadata } from './optionallyAppendMetadata.js'\n\nexport type FileSize = {\n filename: null | string\n filesize: null | number\n height: null | number\n mimeType: null | string\n url?: null | string // TODO V4: make non-optional\n width: null | number\n}\n\n// TODO: deprecate in Payload v4.\n/**\n * FileSizeImproved is a more precise type, and will replace FileSize in Payload v4.\n * This type is for internal use only as it will be deprecated in the future.\n * @internal\n */\nexport type FileSizeImproved = {\n url: null | string\n} & FileSize\n\nexport type FileSizes = {\n [size: string]: FileSize\n}\n\nexport type FileData = {\n filename: string\n filesize: number\n focalX?: number\n focalY?: number\n height: number\n mimeType: string\n sizes: FileSizes\n tempFilePath?: string\n url?: string\n width: number\n}\n\nexport type ProbedImageSize = {\n height: number\n width: number\n}\n\n/**\n * Params sent to the sharp `toFormat()` function\n * @link https://sharp.pixelplumbing.com/api-output#toformat\n */\nexport type ImageUploadFormatOptions = {\n format: Parameters<Sharp['toFormat']>[0]\n options?: Parameters<Sharp['toFormat']>[1]\n}\n\n/**\n * Params sent to the sharp trim() function\n * @link https://sharp.pixelplumbing.com/api-resize#trim\n */\nexport type ImageUploadTrimOptions = Parameters<Sharp['trim']>[0]\n\nexport type GenerateImageName = (args: {\n extension: string\n height: number\n originalName: string\n sizeName: string\n width: number\n}) => string\n\nexport type ImageSize = {\n /**\n * Admin UI options that control how this image size appears in list views.\n *\n * NOTE: In Payload v4, these options (`disableGroupBy`, `disableListColumn` and `disableListFilter`)\n * should default to `true` so image size subfields are hidden from list columns\n * and filters by default, reducing noise in the admin UI.\n */\n admin?: {\n /**\n * If set to true, this image size will not be available\n * as a selectable groupBy option in the collection list view.\n * @default false\n */\n disableGroupBy?: boolean\n /**\n * If set to true, this image size will not be available\n * as a selectable column in the collection list view.\n * @default false\n */\n disableListColumn?: boolean\n /**\n * If set to true, this image size will not be available\n * as a filter option in the collection list view.\n * @default false\n */\n disableListFilter?: boolean\n }\n /**\n * @deprecated prefer position\n */\n crop?: string // comes from sharp package\n formatOptions?: ImageUploadFormatOptions\n /**\n * Generate a custom name for the file of this image size.\n */\n generateImageName?: GenerateImageName\n name: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * When an uploaded image is smaller than the defined image size, we have 3 options:\n *\n * `undefined | false | true`\n *\n * 1. `undefined` [default]: uploading images with smaller width AND height than the image size will return null\n * 2. `false`: always enlarge images to the image size\n * 3. `true`: if the image is smaller than the image size, return the original image\n */\n withoutEnlargement?: ResizeOptions['withoutEnlargement']\n} & Omit<ResizeOptions, 'withoutEnlargement'>\n\nexport type GetAdminThumbnail = (args: { doc: Record<string, unknown> }) => false | null | string\n\nexport type AllowList = Array<{\n hostname: string\n pathname?: string\n port?: string\n protocol?: 'http' | 'https'\n search?: string\n}>\n\nexport type FileAllowList = Array<{\n extensions: string[]\n mimeType: string\n}>\n\ntype Admin = {\n components?: {\n /**\n * The Controls component to extend the upload controls in the admin panel.\n */\n controls?: PayloadComponent[]\n }\n}\n\nexport type UploadConfig = {\n /**\n * The adapter name to use for uploads. Used for storage adapter telemetry.\n * @default undefined\n */\n adapter?: string\n /**\n * The admin configuration for the upload field.\n */\n admin?: Admin\n /**\n * Represents an admin thumbnail, which can be either a React component or a string.\n * - If a string, it should be one of the image size names.\n * - A function that generates a fully qualified URL for the thumbnail, receives the doc as the only argument.\n **/\n adminThumbnail?: GetAdminThumbnail | string\n /**\n * Allow restricted file types known to be problematic.\n * - If set to `true`, it will allow all file types.\n * - If set to `false`, it will not allow file types and extensions known to be problematic.\n * - This setting is overriden by the `mimeTypes` option.\n * @default false\n */\n allowRestrictedFileTypes?: boolean\n /**\n * Enables bulk upload of files from the list view.\n * @default true\n */\n bulkUpload?: boolean\n /**\n * Appends a cache tag to the image URL when fetching the thumbnail in the admin panel. It may be desirable to disable this when hosting via CDNs with strict parameters.\n *\n * @default true\n */\n cacheTags?: boolean\n /**\n * Sharp constructor options to be passed to the uploaded file.\n * @link https://sharp.pixelplumbing.com/api-constructor/#sharp\n */\n constructorOptions?: SharpOptions\n /**\n * Enables cropping of images.\n * @default true\n */\n crop?: boolean\n /**\n * Disable the ability to save files to disk.\n * @default false\n */\n disableLocalStorage?: boolean\n /**\n * Enable displaying preview of the uploaded file in Upload fields related to this Collection.\n * Can be locally overridden by `displayPreview` option in Upload field.\n * @default false\n */\n displayPreview?: boolean\n /**\n *\n * Accepts existing headers and returns the headers after filtering or modifying.\n * If using this option, you should handle the removal of any sensitive cookies\n * (like payload-prefixed cookies) to prevent leaking session information to external\n * services. By default, Payload automatically filters out payload-prefixed cookies\n * when this option is NOT defined.\n *\n * Useful for adding custom headers to fetch from external providers.\n * @default undefined\n */\n externalFileHeaderFilter?: (headers: Record<string, string>) => Record<string, string>\n /**\n * Field slugs to use for a compound index instead of the default filename index.\n */\n filenameCompoundIndex?: string[]\n /**\n * Require files to be uploaded when creating a document.\n * @default true\n */\n filesRequiredOnCreate?: boolean\n /**\n * Enables focal point positioning for image manipulation.\n * @default true\n */\n focalPoint?: boolean\n /**\n * Format options for the uploaded file. Formatting image sizes needs to be done within each formatOptions individually.\n */\n formatOptions?: ImageUploadFormatOptions\n /**\n * Custom handlers to run when a file is fetched.\n *\n * - If a handler returns a Response, the response will be sent to the client and no further handlers will be run.\n * - If a handler returns null, the next handler will be run.\n * - If no handlers return a response the file will be returned by default.\n *\n * @link https://sharp.pixelplumbing.com/api-output/#toformat\n * @default undefined\n */\n handlers?: ((\n req: PayloadRequest,\n args: {\n doc: TypeWithID\n headers?: Headers\n params: {\n clientUploadContext?: unknown\n collection: string\n filename: string\n prefix?: string\n }\n },\n ) => Promise<Response> | Promise<void> | Response | void)[]\n /**\n * Set to `true` to prevent the admin UI from showing file inputs during document creation, useful for programmatic file generation.\n */\n hideFileInputOnCreate?: boolean\n /**\n * Set to `true` to prevent the admin UI having a way to remove an existing file while editing.\n */\n hideRemoveFile?: boolean\n imageSizes?: ImageSize[]\n /**\n * Restrict mimeTypes in the file picker. Array of valid mime types or mimetype wildcards\n * @example ['image/*', 'application/pdf']\n * @default undefined\n */\n mimeTypes?: string[]\n /**\n * Ability to modify the response headers fetching a file.\n * @default undefined\n */\n modifyResponseHeaders?: ({ headers }: { headers: Headers }) => Headers | void\n /**\n * Controls the behavior of pasting/uploading files from URLs.\n * If set to `false`, fetching from remote URLs is disabled.\n * If an `allowList` is provided, server-side fetching will be enabled for specified URLs.\n *\n * @default true (client-side fetching enabled)\n */\n pasteURL?:\n | {\n allowList: AllowList\n }\n | false\n /**\n * Sharp resize options for the original image.\n * @link https://sharp.pixelplumbing.com/api-resize#resize\n * @default undefined\n */\n resizeOptions?: ResizeOptions\n /**\n * Skip safe fetch when using server-side fetching for external files from these URLs.\n * @default false\n */\n skipSafeFetch?: AllowList | boolean\n /**\n * The directory to serve static files from. Defaults to collection slug.\n * @default undefined\n */\n staticDir?: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * Optionally append metadata to the image during processing.\n *\n * Can be a boolean or a function.\n *\n * If true, metadata will be appended to the image.\n * If false, no metadata will be appended.\n * If a function, it will receive an object containing the metadata and should return a boolean indicating whether to append the metadata.\n * @default false\n */\n withMetadata?: WithMetadata\n}\nexport type checkFileRestrictionsParams = {\n collection: CollectionConfig\n file: File\n req: PayloadRequest\n}\n\nexport type SanitizedUploadConfig = {\n staticDir: UploadConfig['staticDir']\n} & UploadConfig\n\nexport type File = {\n /**\n * The buffer of the file.\n */\n data: Buffer\n /**\n * The mimetype of the file.\n */\n mimetype: string\n /**\n * The name of the file.\n */\n name: string\n /**\n * The size of the file in bytes.\n */\n size: number\n}\n\nexport type FileToSave = {\n /**\n * The buffer of the file.\n */\n buffer: Buffer\n /**\n * The path to save the file.\n */\n path: string\n}\n\ntype Crop = {\n height: number\n unit: '%' | 'px'\n width: number\n x: number\n y: number\n}\n\nexport type FocalPoint = {\n x: number\n y: number\n}\n\nexport type UploadEdits = {\n crop?: Crop\n focalPoint?: FocalPoint\n heightInPixels?: number\n widthInPixels?: number\n}\n"],"names":[],"mappings":"AAiXA,WAKC"}
@@ -1 +1 @@
1
- {"version":3,"file":"slugify.d.ts","sourceRoot":"","sources":["../../src/utilities/slugify.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,SAAU,MAAM,KAAG,MAAM,GAAG,SAI9B,CAAA"}
1
+ {"version":3,"file":"slugify.d.ts","sourceRoot":"","sources":["../../src/utilities/slugify.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,SAAU,MAAM,KAAG,MAAM,GAAG,SAK9B,CAAA"}
@@ -1,3 +1,3 @@
1
- export const slugify = (val)=>val?.replace(/ /g, '-').replace(/[^\w-]+/g, '').toLowerCase();
1
+ export const slugify = (val)=>val?.trim().replace(/ /g, '-').replace(/[^\w-]+/g, '').toLowerCase();
2
2
 
3
3
  //# sourceMappingURL=slugify.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/slugify.ts"],"sourcesContent":["export const slugify = (val?: string): string | undefined =>\n val\n ?.replace(/ /g, '-')\n .replace(/[^\\w-]+/g, '')\n .toLowerCase()\n"],"names":["slugify","val","replace","toLowerCase"],"mappings":"AAAA,OAAO,MAAMA,UAAU,CAACC,MACtBA,KACIC,QAAQ,MAAM,KACfA,QAAQ,YAAY,IACpBC,cAAa"}
1
+ {"version":3,"sources":["../../src/utilities/slugify.ts"],"sourcesContent":["export const slugify = (val?: string): string | undefined =>\n val\n ?.trim()\n .replace(/ /g, '-')\n .replace(/[^\\w-]+/g, '')\n .toLowerCase()\n"],"names":["slugify","val","trim","replace","toLowerCase"],"mappings":"AAAA,OAAO,MAAMA,UAAU,CAACC,MACtBA,KACIC,OACDC,QAAQ,MAAM,KACdA,QAAQ,YAAY,IACpBC,cAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"validateTimezones.d.ts","sourceRoot":"","sources":["../../src/utilities/validateTimezones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAIlD,KAAK,qBAAqB,GAAG;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAA;CAClC,CAAA;AAoED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,0BAA2B,qBAAqB,KAAG,IAahF,CAAA"}
1
+ {"version":3,"file":"validateTimezones.d.ts","sourceRoot":"","sources":["../../src/utilities/validateTimezones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAQlD,KAAK,qBAAqB,GAAG;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAA;CAClC,CAAA;AAoED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,0BAA2B,qBAAqB,KAAG,IAiBhF,CAAA"}
@@ -1,4 +1,7 @@
1
1
  import { InvalidConfiguration } from '../errors/index.js';
2
+ import { defaultTimezones } from '../fields/baseFields/timezone/defaultTimezones.js';
3
+ // Pre-computed Set of default timezone values - skip validation for these
4
+ const defaultTimezoneValues = new Set(defaultTimezones.map((tz)=>tz.value));
2
5
  /**
3
6
  * Validates a UTC offset string.
4
7
  * Only supports the ±HH:mm format (e.g., +05:30, -08:00).
@@ -66,6 +69,10 @@ import { InvalidConfiguration } from '../errors/index.js';
66
69
  return;
67
70
  }
68
71
  for (const timezone of timezones){
72
+ // Skip validation for known-valid default timezones
73
+ if (defaultTimezoneValues.has(timezone.value)) {
74
+ continue;
75
+ }
69
76
  if (!isTimezoneSupported(timezone.value)) {
70
77
  const sourceText = source ? ` in ${source}` : '';
71
78
  throw new InvalidConfiguration(`Timezone ${timezone.value}${sourceText} is not supported by the current runtime via the Intl API.`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/validateTimezones.ts"],"sourcesContent":["import type { Timezone } from '../config/types.js'\n\nimport { InvalidConfiguration } from '../errors/index.js'\n\ntype ValidateTimezonesArgs = {\n /**\n * The source of the timezones for error messaging\n */\n source?: string\n /**\n * Array of timezones to validate\n */\n timezones: Timezone[] | undefined\n}\n\n/**\n * Validates a UTC offset string.\n * Only supports the ±HH:mm format (e.g., +05:30, -08:00).\n *\n * Valid ranges: hours -12 to +14, minutes 0-59\n *\n * @returns true if the offset is valid\n */\nconst isValidUtcOffset = (value: string): boolean => {\n // Strict format check: only ±HH:mm\n const match = value.match(/^([+-])(\\d{2}):(\\d{2})$/)\n if (!match) {\n return false\n }\n\n const sign = match[1] === '+' ? 1 : -1\n const hours = parseInt(match[2]!, 10)\n const minutes = parseInt(match[3]!, 10)\n\n // Minutes must be 0-59\n if (minutes > 59) {\n return false\n }\n\n // Valid range: -12:00 (-720 min) to +14:00 (+840 min)\n const totalMinutes = sign * (hours * 60 + minutes)\n return totalMinutes >= -720 && totalMinutes <= 840\n}\n\n/**\n * Checks if a timezone is supported by the current runtime.\n * Supports both IANA timezone names and UTC offset formats.\n *\n * For IANA names: Uses Intl.DateTimeFormat and Intl.supportedValuesOf\n * For UTC offsets: Uses native Date API to validate (±HH:mm format only)\n */\nconst isTimezoneSupported = (timezoneValue: string): boolean => {\n // UTC is always supported\n if (timezoneValue === 'UTC') {\n return true\n }\n\n // Check if it's a UTC offset format (starts with + or -)\n if (timezoneValue.startsWith('+') || timezoneValue.startsWith('-')) {\n return isValidUtcOffset(timezoneValue)\n }\n\n // For IANA timezone names, use Intl.DateTimeFormat as primary check\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: timezoneValue })\n return true\n } catch {\n // DateTimeFormat failed, timezone is not supported\n }\n\n // Secondary check: verify against supportedValuesOf if available\n if (typeof Intl.supportedValuesOf === 'function') {\n const supportedTimezones = Intl.supportedValuesOf('timeZone')\n if (supportedTimezones.includes(timezoneValue)) {\n return true\n }\n }\n\n return false\n}\n\n/**\n * Validates that all provided timezones are supported by the current runtime's Intl API.\n * Uses both Intl.DateTimeFormat and Intl.supportedValuesOf for comprehensive validation.\n *\n * @throws InvalidConfiguration if an unsupported timezone is found\n */\nexport const validateTimezones = ({ source, timezones }: ValidateTimezonesArgs): void => {\n if (!timezones?.length) {\n return\n }\n\n for (const timezone of timezones) {\n if (!isTimezoneSupported(timezone.value)) {\n const sourceText = source ? ` in ${source}` : ''\n throw new InvalidConfiguration(\n `Timezone ${timezone.value}${sourceText} is not supported by the current runtime via the Intl API.`,\n )\n }\n }\n}\n"],"names":["InvalidConfiguration","isValidUtcOffset","value","match","sign","hours","parseInt","minutes","totalMinutes","isTimezoneSupported","timezoneValue","startsWith","Intl","DateTimeFormat","timeZone","supportedValuesOf","supportedTimezones","includes","validateTimezones","source","timezones","length","timezone","sourceText"],"mappings":"AAEA,SAASA,oBAAoB,QAAQ,qBAAoB;AAazD;;;;;;;CAOC,GACD,MAAMC,mBAAmB,CAACC;IACxB,mCAAmC;IACnC,MAAMC,QAAQD,MAAMC,KAAK,CAAC;IAC1B,IAAI,CAACA,OAAO;QACV,OAAO;IACT;IAEA,MAAMC,OAAOD,KAAK,CAAC,EAAE,KAAK,MAAM,IAAI,CAAC;IACrC,MAAME,QAAQC,SAASH,KAAK,CAAC,EAAE,EAAG;IAClC,MAAMI,UAAUD,SAASH,KAAK,CAAC,EAAE,EAAG;IAEpC,uBAAuB;IACvB,IAAII,UAAU,IAAI;QAChB,OAAO;IACT;IAEA,sDAAsD;IACtD,MAAMC,eAAeJ,OAAQC,CAAAA,QAAQ,KAAKE,OAAM;IAChD,OAAOC,gBAAgB,CAAC,OAAOA,gBAAgB;AACjD;AAEA;;;;;;CAMC,GACD,MAAMC,sBAAsB,CAACC;IAC3B,0BAA0B;IAC1B,IAAIA,kBAAkB,OAAO;QAC3B,OAAO;IACT;IAEA,yDAAyD;IACzD,IAAIA,cAAcC,UAAU,CAAC,QAAQD,cAAcC,UAAU,CAAC,MAAM;QAClE,OAAOV,iBAAiBS;IAC1B;IAEA,oEAAoE;IACpE,IAAI;QACF,IAAIE,KAAKC,cAAc,CAAC,SAAS;YAAEC,UAAUJ;QAAc;QAC3D,OAAO;IACT,EAAE,OAAM;IACN,mDAAmD;IACrD;IAEA,iEAAiE;IACjE,IAAI,OAAOE,KAAKG,iBAAiB,KAAK,YAAY;QAChD,MAAMC,qBAAqBJ,KAAKG,iBAAiB,CAAC;QAClD,IAAIC,mBAAmBC,QAAQ,CAACP,gBAAgB;YAC9C,OAAO;QACT;IACF;IAEA,OAAO;AACT;AAEA;;;;;CAKC,GACD,OAAO,MAAMQ,oBAAoB,CAAC,EAAEC,MAAM,EAAEC,SAAS,EAAyB;IAC5E,IAAI,CAACA,WAAWC,QAAQ;QACtB;IACF;IAEA,KAAK,MAAMC,YAAYF,UAAW;QAChC,IAAI,CAACX,oBAAoBa,SAASpB,KAAK,GAAG;YACxC,MAAMqB,aAAaJ,SAAS,CAAC,IAAI,EAAEA,QAAQ,GAAG;YAC9C,MAAM,IAAInB,qBACR,CAAC,SAAS,EAAEsB,SAASpB,KAAK,GAAGqB,WAAW,0DAA0D,CAAC;QAEvG;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/utilities/validateTimezones.ts"],"sourcesContent":["import type { Timezone } from '../config/types.js'\n\nimport { InvalidConfiguration } from '../errors/index.js'\nimport { defaultTimezones } from '../fields/baseFields/timezone/defaultTimezones.js'\n\n// Pre-computed Set of default timezone values - skip validation for these\nconst defaultTimezoneValues = new Set(defaultTimezones.map((tz) => tz.value))\n\ntype ValidateTimezonesArgs = {\n /**\n * The source of the timezones for error messaging\n */\n source?: string\n /**\n * Array of timezones to validate\n */\n timezones: Timezone[] | undefined\n}\n\n/**\n * Validates a UTC offset string.\n * Only supports the ±HH:mm format (e.g., +05:30, -08:00).\n *\n * Valid ranges: hours -12 to +14, minutes 0-59\n *\n * @returns true if the offset is valid\n */\nconst isValidUtcOffset = (value: string): boolean => {\n // Strict format check: only ±HH:mm\n const match = value.match(/^([+-])(\\d{2}):(\\d{2})$/)\n if (!match) {\n return false\n }\n\n const sign = match[1] === '+' ? 1 : -1\n const hours = parseInt(match[2]!, 10)\n const minutes = parseInt(match[3]!, 10)\n\n // Minutes must be 0-59\n if (minutes > 59) {\n return false\n }\n\n // Valid range: -12:00 (-720 min) to +14:00 (+840 min)\n const totalMinutes = sign * (hours * 60 + minutes)\n return totalMinutes >= -720 && totalMinutes <= 840\n}\n\n/**\n * Checks if a timezone is supported by the current runtime.\n * Supports both IANA timezone names and UTC offset formats.\n *\n * For IANA names: Uses Intl.DateTimeFormat and Intl.supportedValuesOf\n * For UTC offsets: Uses native Date API to validate (±HH:mm format only)\n */\nconst isTimezoneSupported = (timezoneValue: string): boolean => {\n // UTC is always supported\n if (timezoneValue === 'UTC') {\n return true\n }\n\n // Check if it's a UTC offset format (starts with + or -)\n if (timezoneValue.startsWith('+') || timezoneValue.startsWith('-')) {\n return isValidUtcOffset(timezoneValue)\n }\n\n // For IANA timezone names, use Intl.DateTimeFormat as primary check\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: timezoneValue })\n return true\n } catch {\n // DateTimeFormat failed, timezone is not supported\n }\n\n // Secondary check: verify against supportedValuesOf if available\n if (typeof Intl.supportedValuesOf === 'function') {\n const supportedTimezones = Intl.supportedValuesOf('timeZone')\n if (supportedTimezones.includes(timezoneValue)) {\n return true\n }\n }\n\n return false\n}\n\n/**\n * Validates that all provided timezones are supported by the current runtime's Intl API.\n * Uses both Intl.DateTimeFormat and Intl.supportedValuesOf for comprehensive validation.\n *\n * @throws InvalidConfiguration if an unsupported timezone is found\n */\nexport const validateTimezones = ({ source, timezones }: ValidateTimezonesArgs): void => {\n if (!timezones?.length) {\n return\n }\n\n for (const timezone of timezones) {\n // Skip validation for known-valid default timezones\n if (defaultTimezoneValues.has(timezone.value)) {\n continue\n }\n if (!isTimezoneSupported(timezone.value)) {\n const sourceText = source ? ` in ${source}` : ''\n throw new InvalidConfiguration(\n `Timezone ${timezone.value}${sourceText} is not supported by the current runtime via the Intl API.`,\n )\n }\n }\n}\n"],"names":["InvalidConfiguration","defaultTimezones","defaultTimezoneValues","Set","map","tz","value","isValidUtcOffset","match","sign","hours","parseInt","minutes","totalMinutes","isTimezoneSupported","timezoneValue","startsWith","Intl","DateTimeFormat","timeZone","supportedValuesOf","supportedTimezones","includes","validateTimezones","source","timezones","length","timezone","has","sourceText"],"mappings":"AAEA,SAASA,oBAAoB,QAAQ,qBAAoB;AACzD,SAASC,gBAAgB,QAAQ,oDAAmD;AAEpF,0EAA0E;AAC1E,MAAMC,wBAAwB,IAAIC,IAAIF,iBAAiBG,GAAG,CAAC,CAACC,KAAOA,GAAGC,KAAK;AAa3E;;;;;;;CAOC,GACD,MAAMC,mBAAmB,CAACD;IACxB,mCAAmC;IACnC,MAAME,QAAQF,MAAME,KAAK,CAAC;IAC1B,IAAI,CAACA,OAAO;QACV,OAAO;IACT;IAEA,MAAMC,OAAOD,KAAK,CAAC,EAAE,KAAK,MAAM,IAAI,CAAC;IACrC,MAAME,QAAQC,SAASH,KAAK,CAAC,EAAE,EAAG;IAClC,MAAMI,UAAUD,SAASH,KAAK,CAAC,EAAE,EAAG;IAEpC,uBAAuB;IACvB,IAAII,UAAU,IAAI;QAChB,OAAO;IACT;IAEA,sDAAsD;IACtD,MAAMC,eAAeJ,OAAQC,CAAAA,QAAQ,KAAKE,OAAM;IAChD,OAAOC,gBAAgB,CAAC,OAAOA,gBAAgB;AACjD;AAEA;;;;;;CAMC,GACD,MAAMC,sBAAsB,CAACC;IAC3B,0BAA0B;IAC1B,IAAIA,kBAAkB,OAAO;QAC3B,OAAO;IACT;IAEA,yDAAyD;IACzD,IAAIA,cAAcC,UAAU,CAAC,QAAQD,cAAcC,UAAU,CAAC,MAAM;QAClE,OAAOT,iBAAiBQ;IAC1B;IAEA,oEAAoE;IACpE,IAAI;QACF,IAAIE,KAAKC,cAAc,CAAC,SAAS;YAAEC,UAAUJ;QAAc;QAC3D,OAAO;IACT,EAAE,OAAM;IACN,mDAAmD;IACrD;IAEA,iEAAiE;IACjE,IAAI,OAAOE,KAAKG,iBAAiB,KAAK,YAAY;QAChD,MAAMC,qBAAqBJ,KAAKG,iBAAiB,CAAC;QAClD,IAAIC,mBAAmBC,QAAQ,CAACP,gBAAgB;YAC9C,OAAO;QACT;IACF;IAEA,OAAO;AACT;AAEA;;;;;CAKC,GACD,OAAO,MAAMQ,oBAAoB,CAAC,EAAEC,MAAM,EAAEC,SAAS,EAAyB;IAC5E,IAAI,CAACA,WAAWC,QAAQ;QACtB;IACF;IAEA,KAAK,MAAMC,YAAYF,UAAW;QAChC,oDAAoD;QACpD,IAAIvB,sBAAsB0B,GAAG,CAACD,SAASrB,KAAK,GAAG;YAC7C;QACF;QACA,IAAI,CAACQ,oBAAoBa,SAASrB,KAAK,GAAG;YACxC,MAAMuB,aAAaL,SAAS,CAAC,IAAI,EAAEA,QAAQ,GAAG;YAC9C,MAAM,IAAIxB,qBACR,CAAC,SAAS,EAAE2B,SAASrB,KAAK,GAAGuB,WAAW,0DAA0D,CAAC;QAEvG;IACF;AACF,EAAC"}
@@ -18,7 +18,7 @@ export type SchedulePublish = {
18
18
  /**
19
19
  * Define a date format to use for the time picker.
20
20
  *
21
- * @example 'hh:mm' will give a 24 hour clock
21
+ * @example 'HH:mm' will give a 24 hour clock
22
22
  *
23
23
  * @default 'h:mm aa' which is a 12 hour clock
24
24
  */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/versions/types.ts"],"sourcesContent":["export type Autosave = {\n /**\n * Define an `interval` in milliseconds to automatically save progress while documents are edited.\n * Document updates are \"debounced\" at this interval.\n *\n * @default 800\n */\n interval?: number\n /**\n * When set to `true`, the \"Save as draft\" button will be displayed even while autosave is enabled.\n * By default, this button is hidden to avoid redundancy with autosave behavior.\n *\n * @default false\n */\n showSaveDraftButton?: boolean\n}\n\nexport type SchedulePublish = {\n /**\n * Define a date format to use for the time picker.\n *\n * @example 'hh:mm' will give a 24 hour clock\n *\n * @default 'h:mm aa' which is a 12 hour clock\n */\n timeFormat?: string\n /**\n * Intervals for the time picker.\n *\n * @default 5\n */\n timeIntervals?: number\n}\n\nexport type IncomingDrafts = {\n /**\n * Enable autosave to automatically save progress while documents are edited.\n * To enable, set to true or pass an object with options.\n */\n autosave?: Autosave | boolean\n /**\n * Localizes the status field.\n *\n * Only effective if the experimental `experimental.localizeStatus` is enabled.\n *\n * @experimental\n * @default false\n */\n localizeStatus?: boolean\n /**\n * Allow for editors to schedule publish / unpublish events in the future.\n */\n schedulePublish?: boolean | SchedulePublish\n /**\n * Set validate to true to validate draft documents when saved.\n *\n * @default false\n */\n validate?: boolean\n}\n\nexport type SanitizedDrafts = {\n /**\n * Enable autosave to automatically save progress while documents are edited.\n * To enable, set to true or pass an object with options.\n */\n autosave: Autosave | false\n /**\n * Localizes the status field.\n *\n * Only effective if the experimental `experimental.localizeStatus` is enabled.\n *\n * @experimental\n * @default false\n */\n localizeStatus?: boolean\n /**\n * Allow for editors to schedule publish / unpublish events in the future.\n */\n schedulePublish: boolean | SchedulePublish\n /**\n * Set validate to true to validate draft documents when saved.\n *\n * @default false\n */\n validate: boolean\n}\n\nexport type IncomingCollectionVersions = {\n /**\n * Enable Drafts mode for this collection.\n * To enable, set to true or pass an object with draft options.\n */\n drafts?: boolean | IncomingDrafts\n /**\n * Use this setting to control how many versions to keep on a document by document basis.\n * Must be an integer. Use 0 to save all versions.\n *\n * @default 100\n */\n maxPerDoc?: number\n}\n\nexport interface SanitizedCollectionVersions extends Omit<IncomingCollectionVersions, 'drafts'> {\n /**\n * Enable Drafts mode for this collection.\n * To enable, set to true or pass an object with draft options.\n */\n drafts: false | SanitizedDrafts\n /**\n * Use this setting to control how many versions to keep on a document by document basis.\n * Must be an integer. Use 0 to save all versions.\n *\n * @default 100\n */\n maxPerDoc: number\n}\n\nexport type IncomingGlobalVersions = {\n drafts?: boolean | IncomingDrafts\n /**\n * Use this setting to control how many versions to keep on a global by global basis.\n * Must be an integer.\n */\n max?: number\n}\n\nexport type SanitizedGlobalVersions = {\n /**\n * Enable Drafts mode for this global. To enable, set to true or pass an object with draft options\n */\n drafts: false | SanitizedDrafts\n /**\n * Use this setting to control how many versions to keep on a global by global basis.\n * Must be an integer.\n */\n max: number\n}\n\nexport type TypeWithVersion<T> = {\n createdAt: string\n id: string\n latest?: boolean\n parent: number | string\n publishedLocale?: string\n snapshot?: boolean\n updatedAt: string\n version: T\n}\n"],"names":[],"mappings":"AA2IA,WASC"}
1
+ {"version":3,"sources":["../../src/versions/types.ts"],"sourcesContent":["export type Autosave = {\n /**\n * Define an `interval` in milliseconds to automatically save progress while documents are edited.\n * Document updates are \"debounced\" at this interval.\n *\n * @default 800\n */\n interval?: number\n /**\n * When set to `true`, the \"Save as draft\" button will be displayed even while autosave is enabled.\n * By default, this button is hidden to avoid redundancy with autosave behavior.\n *\n * @default false\n */\n showSaveDraftButton?: boolean\n}\n\nexport type SchedulePublish = {\n /**\n * Define a date format to use for the time picker.\n *\n * @example 'HH:mm' will give a 24 hour clock\n *\n * @default 'h:mm aa' which is a 12 hour clock\n */\n timeFormat?: string\n /**\n * Intervals for the time picker.\n *\n * @default 5\n */\n timeIntervals?: number\n}\n\nexport type IncomingDrafts = {\n /**\n * Enable autosave to automatically save progress while documents are edited.\n * To enable, set to true or pass an object with options.\n */\n autosave?: Autosave | boolean\n /**\n * Localizes the status field.\n *\n * Only effective if the experimental `experimental.localizeStatus` is enabled.\n *\n * @experimental\n * @default false\n */\n localizeStatus?: boolean\n /**\n * Allow for editors to schedule publish / unpublish events in the future.\n */\n schedulePublish?: boolean | SchedulePublish\n /**\n * Set validate to true to validate draft documents when saved.\n *\n * @default false\n */\n validate?: boolean\n}\n\nexport type SanitizedDrafts = {\n /**\n * Enable autosave to automatically save progress while documents are edited.\n * To enable, set to true or pass an object with options.\n */\n autosave: Autosave | false\n /**\n * Localizes the status field.\n *\n * Only effective if the experimental `experimental.localizeStatus` is enabled.\n *\n * @experimental\n * @default false\n */\n localizeStatus?: boolean\n /**\n * Allow for editors to schedule publish / unpublish events in the future.\n */\n schedulePublish: boolean | SchedulePublish\n /**\n * Set validate to true to validate draft documents when saved.\n *\n * @default false\n */\n validate: boolean\n}\n\nexport type IncomingCollectionVersions = {\n /**\n * Enable Drafts mode for this collection.\n * To enable, set to true or pass an object with draft options.\n */\n drafts?: boolean | IncomingDrafts\n /**\n * Use this setting to control how many versions to keep on a document by document basis.\n * Must be an integer. Use 0 to save all versions.\n *\n * @default 100\n */\n maxPerDoc?: number\n}\n\nexport interface SanitizedCollectionVersions extends Omit<IncomingCollectionVersions, 'drafts'> {\n /**\n * Enable Drafts mode for this collection.\n * To enable, set to true or pass an object with draft options.\n */\n drafts: false | SanitizedDrafts\n /**\n * Use this setting to control how many versions to keep on a document by document basis.\n * Must be an integer. Use 0 to save all versions.\n *\n * @default 100\n */\n maxPerDoc: number\n}\n\nexport type IncomingGlobalVersions = {\n drafts?: boolean | IncomingDrafts\n /**\n * Use this setting to control how many versions to keep on a global by global basis.\n * Must be an integer.\n */\n max?: number\n}\n\nexport type SanitizedGlobalVersions = {\n /**\n * Enable Drafts mode for this global. To enable, set to true or pass an object with draft options\n */\n drafts: false | SanitizedDrafts\n /**\n * Use this setting to control how many versions to keep on a global by global basis.\n * Must be an integer.\n */\n max: number\n}\n\nexport type TypeWithVersion<T> = {\n createdAt: string\n id: string\n latest?: boolean\n parent: number | string\n publishedLocale?: string\n snapshot?: boolean\n updatedAt: string\n version: T\n}\n"],"names":[],"mappings":"AA2IA,WASC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depup/payload",
3
- "version": "3.81.0-depup.0",
3
+ "version": "3.82.0-depup.0",
4
4
  "description": "Node, React, Headless CMS and Application Framework built on Next.js (with updated dependencies)",
5
5
  "keywords": [
6
6
  "payload",
@@ -110,7 +110,7 @@
110
110
  "jose": "^6.2.2",
111
111
  "json-schema-to-typescript": "^15.0.4",
112
112
  "minimist": "1.2.8",
113
- "path-to-regexp": "^8.4.1",
113
+ "path-to-regexp": "^8.4.2",
114
114
  "pino": "^10.3.1",
115
115
  "pino-pretty": "^13.1.3",
116
116
  "pluralize": "8.0.0",
@@ -119,10 +119,10 @@
119
119
  "sanitize-filename": "^1.6.4",
120
120
  "ts-essentials": "^10.1.1",
121
121
  "tsx": "4.21.0",
122
- "undici": "^7.24.6",
122
+ "undici": "^8.0.2",
123
123
  "uuid": "^13.0.0",
124
124
  "ws": "^8.20.0",
125
- "@payloadcms/translations": "3.81.0"
125
+ "@payloadcms/translations": "3.82.0"
126
126
  },
127
127
  "devDependencies": {
128
128
  "@hyrious/esbuild-plugin-commonjs": "0.2.6",
@@ -205,7 +205,7 @@
205
205
  },
206
206
  "path-to-regexp": {
207
207
  "from": "6.3.0",
208
- "to": "^8.4.1"
208
+ "to": "^8.4.2"
209
209
  },
210
210
  "pino": {
211
211
  "from": "9.14.0",
@@ -225,7 +225,7 @@
225
225
  },
226
226
  "undici": {
227
227
  "from": "7.24.4",
228
- "to": "^7.24.6"
228
+ "to": "^8.0.2"
229
229
  },
230
230
  "uuid": {
231
231
  "from": "10.0.0",
@@ -238,8 +238,8 @@
238
238
  },
239
239
  "depsUpdated": 17,
240
240
  "originalPackage": "payload",
241
- "originalVersion": "3.81.0",
242
- "processedAt": "2026-04-01T05:02:55.722Z",
241
+ "originalVersion": "3.82.0",
242
+ "processedAt": "2026-04-08T16:33:08.154Z",
243
243
  "smokeTest": "passed"
244
244
  }
245
245
  }