payload 3.90.0 → 3.91.0-internal.6e3dc85

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 (38) hide show
  1. package/dist/database/queryValidation/validateSearchParams.d.ts.map +1 -1
  2. package/dist/database/queryValidation/validateSearchParams.js +14 -9
  3. package/dist/database/queryValidation/validateSearchParams.js.map +1 -1
  4. package/dist/exports/shared.d.ts +1 -1
  5. package/dist/exports/shared.d.ts.map +1 -1
  6. package/dist/exports/shared.js +1 -1
  7. package/dist/exports/shared.js.map +1 -1
  8. package/dist/index.bundled.d.ts +1 -1
  9. package/dist/utilities/formatAdminURL.d.ts +1 -0
  10. package/dist/utilities/formatAdminURL.d.ts.map +1 -1
  11. package/dist/utilities/formatAdminURL.js +22 -4
  12. package/dist/utilities/formatAdminURL.js.map +1 -1
  13. package/dist/utilities/formatAdminURL.spec.js +98 -2
  14. package/dist/utilities/formatAdminURL.spec.js.map +1 -1
  15. package/dist/utilities/handleEndpoints.d.ts.map +1 -1
  16. package/dist/utilities/handleEndpoints.js +5 -3
  17. package/dist/utilities/handleEndpoints.js.map +1 -1
  18. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.d.ts +4 -0
  19. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.d.ts.map +1 -0
  20. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.js +248 -0
  21. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.js.map +1 -0
  22. package/dist/utilities/telemetry/featureInfo/types.d.ts +62 -0
  23. package/dist/utilities/telemetry/featureInfo/types.d.ts.map +1 -0
  24. package/dist/utilities/telemetry/featureInfo/types.js +3 -0
  25. package/dist/utilities/telemetry/featureInfo/types.js.map +1 -0
  26. package/dist/utilities/telemetry/getProjectContext.d.ts +14 -0
  27. package/dist/utilities/telemetry/getProjectContext.d.ts.map +1 -0
  28. package/dist/utilities/telemetry/getProjectContext.js +36 -0
  29. package/dist/utilities/telemetry/getProjectContext.js.map +1 -0
  30. package/dist/utilities/telemetry/index.d.ts +7 -1
  31. package/dist/utilities/telemetry/index.d.ts.map +1 -1
  32. package/dist/utilities/telemetry/index.js +22 -0
  33. package/dist/utilities/telemetry/index.js.map +1 -1
  34. package/package.json +2 -2
  35. package/dist/auth/baseFields/apiKey.d.ts +0 -3
  36. package/dist/auth/baseFields/apiKey.d.ts.map +0 -1
  37. package/dist/auth/baseFields/apiKey.js +0 -59
  38. package/dist/auth/baseFields/apiKey.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/formatAdminURL.spec.ts"],"sourcesContent":["import { describe, it, expect } from 'vitest'\nimport { formatAdminURL } from './formatAdminURL.js'\n\ndescribe('formatAdminURL', () => {\n const serverURL = 'https://example.com'\n\n const defaultAdminRoute = '/admin'\n const rootAdminRoute = '/'\n\n const dummyPath = '/collections/posts'\n\n describe('relative URLs', () => {\n it('should ignore `serverURL` when relative=true', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n serverURL,\n relative: true,\n })\n\n expect(result).toBe(`${defaultAdminRoute}${dummyPath}`)\n })\n\n it('should force relative URL when `serverURL` is omitted', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n relative: false,\n })\n\n expect(result).toBe(`${defaultAdminRoute}${dummyPath}`)\n })\n })\n\n describe('absolute URLs', () => {\n it('should return absolute URL with serverURL', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${dummyPath}`,\n )\n })\n\n it('should handle serverURL with trailing slash', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: '/collections/posts',\n serverURL: 'https://example.com/',\n })\n\n expect(result).toBe(\n `https://example.com${process.env.NEXT_BASE_PATH || ''}/admin/collections/posts`,\n )\n })\n\n it('should handle serverURL with subdirectory', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: '/collections/posts',\n serverURL: 'https://example.com/api/v1',\n })\n\n expect(result).toBe(\n `https://example.com${process.env.NEXT_BASE_PATH || ''}/admin/collections/posts`,\n )\n })\n })\n\n describe('admin route handling', () => {\n it('should return relative URL for adminRoute=\"/\", no path, no `serverURL`', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n })\n\n expect(result).toBe('/')\n })\n\n it('should handle relative URL for adminRoute=\"/\", with path, no `serverURL`', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n path: dummyPath,\n })\n\n expect(result).toBe(dummyPath)\n })\n\n it('should return absolute URL for adminRoute=\"/\", no path, with `serverURL`', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n serverURL,\n })\n\n expect(result).toBe('https://example.com/')\n })\n\n it('should handle absolute URL for adminRoute=\"/\", with path and `serverURL`', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n serverURL,\n path: dummyPath,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${dummyPath}`)\n })\n })\n\n describe('base path handling', () => {\n it('should include basePath in URL', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n basePath: '/v1',\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1${defaultAdminRoute}${dummyPath}`,\n )\n })\n\n it('should handle basePath with adminRoute=\"/\"', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n basePath: '/v1',\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1`)\n })\n\n it('should handle basePath with no adminRoute', () => {\n const result = formatAdminURL({\n adminRoute: undefined,\n basePath: '/v1',\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1${dummyPath}`)\n })\n\n it('should handle empty basePath', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n basePath: '',\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${dummyPath}`,\n )\n })\n })\n\n describe('path handling', () => {\n it('should handle empty string path', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: '',\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`)\n })\n\n it('should handle null path', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: null,\n serverURL,\n })\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`)\n })\n\n it('should handle undefined path', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: undefined,\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`)\n })\n\n it('should handle path with query parameters', () => {\n const path = `${dummyPath}?page=2`\n\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${path}`,\n )\n })\n })\n\n describe('edge cases', () => {\n it('should return \"/\" when given minimal args', () => {\n const result = formatAdminURL({\n adminRoute: undefined,\n basePath: '',\n path: '',\n relative: true,\n })\n\n expect(result).toBe('/')\n })\n })\n})\n"],"names":["describe","it","expect","formatAdminURL","serverURL","defaultAdminRoute","rootAdminRoute","dummyPath","result","adminRoute","path","relative","toBe","process","env","NEXT_BASE_PATH","basePath","undefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/formatAdminURL.spec.ts"],"sourcesContent":["import { afterEach, beforeEach, describe, it, expect } from 'vitest'\nimport { formatAdminURL, stripTrailingSlash } from './formatAdminURL.js'\n\ndescribe('formatAdminURL', () => {\n const serverURL = 'https://example.com'\n\n const defaultAdminRoute = '/admin'\n const rootAdminRoute = '/'\n\n const dummyPath = '/collections/posts'\n\n describe('stripTrailingSlash', () => {\n it('removes a trailing slash while preserving the root path', () => {\n expect(stripTrailingSlash('/admin/')).toBe('/admin')\n expect(stripTrailingSlash('/')).toBe('/')\n expect(stripTrailingSlash('/admin')).toBe('/admin')\n })\n })\n\n describe('relative URLs', () => {\n it('should ignore `serverURL` when relative=true', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n serverURL,\n relative: true,\n })\n\n expect(result).toBe(`${defaultAdminRoute}${dummyPath}`)\n })\n\n it('should force relative URL when `serverURL` is omitted', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n relative: false,\n })\n\n expect(result).toBe(`${defaultAdminRoute}${dummyPath}`)\n })\n })\n\n describe('absolute URLs', () => {\n it('should return absolute URL with serverURL', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${dummyPath}`,\n )\n })\n\n it('should handle serverURL with trailing slash', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: '/collections/posts',\n serverURL: 'https://example.com/',\n })\n\n expect(result).toBe(\n `https://example.com${process.env.NEXT_BASE_PATH || ''}/admin/collections/posts`,\n )\n })\n\n it('should handle serverURL with subdirectory', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: '/collections/posts',\n serverURL: 'https://example.com/api/v1',\n })\n\n expect(result).toBe(\n `https://example.com${process.env.NEXT_BASE_PATH || ''}/admin/collections/posts`,\n )\n })\n })\n\n describe('admin route handling', () => {\n it('should return relative URL for adminRoute=\"/\", no path, no `serverURL`', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n })\n\n expect(result).toBe('/')\n })\n\n it('should handle relative URL for adminRoute=\"/\", with path, no `serverURL`', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n path: dummyPath,\n })\n\n expect(result).toBe(dummyPath)\n })\n\n it('should return absolute URL for adminRoute=\"/\", no path, with `serverURL`', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n serverURL,\n })\n\n expect(result).toBe('https://example.com/')\n })\n\n it('should handle absolute URL for adminRoute=\"/\", with path and `serverURL`', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n serverURL,\n path: dummyPath,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${dummyPath}`)\n })\n })\n\n describe('base path handling', () => {\n it('should include basePath in URL', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n basePath: '/v1',\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1${defaultAdminRoute}${dummyPath}`,\n )\n })\n\n it('should handle basePath with adminRoute=\"/\"', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n basePath: '/v1',\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1`)\n })\n\n it('should handle basePath with no adminRoute', () => {\n const result = formatAdminURL({\n adminRoute: undefined,\n basePath: '/v1',\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1${dummyPath}`)\n })\n\n it('should handle empty basePath', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n basePath: '',\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${dummyPath}`,\n )\n })\n })\n\n describe('path handling', () => {\n it('should handle empty string path', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: '',\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`)\n })\n\n it('should handle null path', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: null,\n serverURL,\n })\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`)\n })\n\n it('should handle undefined path', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: undefined,\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`)\n })\n\n it('should handle path with query parameters', () => {\n const path = `${dummyPath}?page=2`\n\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${path}`,\n )\n })\n })\n\n describe('edge cases', () => {\n it('should return \"/\" when given minimal args', () => {\n const result = formatAdminURL({\n adminRoute: undefined,\n basePath: '',\n path: '',\n relative: true,\n })\n\n expect(result).toBe('/')\n })\n })\n\n describe('trailing slash handling', () => {\n const originalTrailingSlash = process.env.NEXT_TRAILING_SLASH\n\n beforeEach(() => {\n process.env.NEXT_TRAILING_SLASH = 'true'\n })\n\n afterEach(() => {\n if (originalTrailingSlash === undefined) {\n delete process.env.NEXT_TRAILING_SLASH\n } else {\n process.env.NEXT_TRAILING_SLASH = originalTrailingSlash\n }\n })\n\n it('should append trailing slash to relative admin URL', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n relative: true,\n })\n\n expect(result).toBe(`${defaultAdminRoute}${dummyPath}/`)\n })\n\n it('should append trailing slash to relative api URL', () => {\n const result = formatAdminURL({\n apiRoute: '/api',\n path: '/users',\n relative: true,\n })\n\n expect(result).toBe(`${process.env.NEXT_BASE_PATH || ''}/api/users/`)\n })\n\n it('should append trailing slash to absolute URL', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n serverURL,\n })\n\n expect(result).toBe(\n `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${dummyPath}/`,\n )\n })\n\n it('should append trailing slash when basePath is set', () => {\n const result = formatAdminURL({\n apiRoute: '/api',\n basePath: '/v1',\n path: '/users',\n serverURL,\n })\n\n expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1/api/users/`)\n })\n\n it('should not append trailing slash to root \"/\"', () => {\n const result = formatAdminURL({\n adminRoute: rootAdminRoute,\n relative: true,\n })\n\n expect(result).toBe('/')\n })\n\n it('should not double-slash when path already ends with /', () => {\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: '/collections/posts',\n relative: true,\n })\n\n expect(result.endsWith('//')).toBe(false)\n expect(result).toBe(`${defaultAdminRoute}/collections/posts/`)\n })\n\n it('should place trailing slash before query string', () => {\n const path = `${dummyPath}?page=2`\n\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path,\n relative: true,\n })\n\n expect(result).toBe(`${defaultAdminRoute}${dummyPath}/?page=2`)\n })\n\n it('should leave URLs unchanged when env var is not set', () => {\n delete process.env.NEXT_TRAILING_SLASH\n\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n relative: true,\n })\n\n expect(result).toBe(`${defaultAdminRoute}${dummyPath}`)\n })\n\n it('should leave URLs unchanged when env var is \"false\"', () => {\n process.env.NEXT_TRAILING_SLASH = 'false'\n\n const result = formatAdminURL({\n adminRoute: defaultAdminRoute,\n path: dummyPath,\n relative: true,\n })\n\n expect(result).toBe(`${defaultAdminRoute}${dummyPath}`)\n })\n })\n})\n"],"names":["afterEach","beforeEach","describe","it","expect","formatAdminURL","stripTrailingSlash","serverURL","defaultAdminRoute","rootAdminRoute","dummyPath","toBe","result","adminRoute","path","relative","process","env","NEXT_BASE_PATH","basePath","undefined","originalTrailingSlash","NEXT_TRAILING_SLASH","apiRoute","endsWith"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"handleEndpoints.d.ts","sourceRoot":"","sources":["../../src/utilities/handleEndpoints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA4B,eAAe,EAAE,MAAM,oBAAoB,CAAA;AA0BnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,eAAe,kFAMzB;IACD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAA;IAClD,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;CACjB,KAAG,OAAO,CAAC,QAAQ,CAgNnB,CAAA"}
1
+ {"version":3,"file":"handleEndpoints.d.ts","sourceRoot":"","sources":["../../src/utilities/handleEndpoints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA4B,eAAe,EAAE,MAAM,oBAAoB,CAAA;AA0BnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,eAAe,kFAMzB;IACD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAA;IAClD,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;CACjB,KAAG,OAAO,CAAC,QAAQ,CAkNnB,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { status as httpStatus } from 'http-status';
2
2
  import { match } from 'path-to-regexp';
3
3
  import { createPayloadRequest } from './createPayloadRequest.js';
4
- import { formatAdminURL } from './formatAdminURL.js';
4
+ import { formatAdminURL, stripTrailingSlash } from './formatAdminURL.js';
5
5
  import { headersWithCors } from './headersWithCors.js';
6
6
  import { mergeHeaders } from './mergeHeaders.js';
7
7
  import { routeError } from './routeError.js';
@@ -103,11 +103,13 @@ const notFoundResponse = (req, pathname)=>{
103
103
  });
104
104
  const { payload } = req;
105
105
  const { config } = payload;
106
- const pathname = path ?? new URL(req.url).pathname;
107
- const baseAPIPath = formatAdminURL({
106
+ const rawPathname = path ?? new URL(req.url).pathname;
107
+ const pathname = stripTrailingSlash(rawPathname);
108
+ const rawBaseAPIPath = formatAdminURL({
108
109
  apiRoute: config.routes.api,
109
110
  path: ''
110
111
  });
112
+ const baseAPIPath = stripTrailingSlash(rawBaseAPIPath);
111
113
  if (!pathname.startsWith(baseAPIPath)) {
112
114
  return notFoundResponse(req, pathname);
113
115
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/handleEndpoints.ts"],"sourcesContent":["import { status as httpStatus } from 'http-status'\nimport { match } from 'path-to-regexp'\n\nimport type { Collection } from '../collections/config/types.js'\nimport type { Endpoint, PayloadHandler, SanitizedConfig } from '../config/types.js'\nimport type { APIError } from '../errors/APIError.js'\nimport type { GlobalConfig } from '../globals/config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { createPayloadRequest } from './createPayloadRequest.js'\nimport { formatAdminURL } from './formatAdminURL.js'\nimport { headersWithCors } from './headersWithCors.js'\nimport { mergeHeaders } from './mergeHeaders.js'\nimport { routeError } from './routeError.js'\n\nconst notFoundResponse = (req: PayloadRequest, pathname?: string) => {\n return Response.json(\n {\n message: `Route not found \"${pathname ?? new URL(req.url!).pathname}\"`,\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: httpStatus.NOT_FOUND,\n },\n )\n}\n\n/**\n * Attaches the Payload REST API to any backend framework that uses Fetch Request/Response\n * like Next.js (app router), Remix, Bun, Hono.\n *\n * ### Example: Using Hono\n * ```ts\n * import { handleEndpoints } from 'payload';\n * import { serve } from '@hono/node-server';\n * import { loadEnv } from 'payload/node';\n *\n * const port = 3001;\n * loadEnv();\n *\n * const { default: config } = await import('@payload-config');\n *\n * const server = serve({\n * fetch: async (request) => {\n * const response = await handleEndpoints({\n * config,\n * request: request.clone(),\n * });\n *\n * return response;\n * },\n * port,\n * });\n *\n * server.on('listening', () => {\n * console.log(`API server is listening on http://localhost:${port}/api`);\n * });\n * ```\n */\nexport const handleEndpoints = async ({\n basePath = '',\n config: incomingConfig,\n path,\n payloadInstanceCacheKey,\n request,\n}: {\n basePath?: string\n config: Promise<SanitizedConfig> | SanitizedConfig\n /** Override path from the request */\n path?: string\n payloadInstanceCacheKey?: string\n request: Request\n}): Promise<Response> => {\n let handler!: PayloadHandler\n let req: PayloadRequest\n let collection!: Collection\n\n // This can be used against GET request search params size limit.\n // Instead you can do POST request with a text body as search params.\n // We use this internally for relationships querying on the frontend\n // packages/ui/src/fields/Relationship/index.tsx\n if (\n request.method.toLowerCase() === 'post' &&\n (request.headers.get('X-Payload-HTTP-Method-Override') === 'GET' ||\n request.headers.get('X-HTTP-Method-Override') === 'GET')\n ) {\n let url = request.url\n let data: any = undefined\n\n if (request.headers.get('Content-Type') === 'application/x-www-form-urlencoded') {\n const search = await request.text()\n url = `${request.url}?${search}`\n } else if (request.headers.get('Content-Type') === 'application/json') {\n // May not be supported by every endpoint\n data = await request.json()\n\n // locale and fallbackLocale is read by createPayloadRequest to populate req.locale and req.fallbackLocale\n // => add to searchParams\n if (data?.locale) {\n url += `?locale=${data.locale}`\n }\n if (data?.fallbackLocale) {\n url += `&fallbackLocale=${data.depth}`\n }\n }\n\n const req = new Request(url, {\n // @ts-expect-error RequestInit does not include cache in the type\n cache: request.cache,\n credentials: request.credentials,\n headers: request.headers,\n method: 'GET',\n signal: request.signal,\n })\n\n if (data) {\n // @ts-expect-error attach data to request - less overhead than using urlencoded\n req.data = data\n }\n\n const response = await handleEndpoints({\n basePath,\n config: incomingConfig,\n path,\n payloadInstanceCacheKey,\n request: req,\n })\n\n return response\n }\n\n try {\n req = await createPayloadRequest({\n canSetHeaders: true,\n config: incomingConfig,\n payloadInstanceCacheKey,\n request,\n })\n\n const { payload } = req\n const { config } = payload\n\n const pathname = path ?? new URL(req.url!).pathname\n const baseAPIPath = formatAdminURL({\n apiRoute: config.routes.api,\n path: '',\n })\n\n if (!pathname.startsWith(baseAPIPath)) {\n return notFoundResponse(req, pathname)\n }\n\n // /api/posts/route -> /posts/route\n let adjustedPathname = pathname.replace(baseAPIPath, '')\n\n let isGlobals = false\n\n // /globals/header/route -> /header/route\n if (adjustedPathname.startsWith('/globals')) {\n isGlobals = true\n adjustedPathname = adjustedPathname.replace('/globals', '')\n }\n\n const segments = adjustedPathname.split('/')\n // remove empty string first element\n segments.shift()\n\n const firstParam = segments[0]\n\n let globalConfig!: GlobalConfig\n\n // first param can be a global slug or collection slug, find the relevant config\n if (firstParam) {\n if (isGlobals) {\n globalConfig = payload.globals.config.find((each) => each.slug === firstParam)!\n } else if (payload.collections[firstParam]) {\n collection = payload.collections[firstParam]\n }\n }\n\n let endpoints: Endpoint[] | false = config.endpoints\n\n if (collection) {\n endpoints = collection.config.endpoints\n // /posts/route -> /route\n adjustedPathname = adjustedPathname.replace(`/${collection.config.slug}`, '')\n } else if (globalConfig) {\n // /header/route -> /route\n adjustedPathname = adjustedPathname.replace(`/${globalConfig.slug}`, '')\n endpoints = globalConfig.endpoints!\n }\n\n // sanitize when endpoint.path is '/'\n if (adjustedPathname === '') {\n adjustedPathname = '/'\n }\n\n if (endpoints === false) {\n return Response.json(\n {\n message: `Cannot ${req.method?.toUpperCase()} ${req.url}`,\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: httpStatus.NOT_IMPLEMENTED,\n },\n )\n }\n\n // Find the relevant endpoint configuration\n const endpoint = endpoints?.find((endpoint) => {\n if (endpoint.method !== req.method?.toLowerCase()) {\n return false\n }\n\n const pathMatchFn = match(endpoint.path, { decode: decodeURIComponent })\n\n const matchResult = pathMatchFn(adjustedPathname)\n\n if (!matchResult) {\n return false\n }\n\n req.routeParams = matchResult.params as Record<string, unknown>\n\n // Inject to routeParams the slug as well so it can be used later\n if (collection) {\n req.routeParams.collection = collection.config.slug\n } else if (globalConfig) {\n req.routeParams.global = globalConfig.slug\n }\n\n return true\n })\n\n if (endpoint) {\n handler = endpoint.handler\n }\n\n if (!handler) {\n // If no custom handler found and this is an OPTIONS request,\n // return default CORS response for preflight requests\n if (req.method?.toLowerCase() === 'options') {\n return Response.json(\n {},\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: 200,\n },\n )\n }\n\n return notFoundResponse(req, pathname)\n }\n\n const response = await handler(req)\n\n return new Response(response.body, {\n headers: headersWithCors({\n headers: mergeHeaders(req.responseHeaders ?? new Headers(), response.headers),\n req,\n }),\n status: response.status,\n statusText: response.statusText,\n })\n } catch (_err) {\n const err = _err as APIError\n return routeError({\n collection,\n config: incomingConfig,\n err,\n req: req!,\n })\n }\n}\n"],"names":["status","httpStatus","match","createPayloadRequest","formatAdminURL","headersWithCors","mergeHeaders","routeError","notFoundResponse","req","pathname","Response","json","message","URL","url","headers","Headers","NOT_FOUND","handleEndpoints","basePath","config","incomingConfig","path","payloadInstanceCacheKey","request","handler","collection","method","toLowerCase","get","data","undefined","search","text","locale","fallbackLocale","depth","Request","cache","credentials","signal","response","canSetHeaders","payload","baseAPIPath","apiRoute","routes","api","startsWith","adjustedPathname","replace","isGlobals","segments","split","shift","firstParam","globalConfig","globals","find","each","slug","collections","endpoints","toUpperCase","NOT_IMPLEMENTED","endpoint","pathMatchFn","decode","decodeURIComponent","matchResult","routeParams","params","global","body","responseHeaders","statusText","_err","err"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/handleEndpoints.ts"],"sourcesContent":["import { status as httpStatus } from 'http-status'\nimport { match } from 'path-to-regexp'\n\nimport type { Collection } from '../collections/config/types.js'\nimport type { Endpoint, PayloadHandler, SanitizedConfig } from '../config/types.js'\nimport type { APIError } from '../errors/APIError.js'\nimport type { GlobalConfig } from '../globals/config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { createPayloadRequest } from './createPayloadRequest.js'\nimport { formatAdminURL, stripTrailingSlash } from './formatAdminURL.js'\nimport { headersWithCors } from './headersWithCors.js'\nimport { mergeHeaders } from './mergeHeaders.js'\nimport { routeError } from './routeError.js'\n\nconst notFoundResponse = (req: PayloadRequest, pathname?: string) => {\n return Response.json(\n {\n message: `Route not found \"${pathname ?? new URL(req.url!).pathname}\"`,\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: httpStatus.NOT_FOUND,\n },\n )\n}\n\n/**\n * Attaches the Payload REST API to any backend framework that uses Fetch Request/Response\n * like Next.js (app router), Remix, Bun, Hono.\n *\n * ### Example: Using Hono\n * ```ts\n * import { handleEndpoints } from 'payload';\n * import { serve } from '@hono/node-server';\n * import { loadEnv } from 'payload/node';\n *\n * const port = 3001;\n * loadEnv();\n *\n * const { default: config } = await import('@payload-config');\n *\n * const server = serve({\n * fetch: async (request) => {\n * const response = await handleEndpoints({\n * config,\n * request: request.clone(),\n * });\n *\n * return response;\n * },\n * port,\n * });\n *\n * server.on('listening', () => {\n * console.log(`API server is listening on http://localhost:${port}/api`);\n * });\n * ```\n */\nexport const handleEndpoints = async ({\n basePath = '',\n config: incomingConfig,\n path,\n payloadInstanceCacheKey,\n request,\n}: {\n basePath?: string\n config: Promise<SanitizedConfig> | SanitizedConfig\n /** Override path from the request */\n path?: string\n payloadInstanceCacheKey?: string\n request: Request\n}): Promise<Response> => {\n let handler!: PayloadHandler\n let req: PayloadRequest\n let collection!: Collection\n\n // This can be used against GET request search params size limit.\n // Instead you can do POST request with a text body as search params.\n // We use this internally for relationships querying on the frontend\n // packages/ui/src/fields/Relationship/index.tsx\n if (\n request.method.toLowerCase() === 'post' &&\n (request.headers.get('X-Payload-HTTP-Method-Override') === 'GET' ||\n request.headers.get('X-HTTP-Method-Override') === 'GET')\n ) {\n let url = request.url\n let data: any = undefined\n\n if (request.headers.get('Content-Type') === 'application/x-www-form-urlencoded') {\n const search = await request.text()\n url = `${request.url}?${search}`\n } else if (request.headers.get('Content-Type') === 'application/json') {\n // May not be supported by every endpoint\n data = await request.json()\n\n // locale and fallbackLocale is read by createPayloadRequest to populate req.locale and req.fallbackLocale\n // => add to searchParams\n if (data?.locale) {\n url += `?locale=${data.locale}`\n }\n if (data?.fallbackLocale) {\n url += `&fallbackLocale=${data.depth}`\n }\n }\n\n const req = new Request(url, {\n // @ts-expect-error RequestInit does not include cache in the type\n cache: request.cache,\n credentials: request.credentials,\n headers: request.headers,\n method: 'GET',\n signal: request.signal,\n })\n\n if (data) {\n // @ts-expect-error attach data to request - less overhead than using urlencoded\n req.data = data\n }\n\n const response = await handleEndpoints({\n basePath,\n config: incomingConfig,\n path,\n payloadInstanceCacheKey,\n request: req,\n })\n\n return response\n }\n\n try {\n req = await createPayloadRequest({\n canSetHeaders: true,\n config: incomingConfig,\n payloadInstanceCacheKey,\n request,\n })\n\n const { payload } = req\n const { config } = payload\n\n const rawPathname = path ?? new URL(req.url!).pathname\n const pathname = stripTrailingSlash(rawPathname)\n const rawBaseAPIPath = formatAdminURL({\n apiRoute: config.routes.api,\n path: '',\n })\n const baseAPIPath = stripTrailingSlash(rawBaseAPIPath)\n\n if (!pathname.startsWith(baseAPIPath)) {\n return notFoundResponse(req, pathname)\n }\n\n // /api/posts/route -> /posts/route\n let adjustedPathname = pathname.replace(baseAPIPath, '')\n\n let isGlobals = false\n\n // /globals/header/route -> /header/route\n if (adjustedPathname.startsWith('/globals')) {\n isGlobals = true\n adjustedPathname = adjustedPathname.replace('/globals', '')\n }\n\n const segments = adjustedPathname.split('/')\n // remove empty string first element\n segments.shift()\n\n const firstParam = segments[0]\n\n let globalConfig!: GlobalConfig\n\n // first param can be a global slug or collection slug, find the relevant config\n if (firstParam) {\n if (isGlobals) {\n globalConfig = payload.globals.config.find((each) => each.slug === firstParam)!\n } else if (payload.collections[firstParam]) {\n collection = payload.collections[firstParam]\n }\n }\n\n let endpoints: Endpoint[] | false = config.endpoints\n\n if (collection) {\n endpoints = collection.config.endpoints\n // /posts/route -> /route\n adjustedPathname = adjustedPathname.replace(`/${collection.config.slug}`, '')\n } else if (globalConfig) {\n // /header/route -> /route\n adjustedPathname = adjustedPathname.replace(`/${globalConfig.slug}`, '')\n endpoints = globalConfig.endpoints!\n }\n\n // sanitize when endpoint.path is '/'\n if (adjustedPathname === '') {\n adjustedPathname = '/'\n }\n\n if (endpoints === false) {\n return Response.json(\n {\n message: `Cannot ${req.method?.toUpperCase()} ${req.url}`,\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: httpStatus.NOT_IMPLEMENTED,\n },\n )\n }\n\n // Find the relevant endpoint configuration\n const endpoint = endpoints?.find((endpoint) => {\n if (endpoint.method !== req.method?.toLowerCase()) {\n return false\n }\n\n const pathMatchFn = match(endpoint.path, { decode: decodeURIComponent })\n\n const matchResult = pathMatchFn(adjustedPathname)\n\n if (!matchResult) {\n return false\n }\n\n req.routeParams = matchResult.params as Record<string, unknown>\n\n // Inject to routeParams the slug as well so it can be used later\n if (collection) {\n req.routeParams.collection = collection.config.slug\n } else if (globalConfig) {\n req.routeParams.global = globalConfig.slug\n }\n\n return true\n })\n\n if (endpoint) {\n handler = endpoint.handler\n }\n\n if (!handler) {\n // If no custom handler found and this is an OPTIONS request,\n // return default CORS response for preflight requests\n if (req.method?.toLowerCase() === 'options') {\n return Response.json(\n {},\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: 200,\n },\n )\n }\n\n return notFoundResponse(req, pathname)\n }\n\n const response = await handler(req)\n\n return new Response(response.body, {\n headers: headersWithCors({\n headers: mergeHeaders(req.responseHeaders ?? new Headers(), response.headers),\n req,\n }),\n status: response.status,\n statusText: response.statusText,\n })\n } catch (_err) {\n const err = _err as APIError\n return routeError({\n collection,\n config: incomingConfig,\n err,\n req: req!,\n })\n }\n}\n"],"names":["status","httpStatus","match","createPayloadRequest","formatAdminURL","stripTrailingSlash","headersWithCors","mergeHeaders","routeError","notFoundResponse","req","pathname","Response","json","message","URL","url","headers","Headers","NOT_FOUND","handleEndpoints","basePath","config","incomingConfig","path","payloadInstanceCacheKey","request","handler","collection","method","toLowerCase","get","data","undefined","search","text","locale","fallbackLocale","depth","Request","cache","credentials","signal","response","canSetHeaders","payload","rawPathname","rawBaseAPIPath","apiRoute","routes","api","baseAPIPath","startsWith","adjustedPathname","replace","isGlobals","segments","split","shift","firstParam","globalConfig","globals","find","each","slug","collections","endpoints","toUpperCase","NOT_IMPLEMENTED","endpoint","pathMatchFn","decode","decodeURIComponent","matchResult","routeParams","params","global","body","responseHeaders","statusText","_err","err"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { SanitizedConfig } from '../../../config/types.js';
2
+ import type { FeatureInfo } from './types.js';
3
+ export declare const getFeatureInfo: (config: SanitizedConfig) => FeatureInfo;
4
+ //# sourceMappingURL=getFeatureInfo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getFeatureInfo.d.ts","sourceRoot":"","sources":["../../../../src/utilities/telemetry/featureInfo/getFeatureInfo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAA;AAI9D,eAAO,MAAM,cAAc,WAAY,eAAe,KAAG,WAoBxD,CAAA"}
@@ -0,0 +1,248 @@
1
+ import { defaultUserCollection } from '../../../auth/defaultUser.js';
2
+ export const getFeatureInfo = (config)=>{
3
+ const telemetryConfig = sanitizeTelemetryConfig(config);
4
+ return Object.assign({}, ...[
5
+ collectAdminCustomization,
6
+ collectAuthentication,
7
+ collectBasicDenominators,
8
+ collectI18n,
9
+ collectJobsAndQueues,
10
+ collectOrdering,
11
+ collectPreviewAndLivePreview,
12
+ collectQueryPresets,
13
+ collectTrash,
14
+ collectUploadAndMedia,
15
+ collectVersionsAndDrafts,
16
+ collectRichTextFeatures
17
+ ].map((collect)=>safelyCollect(()=>collect(telemetryConfig))));
18
+ };
19
+ const safelyCollect = (collect)=>{
20
+ try {
21
+ return collect();
22
+ } catch (_) {
23
+ return {};
24
+ }
25
+ };
26
+ // sanitization adds 3 system widgets that we need to account for
27
+ const SYSTEM_WIDGET_COUNT = 3;
28
+ const SYSTEM_COLLECTION_SLUGS = [
29
+ 'payload-locked-documents',
30
+ 'payload-migrations',
31
+ 'payload-preferences',
32
+ 'payload-query-presets'
33
+ ];
34
+ const SYSTEM_GLOBAL_SLUGS = new Set([
35
+ 'payload-jobs-stats'
36
+ ]);
37
+ /**
38
+ * Payload adds internal collections, globals and tasks during config sanitization.
39
+ * Remove them from the telemetry view so feature metrics represent user config.
40
+ */ const sanitizeTelemetryConfig = (config)=>{
41
+ try {
42
+ const collections = config.collections ?? [];
43
+ const systemCollectionSlugs = new Set(SYSTEM_COLLECTION_SLUGS);
44
+ const kvCollectionSlug = config.kv?.kvCollection?.slug;
45
+ if (kvCollectionSlug) {
46
+ systemCollectionSlugs.add(kvCollectionSlug);
47
+ }
48
+ if (config.jobs?.enabled) {
49
+ // uses SYSTEM_COLLECTION_SLUGS (not the Set) to exclude kv slug from position detection
50
+ const firstCollectionAfterJobs = collections.findIndex(({ slug })=>SYSTEM_COLLECTION_SLUGS.includes(slug));
51
+ if (firstCollectionAfterJobs > 0) {
52
+ systemCollectionSlugs.add(collections[firstCollectionAfterJobs - 1].slug);
53
+ } else {
54
+ systemCollectionSlugs.add('payload-jobs');
55
+ }
56
+ }
57
+ const tasks = [
58
+ ...config.jobs?.tasks ?? []
59
+ ];
60
+ if (getDraftEntities(config).some(hasScheduledPublishing)) {
61
+ for(let index = tasks.length - 1; index >= 0; index--){
62
+ if (tasks[index]?.slug === 'schedulePublish') {
63
+ tasks.splice(index, 1);
64
+ break;
65
+ }
66
+ }
67
+ }
68
+ return {
69
+ ...config,
70
+ collections: collections.filter((collection)=>collection !== defaultUserCollection && !systemCollectionSlugs.has(collection.slug)),
71
+ globals: (config.globals ?? []).filter(({ slug })=>!SYSTEM_GLOBAL_SLUGS.has(slug)),
72
+ jobs: {
73
+ ...config.jobs,
74
+ tasks
75
+ }
76
+ };
77
+ } catch (_) {
78
+ return config;
79
+ }
80
+ };
81
+ const collectAdminCustomization = (config)=>({
82
+ adminCustomization: {
83
+ customAdminComponentCount: countRootAdminComponents(config),
84
+ customAdminViewCount: Object.keys(config.admin?.components?.views ?? {}).length,
85
+ customDashboardWidgetCount: Math.max(0, (config.admin?.dashboard?.widgets?.length ?? 0) - SYSTEM_WIDGET_COUNT)
86
+ }
87
+ });
88
+ const collectAuthentication = (config)=>{
89
+ const authCollections = (config.collections ?? []).filter(({ auth })=>Boolean(auth));
90
+ return {
91
+ authentication: {
92
+ apiKeyCollectionCount: authCollections.filter(({ auth })=>isObject(auth) && Boolean(auth.useAPIKey)).length,
93
+ authCollectionCount: authCollections.length,
94
+ customAuthStrategyCount: authCollections.reduce((count, { auth })=>count + (isObject(auth) && Array.isArray(auth.strategies) ? auth.strategies.length : 0), 0),
95
+ localAuthDisabledCollectionCount: authCollections.filter(({ auth })=>isObject(auth) && Boolean(auth.disableLocalStrategy)).length,
96
+ sessionsDisabledCollectionCount: authCollections.filter(({ auth })=>isObject(auth) && auth.useSessions === false).length,
97
+ usernameCollectionCount: authCollections.filter(({ auth })=>isObject(auth) && Boolean(auth.loginWithUsername)).length,
98
+ verifiedCollectionCount: authCollections.filter(({ auth })=>isObject(auth) && Boolean(auth.verify)).length
99
+ }
100
+ };
101
+ };
102
+ const collectBasicDenominators = (config)=>({
103
+ basicDenominators: {
104
+ collectionCount: config.collections?.length ?? 0,
105
+ globalCount: config.globals?.length ?? 0
106
+ }
107
+ });
108
+ const collectI18n = (config)=>({
109
+ i18n: {
110
+ hasCustomAdminTranslations: Object.keys(config.i18n?.translations ?? {}).length > 0,
111
+ supportedAdminLanguageCount: config.i18n?.supportedLanguages ? Object.keys(config.i18n.supportedLanguages).length : 1
112
+ }
113
+ });
114
+ const collectJobsAndQueues = (config)=>{
115
+ const tasks = Array.isArray(config.jobs?.tasks) ? config.jobs.tasks : [];
116
+ const workflows = Array.isArray(config.jobs?.workflows) ? config.jobs.workflows : [];
117
+ const tasksAndWorkflows = [
118
+ ...tasks,
119
+ ...workflows
120
+ ];
121
+ const scheduledPublishingEntityCount = getDraftEntities(config).filter(hasScheduledPublishing).length;
122
+ return {
123
+ jobsAndQueues: {
124
+ jobsAutoRunConfigured: config.jobs?.autoRun !== undefined,
125
+ jobsConcurrencyEnabled: tasksAndWorkflows.some(({ concurrency })=>Boolean(concurrency)),
126
+ jobsEnabled: tasks.length > 0 || workflows.length > 0 || scheduledPublishingEntityCount > 0,
127
+ jobsSchedulingEnabled: tasksAndWorkflows.some(({ schedule })=>Boolean(schedule)),
128
+ taskCount: tasks.length,
129
+ workflowCount: workflows.length
130
+ }
131
+ };
132
+ };
133
+ const collectOrdering = (config)=>({
134
+ orderableCollectionCount: (config.collections ?? []).filter(({ orderable })=>Boolean(orderable)).length
135
+ });
136
+ const collectPreviewAndLivePreview = (config)=>{
137
+ const collections = config.collections ?? [];
138
+ const globals = config.globals ?? [];
139
+ const livePreviewCollections = new Set([
140
+ ...config.admin?.livePreview?.collections ?? [],
141
+ ...collections.filter((c)=>c.admin?.livePreview).map((c)=>c.slug)
142
+ ]);
143
+ const livePreviewGlobals = new Set([
144
+ ...config.admin?.livePreview?.globals ?? [],
145
+ ...globals.filter((g)=>g.admin?.livePreview).map((g)=>g.slug)
146
+ ]);
147
+ return {
148
+ previewAndLivePreview: {
149
+ livePreviewCollectionCount: collections.filter(({ slug })=>livePreviewCollections.has(slug)).length,
150
+ livePreviewGlobalCount: globals.filter(({ slug })=>livePreviewGlobals.has(slug)).length,
151
+ previewCollectionCount: collections.filter(({ admin })=>Boolean(admin?.preview)).length,
152
+ previewGlobalCount: globals.filter(({ admin })=>Boolean(admin?.preview)).length
153
+ }
154
+ };
155
+ };
156
+ const collectQueryPresets = (config)=>({
157
+ queryPresetCollectionCount: (config.collections ?? []).filter(({ enableQueryPresets })=>Boolean(enableQueryPresets)).length
158
+ });
159
+ const collectRichTextFeatures = (config)=>{
160
+ const editor = config.editor;
161
+ const features = isObject(editor) && isObject(editor.editorConfig) ? editor.editorConfig.features : undefined;
162
+ const raw = isObject(features) && Array.isArray(features.enabledFeatures) ? features.enabledFeatures : [];
163
+ const featureSet = new Set(raw.filter((f)=>typeof f === 'string'));
164
+ // per-field editor overrides are not checked; root editor covers the vast majority of projects
165
+ return {
166
+ richTextFeatures: [
167
+ 'blocks',
168
+ 'table',
169
+ 'upload',
170
+ 'relationship'
171
+ ].filter((f)=>featureSet.has(f))
172
+ };
173
+ };
174
+ const collectTrash = (config)=>({
175
+ trashCollectionCount: (config.collections ?? []).filter(({ trash })=>Boolean(trash)).length
176
+ });
177
+ const collectUploadAndMedia = (config)=>{
178
+ const collections = config.collections ?? [];
179
+ return {
180
+ uploadAndMedia: {
181
+ cropDisabledCollectionCount: collections.filter(({ upload })=>isObject(upload) && upload.crop === false).length,
182
+ focalPointDisabledCollectionCount: collections.filter(({ upload })=>isObject(upload) && upload.focalPoint === false).length,
183
+ imageSizesCollectionCount: collections.filter(({ upload })=>isObject(upload) && Boolean(upload.imageSizes?.length)).length,
184
+ mimeRestrictedCollectionCount: collections.filter(({ upload })=>isObject(upload) && Boolean(upload.mimeTypes?.length)).length,
185
+ uploadCollectionCount: collections.filter(({ upload })=>Boolean(upload)).length
186
+ }
187
+ };
188
+ };
189
+ const collectVersionsAndDrafts = (config)=>{
190
+ const collections = config.collections ?? [];
191
+ const globals = config.globals ?? [];
192
+ const draftCollections = collections.filter(hasDrafts);
193
+ const draftGlobals = globals.filter(hasDrafts);
194
+ const draftEntities = [
195
+ ...draftCollections,
196
+ ...draftGlobals
197
+ ];
198
+ return {
199
+ versionsAndDrafts: {
200
+ autosaveEntityCount: draftEntities.filter(hasAutosave).length,
201
+ draftCollectionCount: draftCollections.length,
202
+ draftGlobalCount: draftGlobals.length,
203
+ scheduledPublishingEntityCount: draftEntities.filter(hasScheduledPublishing).length,
204
+ versionsDisabledCollectionCount: collections.filter(({ versions })=>!versions).length,
205
+ versionsDisabledGlobalCount: globals.filter(({ versions })=>!versions).length
206
+ }
207
+ };
208
+ };
209
+ const getDraftEntities = (config)=>[
210
+ ...(config.collections ?? []).filter(hasDrafts),
211
+ ...(config.globals ?? []).filter(hasDrafts)
212
+ ];
213
+ const hasDrafts = ({ versions })=>isObject(versions) && Boolean(versions.drafts);
214
+ const getDraftOptions = ({ versions })=>isObject(versions) && isObject(versions.drafts) ? versions.drafts : undefined;
215
+ const hasAutosave = (entity)=>Boolean(getDraftOptions(entity)?.autosave);
216
+ const hasScheduledPublishing = (entity)=>Boolean(getDraftOptions(entity)?.schedulePublish);
217
+ const countRootAdminComponents = (config)=>{
218
+ const admin = config.admin;
219
+ const customAvatarCount = Number(Boolean(admin?.avatar && typeof admin.avatar === 'object' && admin.avatar.Component));
220
+ const components = admin?.components;
221
+ if (!components) {
222
+ return customAvatarCount;
223
+ }
224
+ const componentArrays = [
225
+ components.actions,
226
+ components.afterDashboard,
227
+ components.afterLogin,
228
+ components.afterNav,
229
+ components.afterNavLinks,
230
+ components.beforeDashboard,
231
+ components.beforeLogin,
232
+ components.beforeNav,
233
+ components.beforeNavLinks,
234
+ components.header,
235
+ components.providers,
236
+ components.settingsMenu
237
+ ];
238
+ const directComponents = [
239
+ components.graphics?.Icon,
240
+ components.graphics?.Logo,
241
+ components.logout?.Button,
242
+ components.Nav
243
+ ];
244
+ return customAvatarCount + componentArrays.reduce((count, items)=>count + (items?.length ?? 0), 0) + directComponents.filter(Boolean).length;
245
+ };
246
+ const isObject = (value)=>value !== null && typeof value === 'object';
247
+
248
+ //# sourceMappingURL=getFeatureInfo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/utilities/telemetry/featureInfo/getFeatureInfo.ts"],"sourcesContent":["import type { SanitizedConfig } from '../../../config/types.js'\nimport type { IncomingDrafts } from '../../../versions/types.js'\nimport type { FeatureInfo, RichTextFeature } from './types.js'\n\nimport { defaultUserCollection } from '../../../auth/defaultUser.js'\n\nexport const getFeatureInfo = (config: SanitizedConfig): FeatureInfo => {\n const telemetryConfig = sanitizeTelemetryConfig(config)\n\n return Object.assign(\n {},\n ...[\n collectAdminCustomization,\n collectAuthentication,\n collectBasicDenominators,\n collectI18n,\n collectJobsAndQueues,\n collectOrdering,\n collectPreviewAndLivePreview,\n collectQueryPresets,\n collectTrash,\n collectUploadAndMedia,\n collectVersionsAndDrafts,\n collectRichTextFeatures,\n ].map((collect) => safelyCollect(() => collect(telemetryConfig))),\n )\n}\n\nconst safelyCollect = (collect: () => FeatureInfo): FeatureInfo => {\n try {\n return collect()\n } catch (_) {\n return {}\n }\n}\n\n// sanitization adds 3 system widgets that we need to account for\nconst SYSTEM_WIDGET_COUNT = 3\nconst SYSTEM_COLLECTION_SLUGS = [\n 'payload-locked-documents',\n 'payload-migrations',\n 'payload-preferences',\n 'payload-query-presets',\n]\nconst SYSTEM_GLOBAL_SLUGS = new Set(['payload-jobs-stats'])\n\n/**\n * Payload adds internal collections, globals and tasks during config sanitization.\n * Remove them from the telemetry view so feature metrics represent user config.\n */\nconst sanitizeTelemetryConfig = (config: SanitizedConfig): SanitizedConfig => {\n try {\n const collections = config.collections ?? []\n const systemCollectionSlugs = new Set(SYSTEM_COLLECTION_SLUGS)\n const kvCollectionSlug = config.kv?.kvCollection?.slug\n\n if (kvCollectionSlug) {\n systemCollectionSlugs.add(kvCollectionSlug)\n }\n\n if (config.jobs?.enabled) {\n // uses SYSTEM_COLLECTION_SLUGS (not the Set) to exclude kv slug from position detection\n const firstCollectionAfterJobs = collections.findIndex(({ slug }) =>\n SYSTEM_COLLECTION_SLUGS.includes(slug),\n )\n\n if (firstCollectionAfterJobs > 0) {\n systemCollectionSlugs.add(collections[firstCollectionAfterJobs - 1]!.slug)\n } else {\n systemCollectionSlugs.add('payload-jobs')\n }\n }\n\n const tasks = [...(config.jobs?.tasks ?? [])]\n\n if (getDraftEntities(config).some(hasScheduledPublishing)) {\n for (let index = tasks.length - 1; index >= 0; index--) {\n if (tasks[index]?.slug === 'schedulePublish') {\n tasks.splice(index, 1)\n break\n }\n }\n }\n\n return {\n ...config,\n collections: collections.filter(\n (collection) =>\n collection !== defaultUserCollection && !systemCollectionSlugs.has(collection.slug),\n ),\n globals: (config.globals ?? []).filter(({ slug }) => !SYSTEM_GLOBAL_SLUGS.has(slug)),\n jobs: {\n ...config.jobs,\n tasks,\n },\n }\n } catch (_) {\n return config\n }\n}\n\nconst collectAdminCustomization = (config: SanitizedConfig): FeatureInfo => ({\n adminCustomization: {\n customAdminComponentCount: countRootAdminComponents(config),\n customAdminViewCount: Object.keys(config.admin?.components?.views ?? {}).length,\n customDashboardWidgetCount: Math.max(\n 0,\n (config.admin?.dashboard?.widgets?.length ?? 0) - SYSTEM_WIDGET_COUNT,\n ),\n },\n})\n\nconst collectAuthentication = (config: SanitizedConfig): FeatureInfo => {\n const authCollections = (config.collections ?? []).filter(({ auth }) => Boolean(auth))\n\n return {\n authentication: {\n apiKeyCollectionCount: authCollections.filter(\n ({ auth }) => isObject(auth) && Boolean(auth.useAPIKey),\n ).length,\n authCollectionCount: authCollections.length,\n customAuthStrategyCount: authCollections.reduce(\n (count, { auth }) =>\n count + (isObject(auth) && Array.isArray(auth.strategies) ? auth.strategies.length : 0),\n 0,\n ),\n localAuthDisabledCollectionCount: authCollections.filter(\n ({ auth }) => isObject(auth) && Boolean(auth.disableLocalStrategy),\n ).length,\n sessionsDisabledCollectionCount: authCollections.filter(\n ({ auth }) => isObject(auth) && auth.useSessions === false,\n ).length,\n usernameCollectionCount: authCollections.filter(\n ({ auth }) => isObject(auth) && Boolean(auth.loginWithUsername),\n ).length,\n verifiedCollectionCount: authCollections.filter(\n ({ auth }) => isObject(auth) && Boolean(auth.verify),\n ).length,\n },\n }\n}\n\nconst collectBasicDenominators = (config: SanitizedConfig): FeatureInfo => ({\n basicDenominators: {\n collectionCount: config.collections?.length ?? 0,\n globalCount: config.globals?.length ?? 0,\n },\n})\n\nconst collectI18n = (config: SanitizedConfig): FeatureInfo => ({\n i18n: {\n hasCustomAdminTranslations: Object.keys(config.i18n?.translations ?? {}).length > 0,\n supportedAdminLanguageCount: config.i18n?.supportedLanguages\n ? Object.keys(config.i18n.supportedLanguages).length\n : 1,\n },\n})\n\nconst collectJobsAndQueues = (config: SanitizedConfig): FeatureInfo => {\n const tasks = Array.isArray(config.jobs?.tasks) ? config.jobs.tasks : []\n const workflows = Array.isArray(config.jobs?.workflows) ? config.jobs.workflows : []\n const tasksAndWorkflows = [...tasks, ...workflows]\n const scheduledPublishingEntityCount =\n getDraftEntities(config).filter(hasScheduledPublishing).length\n\n return {\n jobsAndQueues: {\n jobsAutoRunConfigured: config.jobs?.autoRun !== undefined,\n jobsConcurrencyEnabled: tasksAndWorkflows.some(({ concurrency }) => Boolean(concurrency)),\n jobsEnabled: tasks.length > 0 || workflows.length > 0 || scheduledPublishingEntityCount > 0,\n jobsSchedulingEnabled: tasksAndWorkflows.some(({ schedule }) => Boolean(schedule)),\n taskCount: tasks.length,\n workflowCount: workflows.length,\n },\n }\n}\n\nconst collectOrdering = (config: SanitizedConfig): FeatureInfo => ({\n orderableCollectionCount: (config.collections ?? []).filter(({ orderable }) => Boolean(orderable))\n .length,\n})\n\nconst collectPreviewAndLivePreview = (config: SanitizedConfig): FeatureInfo => {\n const collections = config.collections ?? []\n const globals = config.globals ?? []\n const livePreviewCollections = new Set([\n ...(config.admin?.livePreview?.collections ?? []),\n ...collections.filter((c) => c.admin?.livePreview).map((c) => c.slug),\n ])\n const livePreviewGlobals = new Set([\n ...(config.admin?.livePreview?.globals ?? []),\n ...globals.filter((g) => g.admin?.livePreview).map((g) => g.slug),\n ])\n\n return {\n previewAndLivePreview: {\n livePreviewCollectionCount: collections.filter(({ slug }) => livePreviewCollections.has(slug))\n .length,\n livePreviewGlobalCount: globals.filter(({ slug }) => livePreviewGlobals.has(slug)).length,\n previewCollectionCount: collections.filter(({ admin }) => Boolean(admin?.preview)).length,\n previewGlobalCount: globals.filter(({ admin }) => Boolean(admin?.preview)).length,\n },\n }\n}\n\nconst collectQueryPresets = (config: SanitizedConfig): FeatureInfo => ({\n queryPresetCollectionCount: (config.collections ?? []).filter(({ enableQueryPresets }) =>\n Boolean(enableQueryPresets),\n ).length,\n})\n\nconst collectRichTextFeatures = (config: SanitizedConfig): FeatureInfo => {\n const editor: unknown = config.editor\n const features =\n isObject(editor) && isObject(editor.editorConfig) ? editor.editorConfig.features : undefined\n const raw =\n isObject(features) && Array.isArray(features.enabledFeatures) ? features.enabledFeatures : []\n const featureSet = new Set(raw.filter((f): f is string => typeof f === 'string'))\n // per-field editor overrides are not checked; root editor covers the vast majority of projects\n return {\n richTextFeatures: (['blocks', 'table', 'upload', 'relationship'] as const).filter((f) =>\n featureSet.has(f),\n ) as RichTextFeature[],\n }\n}\n\nconst collectTrash = (config: SanitizedConfig): FeatureInfo => ({\n trashCollectionCount: (config.collections ?? []).filter(({ trash }) => Boolean(trash)).length,\n})\n\nconst collectUploadAndMedia = (config: SanitizedConfig): FeatureInfo => {\n const collections = config.collections ?? []\n\n return {\n uploadAndMedia: {\n cropDisabledCollectionCount: collections.filter(\n ({ upload }) => isObject(upload) && upload.crop === false,\n ).length,\n focalPointDisabledCollectionCount: collections.filter(\n ({ upload }) => isObject(upload) && upload.focalPoint === false,\n ).length,\n imageSizesCollectionCount: collections.filter(\n ({ upload }) => isObject(upload) && Boolean(upload.imageSizes?.length),\n ).length,\n mimeRestrictedCollectionCount: collections.filter(\n ({ upload }) => isObject(upload) && Boolean(upload.mimeTypes?.length),\n ).length,\n uploadCollectionCount: collections.filter(({ upload }) => Boolean(upload)).length,\n },\n }\n}\n\nconst collectVersionsAndDrafts = (config: SanitizedConfig): FeatureInfo => {\n const collections = config.collections ?? []\n const globals = config.globals ?? []\n const draftCollections = collections.filter(hasDrafts)\n const draftGlobals = globals.filter(hasDrafts)\n const draftEntities = [...draftCollections, ...draftGlobals]\n\n return {\n versionsAndDrafts: {\n autosaveEntityCount: draftEntities.filter(hasAutosave).length,\n draftCollectionCount: draftCollections.length,\n draftGlobalCount: draftGlobals.length,\n scheduledPublishingEntityCount: draftEntities.filter(hasScheduledPublishing).length,\n versionsDisabledCollectionCount: collections.filter(({ versions }) => !versions).length,\n versionsDisabledGlobalCount: globals.filter(({ versions }) => !versions).length,\n },\n }\n}\n\nconst getDraftEntities = (config: SanitizedConfig) => [\n ...(config.collections ?? []).filter(hasDrafts),\n ...(config.globals ?? []).filter(hasDrafts),\n]\n\nconst hasDrafts = ({ versions }: { versions?: { drafts?: unknown } | boolean }): boolean =>\n isObject(versions) && Boolean(versions.drafts)\n\nconst getDraftOptions = ({\n versions,\n}: {\n versions?: { drafts?: boolean | IncomingDrafts } | boolean\n}): IncomingDrafts | undefined =>\n isObject(versions) && isObject(versions.drafts) ? versions.drafts : undefined\n\nconst hasAutosave = (entity: Parameters<typeof getDraftOptions>[0]): boolean =>\n Boolean(getDraftOptions(entity)?.autosave)\n\nconst hasScheduledPublishing = (entity: Parameters<typeof getDraftOptions>[0]): boolean =>\n Boolean(getDraftOptions(entity)?.schedulePublish)\n\nconst countRootAdminComponents = (config: SanitizedConfig): number => {\n const admin = config.admin\n const customAvatarCount = Number(\n Boolean(admin?.avatar && typeof admin.avatar === 'object' && admin.avatar.Component),\n )\n const components = admin?.components\n\n if (!components) {\n return customAvatarCount\n }\n\n const componentArrays = [\n components.actions,\n components.afterDashboard,\n components.afterLogin,\n components.afterNav,\n components.afterNavLinks,\n components.beforeDashboard,\n components.beforeLogin,\n components.beforeNav,\n components.beforeNavLinks,\n components.header,\n components.providers,\n components.settingsMenu,\n ]\n const directComponents = [\n components.graphics?.Icon,\n components.graphics?.Logo,\n components.logout?.Button,\n components.Nav,\n ]\n return (\n customAvatarCount +\n componentArrays.reduce((count, items) => count + (items?.length ?? 0), 0) +\n directComponents.filter(Boolean).length\n )\n}\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n value !== null && typeof value === 'object'\n"],"names":["defaultUserCollection","getFeatureInfo","config","telemetryConfig","sanitizeTelemetryConfig","Object","assign","collectAdminCustomization","collectAuthentication","collectBasicDenominators","collectI18n","collectJobsAndQueues","collectOrdering","collectPreviewAndLivePreview","collectQueryPresets","collectTrash","collectUploadAndMedia","collectVersionsAndDrafts","collectRichTextFeatures","map","collect","safelyCollect","_","SYSTEM_WIDGET_COUNT","SYSTEM_COLLECTION_SLUGS","SYSTEM_GLOBAL_SLUGS","Set","collections","systemCollectionSlugs","kvCollectionSlug","kv","kvCollection","slug","add","jobs","enabled","firstCollectionAfterJobs","findIndex","includes","tasks","getDraftEntities","some","hasScheduledPublishing","index","length","splice","filter","collection","has","globals","adminCustomization","customAdminComponentCount","countRootAdminComponents","customAdminViewCount","keys","admin","components","views","customDashboardWidgetCount","Math","max","dashboard","widgets","authCollections","auth","Boolean","authentication","apiKeyCollectionCount","isObject","useAPIKey","authCollectionCount","customAuthStrategyCount","reduce","count","Array","isArray","strategies","localAuthDisabledCollectionCount","disableLocalStrategy","sessionsDisabledCollectionCount","useSessions","usernameCollectionCount","loginWithUsername","verifiedCollectionCount","verify","basicDenominators","collectionCount","globalCount","i18n","hasCustomAdminTranslations","translations","supportedAdminLanguageCount","supportedLanguages","workflows","tasksAndWorkflows","scheduledPublishingEntityCount","jobsAndQueues","jobsAutoRunConfigured","autoRun","undefined","jobsConcurrencyEnabled","concurrency","jobsEnabled","jobsSchedulingEnabled","schedule","taskCount","workflowCount","orderableCollectionCount","orderable","livePreviewCollections","livePreview","c","livePreviewGlobals","g","previewAndLivePreview","livePreviewCollectionCount","livePreviewGlobalCount","previewCollectionCount","preview","previewGlobalCount","queryPresetCollectionCount","enableQueryPresets","editor","features","editorConfig","raw","enabledFeatures","featureSet","f","richTextFeatures","trashCollectionCount","trash","uploadAndMedia","cropDisabledCollectionCount","upload","crop","focalPointDisabledCollectionCount","focalPoint","imageSizesCollectionCount","imageSizes","mimeRestrictedCollectionCount","mimeTypes","uploadCollectionCount","draftCollections","hasDrafts","draftGlobals","draftEntities","versionsAndDrafts","autosaveEntityCount","hasAutosave","draftCollectionCount","draftGlobalCount","versionsDisabledCollectionCount","versions","versionsDisabledGlobalCount","drafts","getDraftOptions","entity","autosave","schedulePublish","customAvatarCount","Number","avatar","Component","componentArrays","actions","afterDashboard","afterLogin","afterNav","afterNavLinks","beforeDashboard","beforeLogin","beforeNav","beforeNavLinks","header","providers","settingsMenu","directComponents","graphics","Icon","Logo","logout","Button","Nav","items","value"],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ export type RichTextFeature = 'blocks' | 'relationship' | 'table' | 'upload';
2
+ type CompleteFeatureInfo = {
3
+ adminCustomization: {
4
+ customAdminComponentCount: number;
5
+ customAdminViewCount: number;
6
+ customDashboardWidgetCount: number;
7
+ };
8
+ authentication: {
9
+ apiKeyCollectionCount: number;
10
+ authCollectionCount: number;
11
+ customAuthStrategyCount: number;
12
+ localAuthDisabledCollectionCount: number;
13
+ sessionsDisabledCollectionCount: number;
14
+ usernameCollectionCount: number;
15
+ verifiedCollectionCount: number;
16
+ };
17
+ basicDenominators: {
18
+ collectionCount: number;
19
+ globalCount: number;
20
+ };
21
+ i18n: {
22
+ hasCustomAdminTranslations: boolean;
23
+ supportedAdminLanguageCount: number;
24
+ };
25
+ jobsAndQueues: {
26
+ jobsAutoRunConfigured: boolean;
27
+ jobsConcurrencyEnabled: boolean;
28
+ jobsEnabled: boolean;
29
+ jobsSchedulingEnabled: boolean;
30
+ taskCount: number;
31
+ workflowCount: number;
32
+ };
33
+ orderableCollectionCount: number;
34
+ previewAndLivePreview: {
35
+ livePreviewCollectionCount: number;
36
+ livePreviewGlobalCount: number;
37
+ previewCollectionCount: number;
38
+ previewGlobalCount: number;
39
+ };
40
+ queryPresetCollectionCount: number;
41
+ richTextFeatures: RichTextFeature[];
42
+ trashCollectionCount: number;
43
+ uploadAndMedia: {
44
+ cropDisabledCollectionCount: number;
45
+ focalPointDisabledCollectionCount: number;
46
+ imageSizesCollectionCount: number;
47
+ mimeRestrictedCollectionCount: number;
48
+ uploadCollectionCount: number;
49
+ };
50
+ versionsAndDrafts: {
51
+ autosaveEntityCount: number;
52
+ draftCollectionCount: number;
53
+ draftGlobalCount: number;
54
+ scheduledPublishingEntityCount: number;
55
+ versionsDisabledCollectionCount: number;
56
+ versionsDisabledGlobalCount: number;
57
+ };
58
+ };
59
+ /** Feature families are omitted individually if their collection fails. */
60
+ export type FeatureInfo = Partial<CompleteFeatureInfo>;
61
+ export {};
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/utilities/telemetry/featureInfo/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE5E,KAAK,mBAAmB,GAAG;IACzB,kBAAkB,EAAE;QAClB,yBAAyB,EAAE,MAAM,CAAA;QACjC,oBAAoB,EAAE,MAAM,CAAA;QAC5B,0BAA0B,EAAE,MAAM,CAAA;KACnC,CAAA;IACD,cAAc,EAAE;QACd,qBAAqB,EAAE,MAAM,CAAA;QAC7B,mBAAmB,EAAE,MAAM,CAAA;QAC3B,uBAAuB,EAAE,MAAM,CAAA;QAC/B,gCAAgC,EAAE,MAAM,CAAA;QACxC,+BAA+B,EAAE,MAAM,CAAA;QACvC,uBAAuB,EAAE,MAAM,CAAA;QAC/B,uBAAuB,EAAE,MAAM,CAAA;KAChC,CAAA;IACD,iBAAiB,EAAE;QACjB,eAAe,EAAE,MAAM,CAAA;QACvB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,IAAI,EAAE;QACJ,0BAA0B,EAAE,OAAO,CAAA;QACnC,2BAA2B,EAAE,MAAM,CAAA;KACpC,CAAA;IACD,aAAa,EAAE;QACb,qBAAqB,EAAE,OAAO,CAAA;QAC9B,sBAAsB,EAAE,OAAO,CAAA;QAC/B,WAAW,EAAE,OAAO,CAAA;QACpB,qBAAqB,EAAE,OAAO,CAAA;QAC9B,SAAS,EAAE,MAAM,CAAA;QACjB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,wBAAwB,EAAE,MAAM,CAAA;IAChC,qBAAqB,EAAE;QACrB,0BAA0B,EAAE,MAAM,CAAA;QAClC,sBAAsB,EAAE,MAAM,CAAA;QAC9B,sBAAsB,EAAE,MAAM,CAAA;QAC9B,kBAAkB,EAAE,MAAM,CAAA;KAC3B,CAAA;IACD,0BAA0B,EAAE,MAAM,CAAA;IAClC,gBAAgB,EAAE,eAAe,EAAE,CAAA;IACnC,oBAAoB,EAAE,MAAM,CAAA;IAC5B,cAAc,EAAE;QACd,2BAA2B,EAAE,MAAM,CAAA;QACnC,iCAAiC,EAAE,MAAM,CAAA;QACzC,yBAAyB,EAAE,MAAM,CAAA;QACjC,6BAA6B,EAAE,MAAM,CAAA;QACrC,qBAAqB,EAAE,MAAM,CAAA;KAC9B,CAAA;IACD,iBAAiB,EAAE;QACjB,mBAAmB,EAAE,MAAM,CAAA;QAC3B,oBAAoB,EAAE,MAAM,CAAA;QAC5B,gBAAgB,EAAE,MAAM,CAAA;QACxB,8BAA8B,EAAE,MAAM,CAAA;QACtC,+BAA+B,EAAE,MAAM,CAAA;QACvC,2BAA2B,EAAE,MAAM,CAAA;KACpC,CAAA;CACF,CAAA;AAED,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** Feature families are omitted individually if their collection fails. */ export { };
2
+
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/utilities/telemetry/featureInfo/types.ts"],"sourcesContent":["export type RichTextFeature = 'blocks' | 'relationship' | 'table' | 'upload'\n\ntype CompleteFeatureInfo = {\n adminCustomization: {\n customAdminComponentCount: number\n customAdminViewCount: number\n customDashboardWidgetCount: number\n }\n authentication: {\n apiKeyCollectionCount: number\n authCollectionCount: number\n customAuthStrategyCount: number\n localAuthDisabledCollectionCount: number\n sessionsDisabledCollectionCount: number\n usernameCollectionCount: number\n verifiedCollectionCount: number\n }\n basicDenominators: {\n collectionCount: number\n globalCount: number\n }\n i18n: {\n hasCustomAdminTranslations: boolean\n supportedAdminLanguageCount: number\n }\n jobsAndQueues: {\n jobsAutoRunConfigured: boolean\n jobsConcurrencyEnabled: boolean\n jobsEnabled: boolean\n jobsSchedulingEnabled: boolean\n taskCount: number\n workflowCount: number\n }\n orderableCollectionCount: number\n previewAndLivePreview: {\n livePreviewCollectionCount: number\n livePreviewGlobalCount: number\n previewCollectionCount: number\n previewGlobalCount: number\n }\n queryPresetCollectionCount: number\n richTextFeatures: RichTextFeature[]\n trashCollectionCount: number\n uploadAndMedia: {\n cropDisabledCollectionCount: number\n focalPointDisabledCollectionCount: number\n imageSizesCollectionCount: number\n mimeRestrictedCollectionCount: number\n uploadCollectionCount: number\n }\n versionsAndDrafts: {\n autosaveEntityCount: number\n draftCollectionCount: number\n draftGlobalCount: number\n scheduledPublishingEntityCount: number\n versionsDisabledCollectionCount: number\n versionsDisabledGlobalCount: number\n }\n}\n\n/** Feature families are omitted individually if their collection fails. */\nexport type FeatureInfo = Partial<CompleteFeatureInfo>\n"],"names":[],"mappings":"AA4DA,yEAAyE,GACzE,WAAsD"}
@@ -0,0 +1,14 @@
1
+ import type { Payload } from '../../types/index.js';
2
+ export type ProjectCohort = 'cloud' | 'enterprise' | 'oss';
3
+ type Args = {
4
+ env?: NodeJS.ProcessEnv;
5
+ packages?: string[];
6
+ payload: Payload;
7
+ plugins: string[];
8
+ };
9
+ export declare const enterprisePackageNames: Set<string>;
10
+ export declare const getProjectContext: ({ env, packages, payload, plugins, }: Args) => {
11
+ projectCohorts: ProjectCohort[];
12
+ };
13
+ export {};
14
+ //# sourceMappingURL=getProjectContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getProjectContext.d.ts","sourceRoot":"","sources":["../../../src/utilities/telemetry/getProjectContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAEnD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,YAAY,GAAG,KAAK,CAAA;AAE1D,KAAK,IAAI,GAAG;IACV,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB,CAAA;AAED,eAAO,MAAM,sBAAsB,aAcjC,CAAA;AAEF,eAAO,MAAM,iBAAiB,yCAK3B,IAAI,KAAG;IAAE,cAAc,EAAE,aAAa,EAAE,CAAA;CAoB1C,CAAA"}
@@ -0,0 +1,36 @@
1
+ export const enterprisePackageNames = new Set([
2
+ '@payloadcms/ai-model-adapter',
3
+ '@payloadcms/plugin-ab-testing',
4
+ '@payloadcms/plugin-admin-only',
5
+ '@payloadcms/plugin-ai-embeddings',
6
+ '@payloadcms/plugin-ai-translate',
7
+ '@payloadcms/plugin-audit-logs',
8
+ '@payloadcms/plugin-csm',
9
+ '@payloadcms/plugin-email-builder',
10
+ '@payloadcms/plugin-environments',
11
+ '@payloadcms/plugin-oauth2',
12
+ '@payloadcms/plugin-publication-workflows',
13
+ '@payloadcms/plugin-visual-editing',
14
+ '@payloadcms/visual-editing'
15
+ ]);
16
+ export const getProjectContext = ({ env = process.env, packages = [], payload, plugins })=>{
17
+ const projectCohorts = [];
18
+ if ([
19
+ ...packages,
20
+ ...plugins
21
+ ].some((name)=>enterprisePackageNames.has(name))) {
22
+ projectCohorts.push('enterprise');
23
+ }
24
+ const hasPayloadCloudConfig = payload.config.globals.some((global)=>global.slug === 'payload-cloud-instance');
25
+ if (env.PAYLOAD_CLOUD === 'true' && hasPayloadCloudConfig) {
26
+ projectCohorts.push('cloud');
27
+ }
28
+ if (projectCohorts.length === 0) {
29
+ projectCohorts.push('oss');
30
+ }
31
+ return {
32
+ projectCohorts
33
+ };
34
+ };
35
+
36
+ //# sourceMappingURL=getProjectContext.js.map